From 68e84ec10dd5b4b32644c32c2dfb5c4148ca3a00 Mon Sep 17 00:00:00 2001 From: Florian Greiner Date: Wed, 29 Sep 2021 10:34:17 +0200 Subject: [PATCH 01/74] Version bump --- .github/version | 2 +- Cargo.lock | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/.github/version b/.github/version index 027a383a..82942c39 100644 --- a/.github/version +++ b/.github/version @@ -1 +1 @@ -v0.1.5 +v0.1.6 diff --git a/Cargo.lock b/Cargo.lock index c5059aba..3ff9828a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -313,7 +313,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rock" -version = "0.1.5-structs" +version = "0.1.5" dependencies = [ "bincode", "bitflags", From cc39ac274025d3fb1b98befa0651ab39764d2a53 Mon Sep 17 00:00:00 2001 From: Champii Date: Wed, 29 Sep 2021 08:34:42 +0000 Subject: [PATCH 02/74] Generated files for new version --- Cargo.toml | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ffae0439..afd6987c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.5" +version = "0.1.6-develop" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 0d3244cc..5ccfe6ca 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.5 +# Rock v0.1.6-develop -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=master)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. @@ -37,10 +37,10 @@ How to install and run the compiler: ### Using released binary -[Rock v0.1.5](https://github.com/Champii/Rock/releases/download/v0.1.5/rock) (Tested on arch linux) +[Rock v0.1.6-develop](https://github.com/Champii/Rock/releases/download/v0.1.6-develop/rock) (Tested on arch linux) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.5/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.6-develop/rock chmod +x rock ./rock -V ``` From e8fa7794ab9e1178b834414c6948f9014068cbe6 Mon Sep 17 00:00:00 2001 From: Champii Date: Thu, 30 Sep 2021 17:13:41 -0700 Subject: [PATCH 03/74] Add complete TypeSignature parsing (#30) * Generated files for new version * Fix branch name that is invalid cargo version * Fix readme build status * Unified version name in readme and cargo.toml * Merged TypeSignature with FuncType * Deactivated out of bounds error for literal index * Removed some clones * Clippy free * Add forgotten file * Generated files for new version * Readme * Generated files for new version * Remove old artefacts * Fix fn arg polymorphism * Add some typecheck failure tests * Add multiline struct const * Add struct field type failure * Generated files for new version Co-authored-by: Florian Greiner --- .github/templates/README.md | 63 ++- .github/templates/replacer.sh | 11 +- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 69 ++- build.rs | 21 +- src/bin/main.rs | 8 +- src/lib/ast/ast_print.rs | 4 +- src/lib/ast/primitive_type.rs | 10 +- src/lib/ast/resolve/mod.rs | 2 +- src/lib/ast/resolve/resolution_map.rs | 4 +- src/lib/ast/resolve/resolve_ctx.rs | 17 +- src/lib/ast/resolve/unused_collector.rs | 24 +- src/lib/ast/span_collector.rs | 2 +- src/lib/ast/tree.rs | 70 ++- src/lib/ast/type.rs | 403 ++++++++++-------- src/lib/ast/visit.rs | 64 +-- src/lib/ast_lowering/ast_lowering_context.rs | 64 +-- src/lib/ast_lowering/infix_desugar.rs | 2 +- src/lib/ast_lowering/return_placement.rs | 10 +- src/lib/codegen/codegen_context.rs | 116 ++--- src/lib/codegen/mod.rs | 4 +- src/lib/diagnostics/diagnostic.rs | 15 +- src/lib/helpers/scopes.rs | 36 +- src/lib/hir/arena.rs | 2 +- src/lib/hir/hir_printer.rs | 2 +- src/lib/hir/tree.rs | 74 ++-- src/lib/hir/visit.rs | 50 +-- src/lib/hir/visit_mut.rs | 15 +- src/lib/infer/annotate.rs | 182 -------- src/lib/infer/constraint.rs | 185 +++++--- src/lib/infer/constraint2.rs | 388 ----------------- src/lib/infer/mod.rs | 5 +- .../{monomorphizer => monomorphize}/mod.rs | 0 .../monomorphizer.rs | 128 +++--- src/lib/infer/state.rs | 71 ++- src/lib/parser/lexer.rs | 26 +- src/lib/parser/mod.rs | 2 +- src/lib/parser/parser_impl.rs | 246 ++++++----- src/lib/parser/parsing_context.rs | 21 +- src/lib/parser/source_file.rs | 2 +- src/lib/parser/token.rs | 6 +- src/lib/rock.rs | 34 +- .../testcases/basic/0_arg_fn/main.rk.stdout | 0 .../testcases/basic/1_arg_fn/main.rk.stdout | 0 .../testcases/basic/2_arg_fn/main.rk.stdout | 0 src/lib/testcases/basic/array/main.rk.stdout | 0 .../testcases/basic/bool_false/main.rk.stdout | 0 .../testcases/basic/bool_true/main.rk.stdout | 0 .../basic/deep_monomorph/main.rk.stdout | 0 .../testcases/basic/dot_assign/main.rk.stdout | 0 src/lib/testcases/basic/extern/main.rk.stdout | 0 src/lib/testcases/basic/fn_arg/main.rk.stdout | 0 src/lib/testcases/basic/fn_arg_array/main.rk | 7 + .../testcases/basic/fn_arg_array/main.rk.out | 1 + .../basic/fn_arg_array/main.rk.stdout | 0 .../testcases/basic/if_else/main.rk.stdout | 0 .../basic/indice_assign/main.rk.stdout | 0 src/lib/testcases/basic/let/main.rk.stdout | 0 src/lib/testcases/basic/main/main.rk.stdout | 0 .../testcases/basic/monomorph/main.rk.stdout | 0 .../basic/monomorph_in_trait/main.rk.stdout | 0 .../basic/multiline_struct_const/main.rk | 11 + .../basic/multiline_struct_const/main.rk.out | 1 + .../multiline_struct_const/main.rk.stdout | 0 .../basic/nested_array/main.rk.stdout | 0 .../basic/nested_struct/main.rk.stdout | 0 .../nested_struct_dect_multiline/main.rk | 17 + .../nested_struct_dect_multiline/main.rk.out | 1 + .../main.rk.stdout | 0 .../testcases/basic/op_func/main.rk.stdout | 0 .../basic/operator_precedence/main.rk.stdout | 0 .../testcases/basic/reassign/main.rk.stdout | 0 src/lib/testcases/basic/recur/main.rk.stdout | 0 .../basic/simple_struct/main.rk.stdout | 0 .../basic/struct_index/main.rk.stdout | 0 .../basic/trait_monomorph/main.rk.stdout | 0 .../trait_use_before_decl/main.rk.stdout | 0 .../testcases/fails/basic/fn_bad_arg/main.rk | 4 + .../fails/basic/fn_bad_arg/main.rk.out | 1 + .../fails/basic/fn_bad_arg/main.rk.stdout | 0 .../fails/basic/fn_bad_arg_nb/main.rk | 3 + .../fails/basic/fn_bad_arg_nb/main.rk.out | 1 + .../fails/basic/fn_bad_arg_nb/main.rk.stdout | 0 .../fails/basic/fn_bad_arg_nb2/main.rk | 3 + .../fails/basic/fn_bad_arg_nb2/main.rk.out | 1 + .../fails/basic/fn_bad_arg_nb2/main.rk.stdout | 0 .../fails/basic/struct_bad_field_type/main.rk | 11 + .../basic/struct_bad_field_type/main.rk.out | 1 + .../struct_bad_field_type/main.rk.stdout | 0 .../testcases/mods/basic_mod/main.rk.stdout | 0 src/lib/testcases/mods/build/main.rk.stdout | 0 src/lib/testcases/mods/full_fact/eq.rk | 16 +- .../testcases/mods/full_fact/main.rk.stdout | 0 .../mods/func_arg_resolution/main.rk.stdout | 0 .../nested_trait_resolution/main.rk.stdout | 0 .../testcases/mods/unused_fn/main.rk.stdout | 0 .../mods/unused_impl_fn/main.rk.stdout | 0 src/lib/testcases/test_template | 2 +- src/lib/testcases/trait/build/main.rk.stdout | 0 .../trait/late_resolution/main.rk.stdout | 0 .../trait/multi_resolution/main.rk.stdout | 0 src/lib/tests.rs | 103 +++-- std/src/eq.rk | 16 +- 104 files changed, 1167 insertions(+), 1495 deletions(-) delete mode 100644 src/lib/infer/annotate.rs delete mode 100644 src/lib/infer/constraint2.rs rename src/lib/infer/{monomorphizer => monomorphize}/mod.rs (100%) rename src/lib/infer/{monomorphizer => monomorphize}/monomorphizer.rs (79%) create mode 100644 src/lib/testcases/basic/0_arg_fn/main.rk.stdout create mode 100644 src/lib/testcases/basic/1_arg_fn/main.rk.stdout create mode 100644 src/lib/testcases/basic/2_arg_fn/main.rk.stdout create mode 100644 src/lib/testcases/basic/array/main.rk.stdout create mode 100644 src/lib/testcases/basic/bool_false/main.rk.stdout create mode 100644 src/lib/testcases/basic/bool_true/main.rk.stdout create mode 100644 src/lib/testcases/basic/deep_monomorph/main.rk.stdout create mode 100644 src/lib/testcases/basic/dot_assign/main.rk.stdout create mode 100644 src/lib/testcases/basic/extern/main.rk.stdout create mode 100644 src/lib/testcases/basic/fn_arg/main.rk.stdout create mode 100644 src/lib/testcases/basic/fn_arg_array/main.rk create mode 100644 src/lib/testcases/basic/fn_arg_array/main.rk.out create mode 100644 src/lib/testcases/basic/fn_arg_array/main.rk.stdout create mode 100644 src/lib/testcases/basic/if_else/main.rk.stdout create mode 100644 src/lib/testcases/basic/indice_assign/main.rk.stdout create mode 100644 src/lib/testcases/basic/let/main.rk.stdout create mode 100644 src/lib/testcases/basic/main/main.rk.stdout create mode 100644 src/lib/testcases/basic/monomorph/main.rk.stdout create mode 100644 src/lib/testcases/basic/monomorph_in_trait/main.rk.stdout create mode 100644 src/lib/testcases/basic/multiline_struct_const/main.rk create mode 100644 src/lib/testcases/basic/multiline_struct_const/main.rk.out create mode 100644 src/lib/testcases/basic/multiline_struct_const/main.rk.stdout create mode 100644 src/lib/testcases/basic/nested_array/main.rk.stdout create mode 100644 src/lib/testcases/basic/nested_struct/main.rk.stdout create mode 100644 src/lib/testcases/basic/nested_struct_dect_multiline/main.rk create mode 100644 src/lib/testcases/basic/nested_struct_dect_multiline/main.rk.out create mode 100644 src/lib/testcases/basic/nested_struct_dect_multiline/main.rk.stdout create mode 100644 src/lib/testcases/basic/op_func/main.rk.stdout create mode 100644 src/lib/testcases/basic/operator_precedence/main.rk.stdout create mode 100644 src/lib/testcases/basic/reassign/main.rk.stdout create mode 100644 src/lib/testcases/basic/recur/main.rk.stdout create mode 100644 src/lib/testcases/basic/simple_struct/main.rk.stdout create mode 100644 src/lib/testcases/basic/struct_index/main.rk.stdout create mode 100644 src/lib/testcases/basic/trait_monomorph/main.rk.stdout create mode 100644 src/lib/testcases/basic/trait_use_before_decl/main.rk.stdout create mode 100644 src/lib/testcases/fails/basic/fn_bad_arg/main.rk create mode 100644 src/lib/testcases/fails/basic/fn_bad_arg/main.rk.out create mode 100644 src/lib/testcases/fails/basic/fn_bad_arg/main.rk.stdout create mode 100644 src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk create mode 100644 src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk.out create mode 100644 src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk.stdout create mode 100644 src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk create mode 100644 src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk.out create mode 100644 src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk.stdout create mode 100644 src/lib/testcases/fails/basic/struct_bad_field_type/main.rk create mode 100644 src/lib/testcases/fails/basic/struct_bad_field_type/main.rk.out create mode 100644 src/lib/testcases/fails/basic/struct_bad_field_type/main.rk.stdout create mode 100644 src/lib/testcases/mods/basic_mod/main.rk.stdout create mode 100644 src/lib/testcases/mods/build/main.rk.stdout create mode 100644 src/lib/testcases/mods/full_fact/main.rk.stdout create mode 100644 src/lib/testcases/mods/func_arg_resolution/main.rk.stdout create mode 100644 src/lib/testcases/mods/nested_trait_resolution/main.rk.stdout create mode 100644 src/lib/testcases/mods/unused_fn/main.rk.stdout create mode 100644 src/lib/testcases/mods/unused_impl_fn/main.rk.stdout create mode 100644 src/lib/testcases/trait/build/main.rk.stdout create mode 100644 src/lib/testcases/trait/late_resolution/main.rk.stdout create mode 100644 src/lib/testcases/trait/multi_resolution/main.rk.stdout diff --git a/.github/templates/README.md b/.github/templates/README.md index 193d9e7a..a686b590 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -33,11 +33,15 @@ This is a personal project, so please bear with me ## Install +Warning: This project has only been tested on Linux x86_64. + How to install and run the compiler: -### Using released binary +### Using released binary + +Linux x86_64 only -[Rock {version}](https://github.com/Champii/Rock/releases/download/{version}/rock) (Tested on arch linux) +[Rock {version}](https://github.com/Champii/Rock/releases/download/{version}/rock) (Tested on arch, btw) ``` sh wget https://github.com/Champii/Rock/releases/download/{version}/rock @@ -79,15 +83,12 @@ mod lib use lib::prelude::* -# Polymophic function -id a = a - fact a = if a <= 1 then 1 else a * fact (a - 1) -main = print fact id 4 +main = print fact 4 ``` Assuming that you built Rock and put its binary in your PATH: @@ -104,6 +105,34 @@ Should output ## Showcases +### Polymophic function + + +``` haskell +mod lib + +use lib::prelude::* + +id a = a + +main = + print id 1 + print id 2.2 + print id "Test" +``` + +``` sh +rock run +``` + +Prints + +``` sh +1 +2.2 +Test +``` + ### Custom infix operator ``` haskell @@ -123,7 +152,7 @@ main = print (4 |> f) rock run ``` -Prints `6\n` +Prints `6` ### Trait definition @@ -149,6 +178,17 @@ main = ``` +``` sh +rock run +``` + +Prints + +``` +33 +42.42 +``` + ### Struct instance and Show implementation ``` haskell @@ -164,9 +204,10 @@ impl Show Player show p = show p.name main = - let player = Player - level: 42 - name: "MyName" + let player = + Player + level: 42 + name: "MyName" print player ``` @@ -175,4 +216,4 @@ main = rock run ``` -Prints `MyName\n` +Prints `MyName` diff --git a/.github/templates/replacer.sh b/.github/templates/replacer.sh index 00de0ebe..a25b1e20 100755 --- a/.github/templates/replacer.sh +++ b/.github/templates/replacer.sh @@ -3,12 +3,15 @@ set -euo pipefail BRANCH=$(basename $GITHUB_REF) NEW_VERSION=$(cat .github/version)-$BRANCH - REPLACE=$(printf '%s\n' "$NEW_VERSION" | sed -e 's/[\/&]/\\&/g') -sed "s/{version}/$REPLACE/g" "./.github/templates/README.md" > README.md +BRANCH_SAFE=$(printf '%s' "$BRANCH" | sed -e 's/_/-/g') +NEW_VERSION_SAFE=$(cat .github/version)-$BRANCH_SAFE +REPLACE_SAFE=$(printf '%s\n' "$NEW_VERSION_SAFE" | sed -e 's/[\/&]/\\&/g') + +sed "s/{version}/$REPLACE_SAFE/g" "./.github/templates/README.md" > README.md sed -i "s/{branch}/$BRANCH/g" "README.md" -REPLACE="${REPLACE:1}" +REPLACE_SAFE="${REPLACE_SAFE:1}" -sed "s/{version}/$REPLACE/g" "./.github/templates/Cargo.toml" > Cargo.toml +sed "s/{version}/$REPLACE_SAFE/g" "./.github/templates/Cargo.toml" > Cargo.toml diff --git a/Cargo.lock b/Cargo.lock index 3ff9828a..7a4b7d54 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -313,7 +313,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rock" -version = "0.1.5" +version = "0.1.6-typesignature-parse" dependencies = [ "bincode", "bitflags", diff --git a/Cargo.toml b/Cargo.toml index afd6987c..5c41648c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.6-develop" +version = "0.1.6-typesignature-parse" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 5ccfe6ca..ae853b38 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.6-develop +# Rock v0.1.6-typesignature-parse -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=typesignature_parse)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. @@ -33,14 +33,18 @@ This is a personal project, so please bear with me ## Install +Warning: This project has only been tested on Linux x86_64. + How to install and run the compiler: -### Using released binary +### Using released binary + +Linux x86_64 only -[Rock v0.1.6-develop](https://github.com/Champii/Rock/releases/download/v0.1.6-develop/rock) (Tested on arch linux) +[Rock v0.1.6-typesignature-parse](https://github.com/Champii/Rock/releases/download/v0.1.6-typesignature-parse/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.6-develop/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.6-typesignature-parse/rock chmod +x rock ./rock -V ``` @@ -79,15 +83,12 @@ mod lib use lib::prelude::* -# Polymophic function -id a = a - fact a = if a <= 1 then 1 else a * fact (a - 1) -main = print fact id 4 +main = print fact 4 ``` Assuming that you built Rock and put its binary in your PATH: @@ -104,6 +105,34 @@ Should output ## Showcases +### Polymophic function + + +``` haskell +mod lib + +use lib::prelude::* + +id a = a + +main = + print id 1 + print id 2.2 + print id "Test" +``` + +``` sh +rock run +``` + +Prints + +``` sh +1 +2.2 +Test +``` + ### Custom infix operator ``` haskell @@ -123,7 +152,7 @@ main = print (4 |> f) rock run ``` -Prints `6\n` +Prints `6` ### Trait definition @@ -149,6 +178,17 @@ main = ``` +``` sh +rock run +``` + +Prints + +``` +33 +42.42 +``` + ### Struct instance and Show implementation ``` haskell @@ -164,9 +204,10 @@ impl Show Player show p = show p.name main = - let player = Player - level: 42 - name: "MyName" + let player = + Player + level: 42 + name: "MyName" print player ``` @@ -175,4 +216,4 @@ main = rock run ``` -Prints `MyName\n` +Prints `MyName` diff --git a/build.rs b/build.rs index f9acf0c3..7c53cb1d 100644 --- a/build.rs +++ b/build.rs @@ -14,11 +14,9 @@ fn visit_dirs(dir: &Path) -> io::Result> { if path.is_dir() { res.extend(visit_dirs(&path)?); - } else { - if let Some(ext) = path.extension() { - if ext == "rk" && path.file_name().unwrap() == "main.rk" { - res.push(entry.path().to_str().unwrap().to_string()); - } + } else if let Some(ext) = path.extension() { + if ext == "rk" && path.file_name().unwrap() == "main.rk" { + res.push(entry.path().to_str().unwrap().to_string()); } } } @@ -41,13 +39,13 @@ fn main() { } } -fn write_test(output_file: &mut File, path: &String) { +fn write_test(output_file: &mut File, path: &str) { let path = path.replace("src/lib/", ""); let name = path.replace("./", ""); let name = name.replace("/", "_"); let name = name.replace(".rk", ""); - let test_name = format!("{}", name); + let test_name = name; write!( output_file, @@ -64,16 +62,17 @@ fn write_header(output_file: &mut File) { r##"use std::path::PathBuf; #[allow(dead_code)] -fn run(path: &str, input: &str, expected_output: &str) {{ +fn run(path: &str, input: &str, expected_ret: &str, expected_output: &str) {{ let mut config = super::Config::default(); config.project_config.entry_point = PathBuf::from(path); - let expected_output = expected_output.parse::().unwrap(); + let expected_ret = expected_ret.parse::().unwrap(); - let actual_output = super::test::run(path, input.to_string(), config.clone()); + let (ret_code, stdout) = super::test::run(path, input.to_string(), config); - assert_eq!(expected_output, actual_output); + assert_eq!(expected_ret, ret_code); + assert_eq!(expected_output, stdout); }} "## ) diff --git a/src/bin/main.rs b/src/bin/main.rs index 52f700c0..7650dfb8 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -20,9 +20,7 @@ fn build(config: &Config) -> bool { fs::create_dir_all(config.build_folder.clone()).unwrap(); - if let Err(diagnostic) = - rock::parse_file(entry_file.to_string(), "".to_string(), config.clone()) - { + if let Err(diagnostic) = rock::parse_file(entry_file.to_string(), "".to_string(), config) { if let DiagnosticKind::NoError = diagnostic.get_kind() { } else { println!("Error: {}", diagnostic.get_kind()); @@ -174,11 +172,11 @@ fn main() { if let Some(_matches) = matches.subcommand_matches("build") { build(&config); - return; + } else if let Some(_matches) = matches.subcommand_matches("run") { run(config); - return; + } else { println!("{}", matches.usage()); } diff --git a/src/lib/ast/ast_print.rs b/src/lib/ast/ast_print.rs index 167288dc..7d97b5c3 100644 --- a/src/lib/ast/ast_print.rs +++ b/src/lib/ast/ast_print.rs @@ -57,7 +57,7 @@ macro_rules! impl_visitor_trait { $name:ident, $method:ident )*) => { impl<'ast> Visitor<'ast> for AstPrintContext { - fn visit_name(&mut self, name: String) { + fn visit_name(&mut self, name: &str) { self.print_primitive(name); } @@ -118,5 +118,5 @@ impl_visitor_trait!( Literal, literal Array, array NativeOperator, native_operator - TypeSignature, type_signature + FuncType, func_type ); diff --git a/src/lib/ast/primitive_type.rs b/src/lib/ast/primitive_type.rs index b0d652c4..543e6d73 100644 --- a/src/lib/ast/primitive_type.rs +++ b/src/lib/ast/primitive_type.rs @@ -14,6 +14,14 @@ pub enum PrimitiveType { } impl PrimitiveType { + pub fn is_solved(&self) -> bool { + if let PrimitiveType::Array(t, _) = self { + t.is_solved() + } else { + true + } + } + pub fn get_name(&self) -> String { match self { Self::Void => "Void".to_string(), @@ -23,7 +31,7 @@ impl PrimitiveType { Self::Int32 => "Int32".to_string(), Self::Int64 => "Int64".to_string(), Self::Float64 => "Float64".to_string(), - Self::String => format!("String"), + Self::String => "String".to_string(), Self::Array(t, size) => format!("[{}; {}]", t.get_name(), size), } } diff --git a/src/lib/ast/resolve/mod.rs b/src/lib/ast/resolve/mod.rs index 63e566ef..fc3778b0 100644 --- a/src/lib/ast/resolve/mod.rs +++ b/src/lib/ast/resolve/mod.rs @@ -48,7 +48,7 @@ pub fn resolve(root: &mut Root, parsing_ctx: &mut ParsingCtx) -> Result<(), Diag root.spans = span_collector.take_list(); for unused_fn in &unused_fns { - let span = root.spans.get(&unused_fn).unwrap(); + let span = root.spans.get(unused_fn).unwrap(); parsing_ctx .diagnostics diff --git a/src/lib/ast/resolve/resolution_map.rs b/src/lib/ast/resolve/resolution_map.rs index ce63b056..b56a1446 100644 --- a/src/lib/ast/resolve/resolution_map.rs +++ b/src/lib/ast/resolve/resolution_map.rs @@ -15,7 +15,7 @@ impl ResolutionMap { } pub fn get(&self, pointer_id: &T) -> Option { - self.0.get(&pointer_id).cloned() + self.0.get(pointer_id).cloned() } pub fn get_recur(&self, pointer_id: &T) -> Option { @@ -23,7 +23,7 @@ impl ResolutionMap { if *pointer_id == pointee_id { warn!("Resolution loop"); - return Some(pointee_id); + Some(pointee_id) } else { self.get_recur(&pointee_id).or(Some(pointee_id)) } diff --git a/src/lib/ast/resolve/resolve_ctx.rs b/src/lib/ast/resolve/resolve_ctx.rs index 7aa05fe6..354ab57d 100644 --- a/src/lib/ast/resolve/resolve_ctx.rs +++ b/src/lib/ast/resolve/resolve_ctx.rs @@ -95,7 +95,7 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { let previous_assign_node_id = self.get(id.name.clone()).unwrap(); self.resolutions - .insert(id.identity.node_id.clone(), previous_assign_node_id.node_id); + .insert(id.identity.node_id, previous_assign_node_id.node_id); self.visit_identifier(id) } @@ -111,15 +111,15 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { fn visit_top_level(&mut self, top: &'a TopLevel) { match &top.kind { - TopLevelKind::Prototype(p) => self.visit_prototype(&p), + TopLevelKind::Prototype(p) => self.visit_prototype(p), TopLevelKind::Use(u) => { - self.visit_use(&u); + self.visit_use(u); } TopLevelKind::Infix(_, _) => (), - TopLevelKind::Trait(t) => self.visit_trait(&t), - TopLevelKind::Impl(i) => self.visit_impl(&i), - TopLevelKind::Struct(s) => self.visit_struct_decl(&s), - TopLevelKind::Function(f) => self.visit_function_decl(&f), + TopLevelKind::Trait(t) => self.visit_trait(t), + TopLevelKind::Impl(i) => self.visit_impl(i), + TopLevelKind::Struct(s) => self.visit_struct_decl(s), + TopLevelKind::Function(f) => self.visit_function_decl(f), TopLevelKind::Mod(name, m) => { let current_mod = self.cur_scope.clone(); @@ -176,7 +176,8 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { match self.scopes.get(&mod_path) { Some(scopes) => { if ident.name == "*" { - let scope = scopes.scopes.iter().nth(0).unwrap(); + let scope = scopes.scopes.get(0).unwrap(); + for (k, v) in &scope.items.clone() { self.add_to_current_scope(k.clone(), v.clone()); } diff --git a/src/lib/ast/resolve/unused_collector.rs b/src/lib/ast/resolve/unused_collector.rs index dd5a3823..d9f6f5fb 100644 --- a/src/lib/ast/resolve/unused_collector.rs +++ b/src/lib/ast/resolve/unused_collector.rs @@ -44,7 +44,7 @@ impl<'a> Visitor<'a> for UnusedCollector { TopLevelKind::Use(_u) => (), TopLevelKind::Trait(t) => { for f in &t.defs { - self.method_list.insert(f.identity.node_id.clone(), false); + self.method_list.insert(f.identity.node_id, false); } } TopLevelKind::Impl(_i) => {} @@ -52,10 +52,10 @@ impl<'a> Visitor<'a> for UnusedCollector { TopLevelKind::Mod(_, _m) => (), TopLevelKind::Infix(_, _) => (), TopLevelKind::Function(f) => { - self.fn_list.insert(f.identity.node_id.clone(), false); + self.fn_list.insert(f.identity.node_id, false); - if f.name.name == "main".to_string() { - self.fn_list.insert(f.identity.node_id.clone(), true); + if f.name.name == *"main" { + self.fn_list.insert(f.identity.node_id, true); } } } @@ -66,22 +66,22 @@ impl<'a> Visitor<'a> for UnusedCollector { fn visit_top_level(&mut self, top_level: &'a TopLevel) { match &top_level.kind { - TopLevelKind::Prototype(p) => self.visit_prototype(&p), + TopLevelKind::Prototype(p) => self.visit_prototype(p), TopLevelKind::Use(_u) => (), - TopLevelKind::Trait(t) => self.visit_trait(&t), - TopLevelKind::Impl(i) => self.visit_impl(&i), - TopLevelKind::Struct(i) => self.visit_struct_decl(&i), + TopLevelKind::Trait(t) => self.visit_trait(t), + TopLevelKind::Impl(i) => self.visit_impl(i), + TopLevelKind::Struct(i) => self.visit_struct_decl(i), TopLevelKind::Mod(name, m) => { - self.visit_identifier(&name); - self.visit_mod(&m); + self.visit_identifier(name); + self.visit_mod(m); } - TopLevelKind::Function(f) => self.visit_function_decl(&f), + TopLevelKind::Function(f) => self.visit_function_decl(f), TopLevelKind::Infix(_ident, _) => (), }; } fn visit_prototype(&mut self, prototype: &'a Prototype) { - self.visit_type_signature(&prototype.signature); + self.visit_func_type(&prototype.signature); } fn visit_function_decl(&mut self, f: &'a FunctionDecl) { diff --git a/src/lib/ast/span_collector.rs b/src/lib/ast/span_collector.rs index fdca326b..0720484b 100644 --- a/src/lib/ast/span_collector.rs +++ b/src/lib/ast/span_collector.rs @@ -22,7 +22,7 @@ impl SpanCollector { } pub fn insert(&mut self, ident: &Identity) { - self.list.insert(ident.node_id.clone(), ident.span.clone()); + self.list.insert(ident.node_id, ident.span.clone()); } } diff --git a/src/lib/ast/tree.rs b/src/lib/ast/tree.rs index cea7dcc2..df145860 100644 --- a/src/lib/ast/tree.rs +++ b/src/lib/ast/tree.rs @@ -7,7 +7,7 @@ use crate::ast::resolve::ResolutionMap; use crate::generate_has_name; use crate::helpers::*; -use super::{StructType, Type, TypeSignature}; +use super::{FuncType, StructType, Type}; #[derive(Debug, Clone)] pub struct Root { @@ -138,16 +138,10 @@ impl StructDecl { .defs .iter() .map(|proto| { - if proto.signature.args.is_empty() { - ( - proto.name.name.clone(), - Box::new(proto.signature.ret.clone()), - ) + if proto.signature.arguments.is_empty() { + (proto.name.name.clone(), proto.signature.ret.clone()) } else { - ( - proto.name.name.clone(), - Box::new(proto.signature.to_func_type()), - ) + (proto.name.name.clone(), Box::new(proto.signature.to_type())) } }) .collect(), @@ -179,7 +173,7 @@ pub struct Impl { #[derive(Debug, Clone)] pub struct Prototype { pub name: Identifier, - pub signature: TypeSignature, + pub signature: FuncType, pub identity: Identity, } @@ -202,7 +196,7 @@ pub struct FunctionDecl { pub arguments: Vec, pub body: Body, pub identity: Identity, - pub signature: TypeSignature, + pub signature: FuncType, } impl FunctionDecl { @@ -255,7 +249,7 @@ impl IdentifierPath { } pub fn prepend_mod(&self, path: IdentifierPath) -> Self { - let mut path = path.clone(); + let mut path = path; path.path.extend::<_>(self.path.clone()); @@ -267,13 +261,15 @@ impl IdentifierPath { .path .iter() .enumerate() - .filter_map(|(i, name)| { - if name.name == "super".to_string() { - Some(i) - } else { - None - } - }) + .filter_map( + |(i, name)| { + if name.name == *"super" { + Some(i) + } else { + None + } + }, + ) .collect::>(); let mut to_remove_total = vec![]; @@ -344,9 +340,9 @@ pub struct Statement { #[derive(Debug, Clone)] pub enum StatementKind { - Expression(Expression), - Assign(Assign), - If(If), + Expression(Box), + Assign(Box), + If(Box), } #[derive(Debug, Clone)] @@ -408,10 +404,7 @@ impl Expression { } pub fn is_binop(&self) -> bool { - match &self.kind { - ExpressionKind::BinopExpr(_, _, _) => true, - _ => false, - } + matches!(&self.kind, ExpressionKind::BinopExpr(_, _, _)) } pub fn is_indice(&self) -> bool { @@ -557,15 +550,12 @@ impl OperandKind { #[derive(Debug, Clone)] pub enum SecondaryExpr { Arguments(Vec), - Indice(Expression), + Indice(Box), // Boxing here to keep the enum size low Dot(Identifier), } impl SecondaryExpr { pub fn is_indice(&self) -> bool { - match self { - SecondaryExpr::Indice(_) => true, - _ => false, - } + matches!(self, SecondaryExpr::Indice(_)) } } @@ -613,14 +603,14 @@ pub enum NativeOperatorKind { FMul, FDiv, IEq, - IGT, - IGE, - ILT, - ILE, + Igt, + Ige, + Ilt, + Ile, FEq, - FGT, - FGE, - FLT, - FLE, + Fgt, + Fge, + Flt, + Fle, BEq, } diff --git a/src/lib/ast/type.rs b/src/lib/ast/type.rs index 7ccff0c1..3aaee532 100644 --- a/src/lib/ast/type.rs +++ b/src/lib/ast/type.rs @@ -2,17 +2,21 @@ use colored::*; use std::{collections::BTreeMap, fmt}; use crate::ast::PrimitiveType; -// use crate::ast::Prototype; -#[derive(Clone, Hash, Eq, Serialize, Deserialize)] +#[derive(Clone, Eq, Serialize, Deserialize)] pub enum Type { Primitive(PrimitiveType), - // Proto(Box), FuncType(FuncType), Struct(StructType), Trait(String), - ForAll(String), // TODO - Undefined(u64), + ForAll(String), + Undefined(u64), // FIXME: To remove +} + +impl std::hash::Hash for Type { + fn hash(&self, state: &mut H) { + core::mem::discriminant(self).hash(state); + } } impl PartialEq for Type { @@ -30,11 +34,21 @@ impl Type { Self::ForAll(String::from(t)) } + pub fn is_solved(&self) -> bool { + match self { + Type::Primitive(p) => p.is_solved(), + Type::FuncType(ft) => ft.is_solved(), + Type::Struct(_) => true, + Type::Trait(_) => true, + Type::ForAll(_) => false, + Type::Undefined(_) => false, + } + } + pub fn get_name(&self) -> String { match self { Self::Primitive(p) => p.get_name(), - // Self::Proto(p) => p.name.clone().unwrap_or(String::new()), - Self::FuncType(f) => f.name.clone(), + Self::FuncType(_f) => String::from("(fn)"), Self::Struct(s) => s.name.clone(), Self::Trait(t) => t.clone(), Self::ForAll(n) => String::from(n), @@ -53,6 +67,14 @@ impl Type { panic!("Not a struct type"); } } + + pub fn into_func_type(&self) -> FuncType { + if let Type::FuncType(f) = self { + f.clone() + } else { + panic!("Not a func type"); + } + } } impl fmt::Debug for Type { @@ -73,31 +95,51 @@ impl fmt::Display for Type { } } -#[derive(Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] +#[derive(Clone, Eq, Serialize, Deserialize)] pub struct FuncType { - pub name: String, pub arguments: Vec>, pub ret: Box, } +impl std::hash::Hash for FuncType { + fn hash(&self, state: &mut H) { + self.arguments.hash(state); + self.ret.hash(state); + } +} + +impl PartialEq for FuncType { + fn eq(&self, other: &Self) -> bool { + self.arguments.eq(&other.arguments) && self.ret.eq(&other.ret) + } +} + +impl Default for FuncType { + fn default() -> Self { + Self { + arguments: vec![], + ret: Box::new(Type::Undefined(0)), + } + } +} + impl fmt::Debug for FuncType { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{}{} {} {}{}", - "(".green(), - self.name.yellow(), - "::".red(), - self.to_type_signature(), - ")".green(), - ) + let s = self + .arguments + .iter() + .map(|arg| format!("{:?}", arg)) + .chain(vec![format!("{:?}", self.ret)].into_iter()) + .collect::>() + .join(&" -> ".magenta().to_string()); + + write!(f, "{}{}{}", "(".green(), s, ")".green(),) } } impl FuncType { - pub fn new(name: String, arguments: Vec, ret: Type) -> Self { + pub fn new(arguments: Vec, ret: Type) -> Self { Self { - name, arguments: arguments.into_iter().map(Box::new).collect(), ret: Box::new(ret), } @@ -112,15 +154,7 @@ impl FuncType { .collect() } - pub fn to_type_signature(&self) -> TypeSignature { - let mut sig = TypeSignature::default().with_ret(*self.ret.clone()); - - sig.args = self.arguments.iter().map(|arg| *arg.clone()).collect(); - - sig - } - - pub fn get_mangled_name(&self) -> String { + pub fn get_mangled_name(&self, name: String) -> String { let mut prefixes = self .arguments .iter() @@ -129,153 +163,96 @@ impl FuncType { prefixes.push(self.ret.to_string()); - format!("{}_{}", self.name, prefixes.join("_")) + format!("{}_{}", name, prefixes.join("_")) } -} -#[derive(Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub struct StructType { - pub name: String, - pub defs: BTreeMap>, -} - -impl fmt::Debug for StructType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{} {} {} {}", - self.name.yellow(), - "{".green(), - self.defs - .iter() - .map(|(n, b)| format!("{}: {:?}", n, b)) - .collect::>() - .join(", "), - "}".green(), - ) - } -} - -impl StructType { - // pub fn -} - -#[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub struct TypeSignature { - pub args: Vec, - pub ret: Type, - next_free_forall_type: usize, -} - -impl fmt::Display for TypeSignature { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - let s = self - .args - .iter() - .map(|arg| format!("{:?}", arg)) - .chain(vec![format!("{:?}", self.ret)].into_iter()) - .collect::>() - .join(&" -> ".magenta().to_string()); - - write!(f, "{}", s) - } -} - -impl Default for TypeSignature { - fn default() -> Self { - Self { - args: vec![], - ret: Type::Undefined(0), - next_free_forall_type: 0, - } - } -} - -impl TypeSignature { - pub fn apply_forall_types(&self, orig: &Vec, dest: &Vec) -> Self { + pub fn apply_forall_types(&self, orig: &[Type], dest: &[Type]) -> Self { assert_eq!(orig.len(), dest.len()); let (dest, orig): (Vec<_>, Vec<_>) = dest .iter() .zip(orig) - .filter_map(|(dest_t, orig_t)| { - if let Type::ForAll(_) = dest_t { - None - } else { - Some((dest_t.clone(), orig_t.clone())) - } + .filter_map(|(dest_t, orig_t)| match dest_t { + Type::ForAll(_) => None, + _ => Some((dest_t.clone(), orig_t.clone())), }) .unzip(); let applied_args = self - .args + .arguments .iter() - .map( - |arg_t| match orig.iter().enumerate().find(|(_, orig_t)| *orig_t == arg_t) { - Some((i, _orig_t)) => dest[i].clone(), + .map(|arg_t| { + match orig + .iter() + .enumerate() + .find(|(_, orig_t)| **orig_t == **arg_t) + { + Some((i, _orig_t)) => Box::new(dest[i].clone()), None => arg_t.clone(), - }, - ) + } + }) .collect(); let applied_ret = match orig .iter() .enumerate() - .find(|(_, orig_t)| **orig_t == self.ret) + .find(|(_, orig_t)| **orig_t == *self.ret) { - Some((i, _orig_t)) => dest[i].clone(), + Some((i, _orig_t)) => Box::new(dest[i].clone()), None => self.ret.clone(), }; Self { - next_free_forall_type: 0, - args: applied_args, + arguments: applied_args, ret: applied_ret, } } - pub fn apply_types(&self, args: Vec, ret: Type) -> Self { + fn collect_forall_types(&self, arguments: Vec, ret: Type) -> (Vec, Vec) { let mut orig = vec![]; let mut dest = vec![]; - self.args.iter().enumerate().for_each(|(i, arg_t)| { + self.arguments.iter().enumerate().for_each(|(i, arg_t)| { if !arg_t.is_forall() { warn!("Trying to apply type to a not forall"); return; } - if let Some(t) = args.get(i) { - orig.push(arg_t.clone()); - dest.push(t.clone()); + if let Some(t) = arguments.get(i) { + orig.push((**arg_t).clone()); + dest.push((*t).clone()); } }); if !ret.is_forall() { - // panic!("Trying to apply type to a not forall") warn!("Trying to apply type to a not forall"); } // FIXME: must remplace all occurences of ret - orig.push(self.ret.clone()); - dest.push(ret.clone()); + orig.push((*self.ret).clone()); + dest.push(ret); - self.apply_forall_types(&orig, &dest) + (orig, dest) } - pub fn apply_partial_types(&self, args: &Vec>, ret: Option) -> Self { + fn collect_partial_forall_types( + &self, + arguments: &[Option], + ret: Option, + ) -> (Vec, Vec) { let mut orig = vec![]; let mut dest = vec![]; - self.args.iter().enumerate().for_each(|(i, arg_t)| { + self.arguments.iter().enumerate().for_each(|(i, arg_t)| { if !arg_t.is_forall() { warn!("Trying to apply type to a not forall"); return; } - if let Some(t) = args.get(i).unwrap() { - orig.push(arg_t.clone()); + if let Some(t) = arguments.get(i).unwrap() { + orig.push(*arg_t.clone()); dest.push(t.clone()); } }); @@ -287,136 +264,186 @@ impl TypeSignature { } // FIXME: must remplace all occurences of ret - orig.push(self.ret.clone()); - dest.push(t.clone()); + orig.push(*self.ret.clone()); + dest.push(t); } - self.apply_forall_types(&orig, &dest) + (orig, dest) } - pub fn apply_partial_types_mut(&mut self, args: &Vec>, ret: Option) { - let mut orig = vec![]; - let mut dest = vec![]; + pub fn apply_types(&self, arguments: Vec, ret: Type) -> Self { + let mut resolved = self.clone(); - self.args.iter_mut().enumerate().for_each(|(i, arg_t)| { - if !arg_t.is_forall() { - warn!("Trying to apply type to a not forall"); + resolved.arguments = self + .arguments + .iter() + .enumerate() + .map(|(i, arg)| { + if let Type::FuncType(f_t) = &**arg { + Box::new( + f_t.merge_with(&arguments.get(i).unwrap().into_func_type()) + .to_type(), + ) + } else { + (*arg).clone() + } + }) + .collect::>(); - return; - } + resolved.ret = if let Type::FuncType(f_t) = &*self.ret { + Box::new(f_t.merge_with(&ret.into_func_type()).to_type()) + } else { + self.ret.clone() + }; - if let Some(t) = args.get(i).unwrap() { - orig.push(arg_t.clone()); - dest.push(t.clone()); - } - }); + let (orig, dest) = resolved.collect_forall_types(arguments, ret); - if let Some(t) = ret { - if !t.is_forall() { - // panic!("Trying to apply type to a not forall") - warn!("Trying to apply type to a not forall"); - } + resolved.apply_forall_types(&orig, &dest) + } - // FIXME: must remplace all occurences of ret - orig.push(self.ret.clone()); - dest.push(t.clone()); - } + pub fn apply_partial_types(&self, arguments: &[Option], ret: Option) -> Self { + let mut resolved = self.clone(); - *self = self.apply_forall_types(&orig, &dest); - } + resolved.arguments = self + .arguments + .iter() + .enumerate() + .map(|(i, arg)| { + if let Type::FuncType(f_t) = &**arg { + let inner = arguments.get(i).unwrap().as_ref().unwrap().into_func_type(); - pub fn from_args_nb(nb: usize) -> Self { - let mut new = Self::default(); + Box::new(f_t.merge_with(&inner).to_type()) + } else { + (*arg).clone() + } + }) + .collect::>(); - new.args = (0..nb).map(|_| new.get_next_available_forall()).collect(); - new.ret = new.get_next_available_forall(); + resolved.ret = if let Type::FuncType(f_t) = &*self.ret { + Box::new( + f_t.merge_with(&ret.as_ref().unwrap().into_func_type()) + .to_type(), + ) + } else { + self.ret.clone() + }; - new + let (orig, dest) = resolved.collect_partial_forall_types(arguments, ret); + + resolved.apply_forall_types(&orig, &dest) } - fn get_next_available_forall(&mut self) -> Type { - let t = Type::ForAll( - ('a'..'z') - .nth(self.next_free_forall_type) - .unwrap() - .to_string(), - ); + pub fn from_args_nb(nb: usize) -> Self { + let mut new = Self::default(); + let mut forall_generator = 'a'..'z'; + + new.arguments = forall_generator + .clone() + .take(nb) + .map(|n| Box::new(Type::ForAll(n.to_string()))) + .collect(); - self.next_free_forall_type += 1; + new.ret = Box::new(Type::ForAll(forall_generator.nth(nb).unwrap().to_string())); - t + new } pub fn is_solved(&self) -> bool { - self.are_args_solved() && !self.ret.is_forall() + self.are_args_solved() && self.ret.is_solved() } pub fn are_args_solved(&self) -> bool { - !self.args.iter().any(|arg| arg.is_forall()) + !self.arguments.iter().any(|arg| !arg.is_solved()) } pub fn with_ret(mut self, ret: Type) -> Self { - self.ret = ret; + self.ret = Box::new(ret); self } - pub fn to_func_type(&self) -> Type { - Type::FuncType(FuncType::new( - String::new(), - self.args.clone(), - self.ret.clone(), - )) + pub fn merge_with(&self, other: &Self) -> Self { + self.apply_types( + other.arguments.iter().map(|b| (**b).clone()).collect(), + *other.ret.clone(), + ) } - pub fn merge_with(&self, other: &Self) -> Self { - self.apply_types(other.args.clone(), other.ret.clone()) + pub fn to_type(&self) -> Type { + Type::FuncType(self.clone()) } } +#[derive(Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub struct StructType { + pub name: String, + pub defs: BTreeMap>, +} + +impl fmt::Debug for StructType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{} {} {} {}", + self.name.yellow(), + "{".green(), + self.defs + .iter() + .map(|(n, b)| format!("{}: {:?}", n, b)) + .collect::>() + .join(", "), + "}".green(), + ) + } +} + +impl StructType { + // pub fn +} + #[cfg(test)] mod tests { use super::*; #[test] fn basic_type_signature() { - let sig = TypeSignature::from_args_nb(2); + let sig = FuncType::from_args_nb(2); - assert_eq!(sig.args[0], Type::forall("a")); - assert_eq!(sig.args[1], Type::forall("b")); - assert_eq!(sig.ret, Type::forall("c")); + assert_eq!(*sig.arguments[0], Type::forall("a")); + assert_eq!(*sig.arguments[1], Type::forall("b")); + assert_eq!(*sig.ret, Type::forall("c")); } #[test] fn apply_forall_types() { - let sig = TypeSignature::from_args_nb(2); + let sig = FuncType::from_args_nb(2); let res = sig.apply_forall_types(&vec![Type::forall("b")], &vec![Type::int64()]); - assert_eq!(res.args[0], Type::forall("a")); - assert_eq!(res.args[1], Type::int64()); - assert_eq!(res.ret, Type::forall("c")); + assert_eq!(*res.arguments[0], Type::forall("a")); + assert_eq!(*res.arguments[1], Type::int64()); + assert_eq!(*res.ret, Type::forall("c")); } #[test] fn apply_types() { - let sig = TypeSignature::from_args_nb(2); + let sig = FuncType::from_args_nb(2); let res = sig.apply_types(vec![Type::int64()], Type::int64()); - assert_eq!(res.args[0], Type::int64()); - assert_eq!(res.args[1], Type::forall("b")); - assert_eq!(res.ret, Type::int64()); + assert_eq!(*res.arguments[0], Type::int64()); + assert_eq!(*res.arguments[1], Type::forall("b")); + assert_eq!(*res.ret, Type::int64()); } #[test] fn apply_partial_types() { - let sig = TypeSignature::from_args_nb(2); + let sig = FuncType::from_args_nb(2); let res = sig.apply_partial_types(&vec![None, Some(Type::int64())], Some(Type::int64())); - assert_eq!(res.args[0], Type::forall("a")); - assert_eq!(res.args[1], Type::int64()); - assert_eq!(res.ret, Type::int64()); + assert_eq!(*res.arguments[0], Type::forall("a")); + assert_eq!(*res.arguments[1], Type::int64()); + assert_eq!(*res.ret, Type::int64()); } } diff --git a/src/lib/ast/visit.rs b/src/lib/ast/visit.rs index 95422772..9bcdfd58 100644 --- a/src/lib/ast/visit.rs +++ b/src/lib/ast/visit.rs @@ -8,7 +8,7 @@ macro_rules! generate_visitor_trait { $name:ident, $method:ident )*) => { pub trait Visitor<'ast>: Sized { - fn visit_name(&mut self, _name: String) {} + fn visit_name(&mut self, _name: &str) {} fn visit_primitive(&mut self, _val: T) where @@ -58,7 +58,7 @@ generate_visitor_trait!( StructCtor, struct_ctor Array, array NativeOperator, native_operator - TypeSignature, type_signature + FuncType, func_type Type, r#type ); @@ -72,17 +72,17 @@ pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, _mod: &'a Mod) { pub fn walk_top_level<'a, V: Visitor<'a>>(visitor: &mut V, top_level: &'a TopLevel) { match &top_level.kind { - TopLevelKind::Prototype(p) => visitor.visit_prototype(&p), - TopLevelKind::Use(u) => visitor.visit_use(&u), - TopLevelKind::Trait(t) => visitor.visit_trait(&t), - TopLevelKind::Impl(i) => visitor.visit_impl(&i), - TopLevelKind::Struct(i) => visitor.visit_struct_decl(&i), + TopLevelKind::Prototype(p) => visitor.visit_prototype(p), + TopLevelKind::Use(u) => visitor.visit_use(u), + TopLevelKind::Trait(t) => visitor.visit_trait(t), + TopLevelKind::Impl(i) => visitor.visit_impl(i), + TopLevelKind::Struct(i) => visitor.visit_struct_decl(i), TopLevelKind::Mod(name, m) => { - visitor.visit_identifier(&name); - visitor.visit_mod(&m); + visitor.visit_identifier(name); + visitor.visit_mod(m); } - TopLevelKind::Function(f) => visitor.visit_function_decl(&f), - TopLevelKind::Infix(ident, _) => visitor.visit_identifier(&ident), + TopLevelKind::Function(f) => visitor.visit_function_decl(f), + TopLevelKind::Infix(ident, _) => visitor.visit_identifier(ident), }; } @@ -111,7 +111,7 @@ pub fn walk_impl<'a, V: Visitor<'a>>(visitor: &mut V, i: &'a Impl) { pub fn walk_prototype<'a, V: Visitor<'a>>(visitor: &mut V, prototype: &'a Prototype) { visitor.visit_identifier(&prototype.name); - visitor.visit_type_signature(&prototype.signature); + visitor.visit_func_type(&prototype.signature); } pub fn walk_use<'a, V: Visitor<'a>>(visitor: &mut V, r#use: &'a Use) { @@ -134,11 +134,11 @@ pub fn walk_identifier_path<'a, V: Visitor<'a>>( } pub fn walk_identifier<'a, V: Visitor<'a>>(visitor: &mut V, identifier: &'a Identifier) { - visitor.visit_name(identifier.name.clone()); + visitor.visit_name(&identifier.name); } pub fn walk_argument_decl<'a, V: Visitor<'a>>(visitor: &mut V, argument: &'a ArgumentDecl) { - visitor.visit_name(argument.name.clone()); + visitor.visit_name(&argument.name); } pub fn walk_body<'a, V: Visitor<'a>>(visitor: &mut V, body: &'a Body) { @@ -147,9 +147,9 @@ pub fn walk_body<'a, V: Visitor<'a>>(visitor: &mut V, body: &'a Body) { pub fn walk_statement<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Statement) { match statement.kind.as_ref() { - StatementKind::Expression(expr) => visitor.visit_expression(&expr), - StatementKind::Assign(assign) => visitor.visit_assign(&assign), - StatementKind::If(expr) => visitor.visit_if(&expr), + StatementKind::Expression(expr) => visitor.visit_expression(expr), + StatementKind::Assign(assign) => visitor.visit_assign(assign), + StatementKind::If(expr) => visitor.visit_if(expr), } } @@ -170,33 +170,33 @@ pub fn walk_if<'a, V: Visitor<'a>>(visitor: &mut V, r#if: &'a If) { visitor.visit_expression(&r#if.predicat); visitor.visit_body(&r#if.body); if let Some(r#else) = &r#if.else_ { - visitor.visit_else(&r#else); + visitor.visit_else(r#else); } } pub fn walk_else<'a, V: Visitor<'a>>(visitor: &mut V, r#else: &'a Else) { match r#else { - Else::If(expr) => visitor.visit_if(&expr), - Else::Body(expr) => visitor.visit_body(&expr), + Else::If(expr) => visitor.visit_if(expr), + Else::Body(expr) => visitor.visit_body(expr), } } pub fn walk_expression<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a Expression) { match &expr.kind { ExpressionKind::BinopExpr(unary, operator, expr) => { - visitor.visit_unary(&unary); - visitor.visit_operator(&operator); + visitor.visit_unary(unary); + visitor.visit_operator(operator); visitor.visit_expression(&*expr); } - ExpressionKind::UnaryExpr(unary) => visitor.visit_unary(&unary), - ExpressionKind::StructCtor(ctor) => visitor.visit_struct_ctor(&ctor), + ExpressionKind::UnaryExpr(unary) => visitor.visit_unary(unary), + ExpressionKind::StructCtor(ctor) => visitor.visit_struct_ctor(ctor), ExpressionKind::NativeOperation(op, left, right) => { - visitor.visit_identifier(&left); - visitor.visit_identifier(&right); - visitor.visit_native_operator(&op); + visitor.visit_identifier(left); + visitor.visit_identifier(right); + visitor.visit_native_operator(op); } ExpressionKind::Return(expr) => { - visitor.visit_expression(&expr); + visitor.visit_expression(expr); } } } @@ -245,8 +245,8 @@ pub fn walk_operator<'a, V: Visitor<'a>>(visitor: &mut V, operator: &'a Operator pub fn walk_operand<'a, V: Visitor<'a>>(visitor: &mut V, operand: &'a Operand) { match &operand.kind { - OperandKind::Literal(l) => visitor.visit_literal(&l), - OperandKind::Identifier(i) => visitor.visit_identifier_path(&i), + OperandKind::Literal(l) => visitor.visit_literal(l), + OperandKind::Identifier(i) => visitor.visit_identifier_path(i), OperandKind::Expression(e) => visitor.visit_expression(&*e), } } @@ -273,8 +273,8 @@ pub fn walk_native_operator<'a, V: Visitor<'a>>(_visitor: &mut V, _operator: &'a // Nothing to do } -pub fn walk_type_signature<'a, V: Visitor<'a>>(visitor: &mut V, signature: &'a TypeSignature) { - walk_list!(visitor, visit_type, &signature.args); +pub fn walk_func_type<'a, V: Visitor<'a>>(visitor: &mut V, signature: &'a FuncType) { + walk_list!(visitor, visit_type, &signature.arguments); visitor.visit_type(&signature.ret); } diff --git a/src/lib/ast_lowering/ast_lowering_context.rs b/src/lib/ast_lowering/ast_lowering_context.rs index 092dbdb3..b1c61c9d 100644 --- a/src/lib/ast_lowering/ast_lowering_context.rs +++ b/src/lib/ast_lowering/ast_lowering_context.rs @@ -14,7 +14,7 @@ pub struct AstLoweringContext { bodies: BTreeMap, operators_list: HashMap, traits: HashMap, - trait_methods: HashMap>, + trait_methods: HashMap>, structs: HashMap, } @@ -59,21 +59,21 @@ impl AstLoweringContext { r#mod .top_levels .iter() - .for_each(|t| self.lower_top_level(&t)); + .for_each(|t| self.lower_top_level(t)); } pub fn lower_top_level(&mut self, top_level: &TopLevel) { match &top_level.kind { TopLevelKind::Prototype(p) => { let top_level = hir::TopLevel { - kind: hir::TopLevelKind::Prototype(self.lower_prototype(&p)), + kind: hir::TopLevelKind::Prototype(self.lower_prototype(p)), }; self.top_levels.push(top_level); } TopLevelKind::Function(f) => { let top_level = hir::TopLevel { - kind: hir::TopLevelKind::Function(self.lower_function_decl(&f)), + kind: hir::TopLevelKind::Function(self.lower_function_decl(f)), }; self.top_levels.push(top_level); @@ -85,9 +85,9 @@ impl AstLoweringContext { self.lower_struct_decl(s); } TopLevelKind::Impl(i) => { - self.lower_impl(&i); + self.lower_impl(i); } - TopLevelKind::Mod(_name, mod_) => self.lower_mod(&mod_), + TopLevelKind::Mod(_name, mod_) => self.lower_mod(mod_), TopLevelKind::Infix(_, _) => (), TopLevelKind::Use(_u) => (), }; @@ -100,7 +100,7 @@ impl AstLoweringContext { defs: s .defs .iter() - .map(|proto| self.lower_prototype(&proto)) + .map(|proto| self.lower_prototype(proto)) .collect(), }; @@ -116,7 +116,7 @@ impl AstLoweringContext { defs: t .defs .iter() - .map(|proto| self.lower_prototype(&proto)) + .map(|proto| self.lower_prototype(proto)) .collect(), }; @@ -152,7 +152,7 @@ impl AstLoweringContext { let fn_decls = self .trait_methods .entry(hir_f.name.name.clone()) - .or_insert(HashMap::new()); + .or_insert_with(HashMap::new); let _hir_id = self.hir_map.next_hir_id(f.identity.clone()); @@ -186,7 +186,7 @@ impl AstLoweringContext { arguments: f .arguments .iter() - .map(|arg| self.lower_argument_decl(&arg)) + .map(|arg| self.lower_argument_decl(arg)) .collect(), body_id, signature: f.signature.clone(), @@ -212,7 +212,7 @@ impl AstLoweringContext { body_id: FnBodyId, fn_id: HirId, ) -> hir::FnBody { - let body = ReturnInserter { body: &fn_body }.run(); + let body = ReturnInserter { body: fn_body }.run(); let body = self.lower_body(&body); @@ -239,11 +239,11 @@ impl AstLoweringContext { hir::Statement { kind: match &*stmt.kind { StatementKind::Expression(e) => { - Box::new(hir::StatementKind::Expression(self.lower_expression(&e))) + Box::new(hir::StatementKind::Expression(self.lower_expression(e))) } - StatementKind::If(e) => Box::new(hir::StatementKind::If(self.lower_if(&e))), + StatementKind::If(e) => Box::new(hir::StatementKind::If(self.lower_if(e))), StatementKind::Assign(a) => { - Box::new(hir::StatementKind::Assign(self.lower_assign(&a))) + Box::new(hir::StatementKind::Assign(self.lower_assign(a))) } }, } @@ -252,10 +252,10 @@ impl AstLoweringContext { pub fn lower_assign_left_side(&mut self, assign_left: &AssignLeftSide) -> hir::AssignLeftSide { match assign_left { AssignLeftSide::Identifier(id) => { - hir::AssignLeftSide::Identifier(self.lower_identifier(&id)) + hir::AssignLeftSide::Identifier(self.lower_identifier(id)) } AssignLeftSide::Indice(indice) => { - let expr_hir = self.lower_expression(&indice); + let expr_hir = self.lower_expression(indice); let indice = match &*expr_hir.kind { hir::ExpressionKind::Indice(indice) => indice, _ => unimplemented!( @@ -266,7 +266,7 @@ impl AstLoweringContext { hir::AssignLeftSide::Indice(indice.clone()) } AssignLeftSide::Dot(dot) => { - let expr_hir = self.lower_expression(&dot); + let expr_hir = self.lower_expression(dot); let dot = match &*expr_hir.kind { hir::ExpressionKind::Dot(dot) => dot, _ => unimplemented!( @@ -289,10 +289,10 @@ impl AstLoweringContext { pub fn lower_expression(&mut self, expr: &Expression) -> hir::Expression { match &expr.kind { - ExpressionKind::UnaryExpr(unary) => self.lower_unary(&unary), - ExpressionKind::StructCtor(s) => self.lower_struct_ctor(&s), + ExpressionKind::UnaryExpr(unary) => self.lower_unary(unary), + ExpressionKind::StructCtor(s) => self.lower_struct_ctor(s), ExpressionKind::NativeOperation(op, left, right) => { - self.lower_native_operation(&op, &left, &right) + self.lower_native_operation(op, left, right) } ExpressionKind::BinopExpr(_unary, _op, _expr22) => { let mut infix = InfixDesugar::new(self.operators_list.clone()); @@ -322,7 +322,7 @@ impl AstLoweringContext { hir_id: self.hir_map.next_hir_id(r#if.identity.clone()), predicat: self.lower_expression(&r#if.predicat), body: self.lower_body(&r#if.body), - else_: r#if.else_.as_ref().map(|e| Box::new(self.lower_else(&e))), + else_: r#if.else_.as_ref().map(|e| Box::new(self.lower_else(e))), } } @@ -335,7 +335,7 @@ impl AstLoweringContext { pub fn lower_unary(&mut self, unary: &UnaryExpr) -> hir::Expression { match &unary { - UnaryExpr::PrimaryExpr(primary) => self.lower_primary(&primary), + UnaryExpr::PrimaryExpr(primary) => self.lower_primary(primary), _ => unimplemented!(), } } @@ -356,9 +356,9 @@ impl AstLoweringContext { pub fn lower_operand(&mut self, operand: &Operand) -> hir::Expression { match &operand.kind { - OperandKind::Literal(l) => hir::Expression::new_literal(self.lower_literal(&l)), + OperandKind::Literal(l) => hir::Expression::new_literal(self.lower_literal(l)), OperandKind::Identifier(i) => { - hir::Expression::new_identifier_path(self.lower_identifier_path(&i)) + hir::Expression::new_identifier_path(self.lower_identifier_path(i)) } OperandKind::Expression(e) => self.lower_expression(&**e), } @@ -457,15 +457,15 @@ impl AstLoweringContext { NativeOperatorKind::FMul => hir::NativeOperatorKind::FMul, NativeOperatorKind::FDiv => hir::NativeOperatorKind::FDiv, NativeOperatorKind::IEq => hir::NativeOperatorKind::IEq, - NativeOperatorKind::IGT => hir::NativeOperatorKind::IGT, - NativeOperatorKind::IGE => hir::NativeOperatorKind::IGE, - NativeOperatorKind::ILT => hir::NativeOperatorKind::ILT, - NativeOperatorKind::ILE => hir::NativeOperatorKind::ILE, + NativeOperatorKind::Igt => hir::NativeOperatorKind::Igt, + NativeOperatorKind::Ige => hir::NativeOperatorKind::Ige, + NativeOperatorKind::Ilt => hir::NativeOperatorKind::Ilt, + NativeOperatorKind::Ile => hir::NativeOperatorKind::Ile, NativeOperatorKind::FEq => hir::NativeOperatorKind::FEq, - NativeOperatorKind::FGT => hir::NativeOperatorKind::FGT, - NativeOperatorKind::FGE => hir::NativeOperatorKind::FGE, - NativeOperatorKind::FLT => hir::NativeOperatorKind::FLT, - NativeOperatorKind::FLE => hir::NativeOperatorKind::FLE, + NativeOperatorKind::Fgt => hir::NativeOperatorKind::Fgt, + NativeOperatorKind::Fge => hir::NativeOperatorKind::Fge, + NativeOperatorKind::Flt => hir::NativeOperatorKind::Flt, + NativeOperatorKind::Fle => hir::NativeOperatorKind::Fle, NativeOperatorKind::BEq => hir::NativeOperatorKind::BEq, }; diff --git a/src/lib/ast_lowering/infix_desugar.rs b/src/lib/ast_lowering/infix_desugar.rs index daed3043..df009e9c 100644 --- a/src/lib/ast_lowering/infix_desugar.rs +++ b/src/lib/ast_lowering/infix_desugar.rs @@ -42,7 +42,7 @@ impl InfixDesugar { let left = stack.pop().unwrap(); stack.push(UnaryExpr::create_2_args_func_call( - Operand::from_identifier(&id), + Operand::from_identifier(id), left.clone(), right.clone(), )); diff --git a/src/lib/ast_lowering/return_placement.rs b/src/lib/ast_lowering/return_placement.rs index 92cd97bc..63f8ce45 100644 --- a/src/lib/ast_lowering/return_placement.rs +++ b/src/lib/ast_lowering/return_placement.rs @@ -14,16 +14,15 @@ impl<'a> ReturnInserter<'a> { } fn visit_body(&mut self, body: &mut Body) { - body.stmts - .iter_mut() - .last() - .map(|stmt| self.visit_statement(stmt)); + if let Some(stmt) = body.stmts.iter_mut().last() { + self.visit_statement(stmt) + } } fn visit_statement(&mut self, stmt: &mut Statement) { match *stmt.kind { StatementKind::Expression(ref mut e) => { - e.kind = ExpressionKind::Return(Box::new(e.clone())); + e.kind = ExpressionKind::Return(e.clone()); } StatementKind::If(ref mut i) => { self.visit_if(i); @@ -33,6 +32,7 @@ impl<'a> ReturnInserter<'a> { } } } + fn visit_if(&mut self, r#if: &mut If) { self.visit_body(&mut r#if.body); diff --git a/src/lib/codegen/codegen_context.rs b/src/lib/codegen/codegen_context.rs index 912729f8..97e35318 100644 --- a/src/lib/codegen/codegen_context.rs +++ b/src/lib/codegen/codegen_context.rs @@ -1,15 +1,14 @@ -use std::convert::TryFrom; -use std::convert::TryInto; +use std::convert::{TryFrom, TryInto}; use inkwell::{ basic_block::BasicBlock, builder::Builder, - values::{AnyValue, AnyValueEnum, BasicValueEnum, CallableValue, FunctionValue}, - FloatPredicate, IntPredicate, + context::Context, + module::Module, + types::{BasicType, BasicTypeEnum}, + values::{AnyValue, AnyValueEnum, BasicValue, BasicValueEnum, CallableValue, FunctionValue}, + AddressSpace, FloatPredicate, IntPredicate, }; -use inkwell::{context::Context, types::BasicTypeEnum}; -use inkwell::{module::Module, values::BasicValue}; -use inkwell::{types::BasicType, AddressSpace}; use crate::{ ast::{PrimitiveType, Type}, @@ -53,30 +52,38 @@ impl<'a> CodegenContext<'a> { .i8_type() .ptr_type(AddressSpace::Generic) .into(), - Type::Primitive(PrimitiveType::Array(arr, size)) => { + Type::Primitive(PrimitiveType::Array(inner, size)) => { // assuming all types are equals - self.lower_type(arr, builder)? + self.lower_type(inner, builder)? .array_type(*size as u32) .ptr_type(AddressSpace::Generic) .into() } Type::FuncType(f) => { - // FIXME: Don't rely on names for resolution - let f2 = match self.module.get_function(&f.get_mangled_name()) { - Some(f2) => f2, - None => { - let f = self - .hir - .get_function_by_mangled_name(&f.get_mangled_name()) - .unwrap(); - - self.lower_function_decl(&f, builder)?; - - self.module.get_function(&f.get_name()).unwrap() - } + let ret_t = f.ret.clone(); + + let args = f + .arguments + .iter() + .map(|arg| self.lower_type(arg, builder)) + .collect::>(); + + let mut args_ret = vec![]; + + for arg in args { + args_ret.push(arg?); + } + + let args = args_ret; + + let fn_type = if let Type::Primitive(PrimitiveType::Void) = *ret_t { + self.context.void_type().fn_type(args.as_slice(), false) + } else { + self.lower_type(&ret_t, builder)? + .fn_type(args.as_slice(), false) }; - f2.get_type().ptr_type(AddressSpace::Generic).into() + fn_type.ptr_type(AddressSpace::Generic).into() } Type::Struct(s) => self .context @@ -97,13 +104,13 @@ impl<'a> CodegenContext<'a> { pub fn lower_hir(&mut self, root: &'a Root, builder: &'a Builder) -> Result<(), ()> { for item in &root.top_levels { match &item.kind { - TopLevelKind::Prototype(p) => self.lower_prototype(&p, builder)?, - TopLevelKind::Function(f) => self.lower_function_decl(&f, builder)?, + TopLevelKind::Prototype(p) => self.lower_prototype(p, builder)?, + TopLevelKind::Function(f) => self.lower_function_decl(f, builder)?, } } for body in root.bodies.values() { - self.lower_fn_body(&body, builder)?; + self.lower_fn_body(body, builder)?; } Ok(()) @@ -117,8 +124,8 @@ impl<'a> CodegenContext<'a> { let mut args = vec![]; - for arg in &p.signature.args { - args.push(self.lower_type(&arg, builder)?); + for arg in &p.signature.arguments { + args.push(self.lower_type(arg, builder)?); } let fn_type = if let Type::Primitive(PrimitiveType::Void) = *ret_t { @@ -216,7 +223,7 @@ impl<'a> CodegenContext<'a> { ) -> Result, ()> { let t = self.hir.node_types.get(&arg.name.hir_id).unwrap(); - self.lower_type(&t, builder) + self.lower_type(t, builder) } pub fn lower_fn_body(&mut self, fn_body: &'a FnBody, builder: &'a Builder) -> Result<(), ()> { @@ -251,14 +258,14 @@ impl<'a> CodegenContext<'a> { ) -> Result<(AnyValueEnum<'a>, BasicBlock<'a>), ()> { let basic_block = self .context - .append_basic_block(self.cur_func.clone().unwrap(), name); + .append_basic_block(self.cur_func.unwrap(), name); builder.position_at_end(basic_block); let stmt = body .stmts .iter() - .map(|stmt| self.lower_stmt(&stmt, builder)) + .map(|stmt| self.lower_stmt(stmt, builder)) .last() .unwrap()?; @@ -271,9 +278,9 @@ impl<'a> CodegenContext<'a> { builder: &'a Builder, ) -> Result, ()> { Ok(match &*stmt.kind { - StatementKind::Expression(e) => self.lower_expression(&e, builder)?.as_any_value_enum(), - StatementKind::If(e) => self.lower_if(&e, builder)?.0, - StatementKind::Assign(a) => self.lower_assign(&a, builder)?, + StatementKind::Expression(e) => self.lower_expression(e, builder)?.as_any_value_enum(), + StatementKind::If(e) => self.lower_if(e, builder)?.0, + StatementKind::Assign(a) => self.lower_assign(a, builder)?, }) } @@ -324,9 +331,8 @@ impl<'a> CodegenContext<'a> { } else { //new empty block let f = self.module.get_last_function().unwrap(); - let else_block = self.context.append_basic_block(f, "else"); - else_block + self.context.append_basic_block(f, "else") }; // FIXME: Need a last block if the 'if' is not the last statement in the fn body @@ -359,7 +365,7 @@ impl<'a> CodegenContext<'a> { Else::If(i) => { let block = self .context - .append_basic_block(self.cur_func.clone().unwrap(), "if"); + .append_basic_block(self.cur_func.unwrap(), "if"); builder.position_at_end(block); @@ -375,8 +381,8 @@ impl<'a> CodegenContext<'a> { builder: &'a Builder, ) -> Result, ()> { Ok(match &*expr.kind { - ExpressionKind::Lit(l) => self.lower_literal(&l, builder)?, - ExpressionKind::Identifier(id) => self.lower_identifier_path(&id, builder)?, + ExpressionKind::Lit(l) => self.lower_literal(l, builder)?, + ExpressionKind::Identifier(id) => self.lower_identifier_path(id, builder)?, ExpressionKind::FunctionCall(fc) => self.lower_function_call(fc, builder)?, ExpressionKind::StructCtor(s) => self.lower_struct_ctor(s, builder)?, ExpressionKind::Indice(i) => self.lower_indice(i, builder)?, @@ -402,7 +408,7 @@ impl<'a> CodegenContext<'a> { let t = self.hir.node_types.get(&s.get_hir_id()).unwrap(); let struct_t = t.into_struct_type(); - let llvm_struct_t_ptr = self.lower_type(&t, builder).unwrap().into_pointer_type(); + let llvm_struct_t_ptr = self.lower_type(t, builder).unwrap().into_pointer_type(); let llvm_struct_t = llvm_struct_t_ptr.get_element_type().into_struct_type(); // FIXME: types should be ordered already @@ -428,7 +434,7 @@ impl<'a> CodegenContext<'a> { .build_struct_gep(ptr, i as u32, "struct_inner") .unwrap(); - builder.build_store(inner_ptr, def.clone()); + builder.build_store(inner_ptr, *def); } Ok(ptr.into()) @@ -443,7 +449,7 @@ impl<'a> CodegenContext<'a> { let f_id = self.hir.resolutions.get(&terminal_hir_id).unwrap(); - let callable_value = match self.hir.get_top_level(f_id.clone()) { + let callable_value = match self.hir.get_top_level(f_id) { Some(top) => CallableValue::try_from(match &top.kind { TopLevelKind::Prototype(p) => { self.module.get_function(&p.name.to_string()).unwrap() @@ -462,7 +468,7 @@ impl<'a> CodegenContext<'a> { let mut arguments = vec![]; for arg in &fc.args { - arguments.push(self.lower_expression(&arg, builder)?); + arguments.push(self.lower_expression(arg, builder)?); } Ok(builder @@ -563,7 +569,7 @@ impl<'a> CodegenContext<'a> { LiteralKind::Float(n) => { let f64_type = self.context.f64_type(); - f64_type.const_float((*n).try_into().unwrap()).into() + f64_type.const_float(*n).into() } LiteralKind::Bool(b) => { let bool_type = self.context.bool_type(); @@ -590,7 +596,7 @@ impl<'a> CodegenContext<'a> { let i64_type = self.context.i64_type(); - let const_i = i64_type.const_int(i as u64, false).into(); + let const_i = i64_type.const_int(i as u64, false); let const_0 = i64_type.const_zero(); let inner_ptr = unsafe { @@ -610,7 +616,7 @@ impl<'a> CodegenContext<'a> { id: &IdentifierPath, _builder: &'a Builder, ) -> Result, ()> { - Ok(self.lower_identifier(id.path.iter().last().unwrap(), _builder)?) + self.lower_identifier(id.path.iter().last().unwrap(), _builder) } pub fn lower_identifier( @@ -621,7 +627,7 @@ impl<'a> CodegenContext<'a> { let reso = self.hir.resolutions.get(&id.hir_id).unwrap(); // println!("SCOPES {:#?}", self.scopes); - let val = match self.scopes.get(reso.clone()) { + let val = match self.scopes.get(reso) { None => { let span = self .hir @@ -728,7 +734,7 @@ impl<'a> CodegenContext<'a> { .build_int_compare(IntPredicate::EQ, left, right, "ieq") .as_basic_value_enum() } - NativeOperatorKind::IGT => { + NativeOperatorKind::Igt => { let left = self.lower_identifier(left, builder)?.into_int_value(); let right = self.lower_identifier(right, builder)?.into_int_value(); @@ -736,7 +742,7 @@ impl<'a> CodegenContext<'a> { .build_int_compare(IntPredicate::SGT, left, right, "isgt") .as_basic_value_enum() } - NativeOperatorKind::IGE => { + NativeOperatorKind::Ige => { let left = self.lower_identifier(left, builder)?.into_int_value(); let right = self.lower_identifier(right, builder)?.into_int_value(); @@ -744,7 +750,7 @@ impl<'a> CodegenContext<'a> { .build_int_compare(IntPredicate::SGE, left, right, "isge") .as_basic_value_enum() } - NativeOperatorKind::ILT => { + NativeOperatorKind::Ilt => { let left = self.lower_identifier(left, builder)?.into_int_value(); let right = self.lower_identifier(right, builder)?.into_int_value(); @@ -752,7 +758,7 @@ impl<'a> CodegenContext<'a> { .build_int_compare(IntPredicate::SLT, left, right, "islt") .as_basic_value_enum() } - NativeOperatorKind::ILE => { + NativeOperatorKind::Ile => { let left = self.lower_identifier(left, builder)?.into_int_value(); let right = self.lower_identifier(right, builder)?.into_int_value(); @@ -768,7 +774,7 @@ impl<'a> CodegenContext<'a> { .build_float_compare(FloatPredicate::OEQ, left, right, "feq") .as_basic_value_enum() } - NativeOperatorKind::FGT => { + NativeOperatorKind::Fgt => { let left = self.lower_identifier(left, builder)?.into_float_value(); let right = self.lower_identifier(right, builder)?.into_float_value(); @@ -776,7 +782,7 @@ impl<'a> CodegenContext<'a> { .build_float_compare(FloatPredicate::OGT, left, right, "fsgt") .as_basic_value_enum() } - NativeOperatorKind::FGE => { + NativeOperatorKind::Fge => { let left = self.lower_identifier(left, builder)?.into_float_value(); let right = self.lower_identifier(right, builder)?.into_float_value(); @@ -784,7 +790,7 @@ impl<'a> CodegenContext<'a> { .build_float_compare(FloatPredicate::OGE, left, right, "fsge") .as_basic_value_enum() } - NativeOperatorKind::FLT => { + NativeOperatorKind::Flt => { let left = self.lower_identifier(left, builder)?.into_float_value(); let right = self.lower_identifier(right, builder)?.into_float_value(); @@ -792,7 +798,7 @@ impl<'a> CodegenContext<'a> { .build_float_compare(FloatPredicate::OLT, left, right, "fslt") .as_basic_value_enum() } - NativeOperatorKind::FLE => { + NativeOperatorKind::Fle => { let left = self.lower_identifier(left, builder)?.into_float_value(); let right = self.lower_identifier(right, builder)?.into_float_value(); diff --git a/src/lib/codegen/mod.rs b/src/lib/codegen/mod.rs index 7e8dc301..3a5cc3f0 100644 --- a/src/lib/codegen/mod.rs +++ b/src/lib/codegen/mod.rs @@ -5,7 +5,7 @@ use inkwell::context::Context; use crate::{diagnostics::Diagnostic, hir::Root, parser::ParsingCtx, Config}; -pub fn generate<'a>( +pub fn generate( config: &Config, parsing_ctx: ParsingCtx, hir: Root, @@ -14,7 +14,7 @@ pub fn generate<'a>( let builder = context.create_builder(); let mut codegen_ctx = CodegenContext::new(&context, parsing_ctx, &hir); - if let Err(_) = codegen_ctx.lower_hir(&hir, &builder) { + if codegen_ctx.lower_hir(&hir, &builder).is_err() { codegen_ctx.parsing_ctx.return_if_error()?; } diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index a6a06b00..ef653546 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -1,7 +1,7 @@ use std::fmt::Display; use crate::{ - ast::{Type, TypeSignature}, + ast::{FuncType, Type}, hir::HirId, parser::SourceFile, }; @@ -29,6 +29,7 @@ impl Diagnostic { pub fn new_file_not_found(span: Span, path: String) -> Self { Self::new(span, DiagnosticKind::FileNotFound(path)) } + pub fn new_unexpected_token(span: Span) -> Self { Self::new(span, DiagnosticKind::UnexpectedToken) } @@ -60,8 +61,8 @@ impl Diagnostic { pub fn new_unresolved_trait_call( span: Span, call_hir_id: HirId, - given_sig: TypeSignature, - existing_impls: Vec, + given_sig: FuncType, + existing_impls: Vec, ) -> Self { Self::new( span, @@ -174,8 +175,8 @@ pub enum DiagnosticKind { UnusedParameter, UnresolvedTraitCall { call_hir_id: HirId, - given_sig: TypeSignature, - existing_impls: Vec, + given_sig: FuncType, + existing_impls: Vec, }, UnusedFunction, DuplicatedOperator, @@ -210,11 +211,11 @@ impl Display for DiagnosticKind { existing_impls, } => { format!( - "Unresolved trait call {}\n{}", + "Unresolved trait call {:?}\n{}", given_sig, existing_impls .iter() - .map(|sig| format!("Found impl: {}", sig)) + .map(|sig| format!("Found impl: {:?}", sig)) .collect::>() .join("\n") ) diff --git a/src/lib/helpers/scopes.rs b/src/lib/helpers/scopes.rs index d3b32aa5..dc06320d 100644 --- a/src/lib/helpers/scopes.rs +++ b/src/lib/helpers/scopes.rs @@ -2,13 +2,17 @@ use std::collections::HashMap; use std::hash::Hash; #[derive(Clone, Debug)] -pub struct Scopes { +pub struct Scopes +where + K: Default + Hash + Eq + Clone, + T: Clone, +{ pub scopes: Vec>, } impl Default for Scopes where - K: Hash + Eq + Clone, + K: Default + Hash + Eq + Clone, T: Clone, { fn default() -> Self { @@ -18,7 +22,7 @@ where impl Scopes where - K: Hash + Eq + Clone, + K: Default + Hash + Eq + Clone, T: Clone, { pub fn new() -> Scopes { @@ -58,21 +62,35 @@ where } #[derive(Clone, Debug)] -pub struct Scope { +pub struct Scope +where + K: Default + Hash + Eq + Clone, + T: Clone, +{ pub ordering: Vec, pub items: HashMap, } +impl Default for Scope +where + K: Default + Hash + Eq + Clone, + T: Clone, +{ + fn default() -> Self { + Self { + ordering: Default::default(), + items: Default::default(), + } + } +} + impl Scope where - K: Hash + Eq + Clone, + K: Default + Hash + Eq + Clone, T: Clone, { pub fn new() -> Scope { - Scope { - ordering: vec![], - items: HashMap::new(), - } + Default::default() } pub fn insert(&mut self, s: K, v: T) { diff --git a/src/lib/hir/arena.rs b/src/lib/hir/arena.rs index 35e9a181..760934a3 100644 --- a/src/lib/hir/arena.rs +++ b/src/lib/hir/arena.rs @@ -96,7 +96,7 @@ generate_hirnode_collector!( pub fn collect_arena(root: &Root) -> Arena { let mut hir_node_collector = HirNodeCollector::new(); - hir_node_collector.visit_root(&root); + hir_node_collector.visit_root(root); hir_node_collector.take_arena() } diff --git a/src/lib/hir/hir_printer.rs b/src/lib/hir/hir_printer.rs index 2562d5c7..15e797ac 100644 --- a/src/lib/hir/hir_printer.rs +++ b/src/lib/hir/hir_printer.rs @@ -67,7 +67,7 @@ macro_rules! impl_visitor_trait2 { $name:ident )*) => { impl<'a> Visitor<'a> for HirPrinter<'a> { - fn visit_name(&mut self, name: String) { + fn visit_name(&mut self, name: &str) { self.print_primitive(name); } diff --git a/src/lib/hir/tree.rs b/src/lib/hir/tree.rs index 1c0213c9..041cc297 100644 --- a/src/lib/hir/tree.rs +++ b/src/lib/hir/tree.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ - ast::{resolve::ResolutionMap, StructType, Type, TypeSignature}, + ast::{resolve::ResolutionMap, FuncType, StructType, Type}, ast_lowering::HirMap, hir::hir_id::*, parser::Span, @@ -20,7 +20,7 @@ pub struct Root { pub types: BTreeMap, pub node_types: BTreeMap, pub traits: HashMap, // TraitHirId => (Trait, TypeId => Impl) - pub trait_methods: HashMap>, + pub trait_methods: HashMap>, pub top_levels: Vec, pub bodies: BTreeMap, pub spans: HashMap, @@ -37,21 +37,11 @@ impl Root { pub fn get_trait_by_method(&self, ident: String) -> Option { self.traits .iter() - .find(|(_, r#trait)| { - r#trait - .defs - .iter() - .find(|proto| *proto.name == ident) - .is_some() - }) + .find(|(_, r#trait)| r#trait.defs.iter().any(|proto| proto.name.name == ident)) .map(|(_, r#trait)| r#trait.clone()) } - pub fn get_trait_method( - &self, - ident: String, - applied_type: &TypeSignature, - ) -> Option { + pub fn get_trait_method(&self, ident: String, applied_type: &FuncType) -> Option { self.trait_methods .get(&ident)? .get(applied_type) @@ -60,7 +50,7 @@ impl Root { self.trait_methods .get(&ident)? .iter() - .find(|(sig, _)| sig.args == applied_type.args) + .find(|(sig, _)| sig.arguments == applied_type.arguments) .map(|(_, f)| f.clone()) }) } @@ -69,7 +59,7 @@ impl Root { let map = self.trait_methods.get(&ident)?; map.iter() - .find(|(sig, _)| sig.args[0] == *applied_type) + .find(|(sig, _)| *sig.arguments[0] == *applied_type) .map(|(_, fn_decl)| fn_decl.clone()) } @@ -169,15 +159,12 @@ impl StructDecl { .defs .iter() .map(|proto| { - if proto.signature.args.is_empty() { - ( - proto.name.name.clone(), - Box::new(proto.signature.ret.clone()), - ) + if proto.signature.arguments.is_empty() { + (proto.name.name.clone(), proto.signature.ret.clone()) } else { ( proto.name.name.clone(), - Box::new(proto.signature.to_func_type()), + Box::new(Type::FuncType(proto.signature.clone())), ) } }) @@ -217,7 +204,7 @@ pub enum TopLevelKind { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Prototype { pub name: Identifier, - pub signature: TypeSignature, + pub signature: FuncType, pub hir_id: HirId, } @@ -228,7 +215,7 @@ pub struct FunctionDecl { pub arguments: Vec, pub body_id: FnBodyId, pub hir_id: HirId, - pub signature: TypeSignature, + pub signature: FuncType, } impl FunctionDecl { @@ -489,7 +476,7 @@ impl Expression { pub fn as_identifier(&self) -> Identifier { if let ExpressionKind::Identifier(i) = &*self.kind { - i.last_segment().clone() + i.last_segment() } else { panic!("Not an identifier"); } @@ -537,40 +524,29 @@ pub struct FunctionCall { } impl FunctionCall { - // pub fn get_mangled_name(&self, prefixes: Vec) -> Option { - // match &*self.op.kind { - // ExpressionKind::Identifier(id) => { - // let identifier = id.path.iter().last().unwrap(); - - // Some(prefixes.join("_") + "_" + &identifier.name) - // } - // _ => None, // FIXME: recurse on '(expr)' parenthesis expression - // } - // } - pub fn mangle(&mut self, prefixes: Vec) { match &mut *self.op.kind { ExpressionKind::Identifier(id) => { let identifier = id.path.iter_mut().last().unwrap(); identifier.name = format!("{}_{}", identifier.name, &prefixes.join("_")); - // identifier.name = prefixes.join("_") + "_" + &identifier.name; } - _ => (), // FIXME: recurse on '(expr)' parenthesis expression + _ => unimplemented!("Need to recurse on expr"), // FIXME: recurse on '(expr)' parenthesis expression } } - pub fn to_type_signature(&self, env: &BTreeMap) -> TypeSignature { - TypeSignature::from_args_nb(self.args.len()).apply_partial_types( + pub fn to_func_type(&self, env: &BTreeMap) -> FuncType { + FuncType::from_args_nb(self.args.len()).apply_partial_types( &self .args .iter() .map(|arg| env.get(&arg.get_hir_id()).cloned()) - .collect(), + .collect::>(), env.get(&self.hir_id).cloned(), ) } } + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct Literal { pub hir_id: HirId, @@ -624,15 +600,15 @@ pub enum NativeOperatorKind { FMul, FDiv, IEq, - IGT, - IGE, - ILT, - ILE, + Igt, + Ige, + Ilt, + Ile, FEq, - FLE, - FGT, - FGE, - FLT, + Fle, + Fgt, + Fge, + Flt, BEq, } diff --git a/src/lib/hir/visit.rs b/src/lib/hir/visit.rs index 67b35c57..a56b7f42 100644 --- a/src/lib/hir/visit.rs +++ b/src/lib/hir/visit.rs @@ -1,14 +1,14 @@ use concat_idents::concat_idents; +use crate::{ast::FuncType, walk_list}; use crate::{ast::Type, hir::*}; -use crate::{ast::TypeSignature, walk_list}; macro_rules! generate_visitor_trait { ($( $name:ident, $method:ident )*) => { pub trait Visitor<'ast>: Sized { - fn visit_name(&mut self, _name: String) {} + fn visit_name(&mut self, _name: &str) {} fn visit_primitive(&mut self, _val: T) {} @@ -53,21 +53,21 @@ generate_visitor_trait!( Array, array NativeOperator, native_operator Type, r#type - TypeSignature, type_signature + FuncType, func_type ); pub fn walk_root<'a, V: Visitor<'a>>(visitor: &mut V, root: &'a Root) { walk_list!(visitor, visit_top_level, &root.top_levels); - for (_, r#struct) in &root.structs { + for r#struct in root.structs.values() { visitor.visit_struct_decl(r#struct); } - for (_, r#trait) in &root.traits { + for r#trait in root.traits.values() { visitor.visit_trait(r#trait); } - for (_, impls) in &root.trait_methods { + for impls in root.trait_methods.values() { walk_map!(visitor, visit_function_decl, impls); } @@ -76,8 +76,8 @@ pub fn walk_root<'a, V: Visitor<'a>>(visitor: &mut V, root: &'a Root) { pub fn walk_top_level<'a, V: Visitor<'a>>(visitor: &mut V, top_level: &'a TopLevel) { match &top_level.kind { - TopLevelKind::Prototype(p) => visitor.visit_prototype(&p), - TopLevelKind::Function(f) => visitor.visit_function_decl(&f), + TopLevelKind::Prototype(p) => visitor.visit_prototype(p), + TopLevelKind::Function(f) => visitor.visit_function_decl(f), }; } @@ -107,7 +107,7 @@ pub fn walk_impl<'a, V: Visitor<'a>>(visitor: &mut V, i: &'a Impl) { pub fn walk_prototype<'a, V: Visitor<'a>>(visitor: &mut V, prototype: &'a Prototype) { visitor.visit_identifier(&prototype.name); - visitor.visit_type_signature(&prototype.signature); + visitor.visit_func_type(&prototype.signature); } pub fn walk_function_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_decl: &'a FunctionDecl) { @@ -121,7 +121,7 @@ pub fn walk_identifier_path<'a, V: Visitor<'a>>(visitor: &mut V, identifier: &'a } pub fn walk_identifier<'a, V: Visitor<'a>>(visitor: &mut V, identifier: &'a Identifier) { - visitor.visit_name(identifier.name.clone()); + visitor.visit_name(&identifier.name); } pub fn walk_argument_decl<'a, V: Visitor<'a>>(visitor: &mut V, argument: &'a ArgumentDecl) { @@ -151,24 +151,24 @@ pub fn walk_assign<'a, V: Visitor<'a>>(visitor: &mut V, assign: &'a Assign) { pub fn walk_statement<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Statement) { match statement.kind.as_ref() { - StatementKind::Expression(expr) => visitor.visit_expression(&expr), - StatementKind::Assign(assign) => visitor.visit_assign(&assign), - StatementKind::If(expr) => visitor.visit_if(&expr), + StatementKind::Expression(expr) => visitor.visit_expression(expr), + StatementKind::Assign(assign) => visitor.visit_assign(assign), + StatementKind::If(expr) => visitor.visit_if(expr), } } pub fn walk_expression<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a Expression) { match &*expr.kind { - ExpressionKind::Lit(lit) => visitor.visit_literal(&lit), - ExpressionKind::Identifier(id) => visitor.visit_identifier_path(&id), - ExpressionKind::FunctionCall(fc) => visitor.visit_function_call(&fc), - ExpressionKind::StructCtor(s) => visitor.visit_struct_ctor(&s), + ExpressionKind::Lit(lit) => visitor.visit_literal(lit), + ExpressionKind::Identifier(id) => visitor.visit_identifier_path(id), + ExpressionKind::FunctionCall(fc) => visitor.visit_function_call(fc), + ExpressionKind::StructCtor(s) => visitor.visit_struct_ctor(s), ExpressionKind::Indice(indice) => visitor.visit_indice(indice), ExpressionKind::Dot(dot) => visitor.visit_dot(dot), ExpressionKind::NativeOperation(op, left, right) => { - visitor.visit_native_operator(&op); - visitor.visit_identifier(&left); - visitor.visit_identifier(&right); + visitor.visit_native_operator(op); + visitor.visit_identifier(left); + visitor.visit_identifier(right); } ExpressionKind::Return(expr) => visitor.visit_expression(expr), } @@ -219,14 +219,14 @@ pub fn walk_if<'a, V: Visitor<'a>>(visitor: &mut V, r#if: &'a If) { visitor.visit_body(&r#if.body); if let Some(r#else) = &r#if.else_ { - visitor.visit_else(&r#else); + visitor.visit_else(r#else); } } pub fn walk_else<'a, V: Visitor<'a>>(visitor: &mut V, r#else: &'a Else) { match r#else { - Else::If(expr) => visitor.visit_if(&expr), - Else::Body(expr) => visitor.visit_body(&expr), + Else::If(expr) => visitor.visit_if(expr), + Else::Body(expr) => visitor.visit_body(expr), } } @@ -234,8 +234,8 @@ pub fn walk_type<'a, V: Visitor<'a>>(_visitor: &mut V, _t: &'a Type) { // Nothing to do } -pub fn walk_type_signature<'a, V: Visitor<'a>>(visitor: &mut V, signature: &'a TypeSignature) { - walk_list!(visitor, visit_type, &signature.args); +pub fn walk_func_type<'a, V: Visitor<'a>>(visitor: &mut V, signature: &'a FuncType) { + walk_list!(visitor, visit_type, &signature.arguments); visitor.visit_type(&signature.ret); } diff --git a/src/lib/hir/visit_mut.rs b/src/lib/hir/visit_mut.rs index 4d6013e5..b03c9744 100644 --- a/src/lib/hir/visit_mut.rs +++ b/src/lib/hir/visit_mut.rs @@ -1,7 +1,7 @@ use concat_idents::concat_idents; +use crate::{ast::FuncType, walk_list}; use crate::{ast::Type, hir::*}; -use crate::{ast::TypeSignature, walk_list}; macro_rules! generate_visitor_mut_trait { ($( @@ -53,13 +53,13 @@ generate_visitor_mut_trait!( Array, array NativeOperator, native_operator Type, r#type - TypeSignature, type_signature + FuncType, func_type ); pub fn walk_root<'a, V: VisitorMut<'a>>(visitor: &mut V, root: &'a mut Root) { walk_list!(visitor, visit_top_level, &mut root.top_levels); - for (_, r#struct) in &mut root.structs { + for r#struct in &mut root.structs.values_mut() { visitor.visit_struct_decl(r#struct); } @@ -114,7 +114,7 @@ pub fn walk_impl<'a, V: VisitorMut<'a>>(visitor: &mut V, i: &'a mut Impl) { pub fn walk_prototype<'a, V: VisitorMut<'a>>(visitor: &mut V, prototype: &'a mut Prototype) { visitor.visit_identifier(&mut prototype.name); - visitor.visit_type_signature(&mut prototype.signature); + visitor.visit_func_type(&mut prototype.signature); } pub fn walk_function_decl<'a, V: VisitorMut<'a>>( @@ -247,11 +247,8 @@ pub fn walk_type<'a, V: VisitorMut<'a>>(_visitor: &mut V, _t: &'a mut Type) { // Nothing to do } -pub fn walk_type_signature<'a, V: VisitorMut<'a>>( - visitor: &mut V, - signature: &'a mut TypeSignature, -) { - walk_list!(visitor, visit_type, &mut signature.args); +pub fn walk_func_type<'a, V: VisitorMut<'a>>(visitor: &mut V, signature: &'a mut FuncType) { + walk_list!(visitor, visit_type, &mut signature.arguments); visitor.visit_type(&mut signature.ret); } diff --git a/src/lib/infer/annotate.rs b/src/lib/infer/annotate.rs deleted file mode 100644 index 7f485281..00000000 --- a/src/lib/infer/annotate.rs +++ /dev/null @@ -1,182 +0,0 @@ -use std::collections::{BTreeMap, HashMap}; - -use super::InferState; -use crate::hir::visit::*; -use crate::hir::*; -use crate::walk_list; -use crate::{ - ast::{PrimitiveType, Type, TypeSignature}, - walk_map, -}; - -#[derive(Debug)] -pub struct AnnotateContext<'a> { - state: InferState<'a>, - trait_methods: HashMap>, - body_arguments: BTreeMap>, -} - -impl<'a> AnnotateContext<'a> { - pub fn new( - state: InferState<'a>, - trait_methods: HashMap>, - ) -> Self { - Self { - state, - trait_methods, - body_arguments: BTreeMap::new(), - } - } - - pub fn annotate(&mut self, root: &'a Root) { - self.visit_root(root); - } - - pub fn get_state(self) -> InferState<'a> { - self.state - } -} - -impl<'a, 'ar> Visitor<'a> for AnnotateContext<'ar> { - fn visit_root(&mut self, root: &'a Root) { - walk_list!(self, visit_top_level, &root.top_levels); - - for (_, r#trait) in &root.traits { - self.visit_trait(r#trait); - } - - for (_, impls) in &root.trait_methods { - walk_map!(self, visit_function_decl, impls); - } - - walk_map!(self, visit_fn_body, &root.bodies); - } - - fn visit_top_level(&mut self, top_level: &'a TopLevel) { - match &top_level.kind { - TopLevelKind::Prototype(p) => { - // self.state.new_type_id(p.name.get_hir_id()); - self.visit_prototype(&p); - } - TopLevelKind::Function(f) => { - // self.state.new_type_id(f.name.get_hir_id()); - self.visit_function_decl(&f); - } - }; - } - - // Ignoring traits - fn visit_trait(&mut self, _t: &Trait) {} - - fn visit_impl(&mut self, i: &Impl) { - self.visit_type(&i.name); - - walk_list!(self, visit_type, &i.types); - - walk_list!(self, visit_function_decl, &i.defs); - - for (_method_name, list) in &self.trait_methods { - for (sig, f_decl) in list { - for (i, arg) in f_decl.arguments.iter().enumerate() { - self.state - .new_type_solved(arg.name.hir_id.clone(), sig.args[i].clone()); - } - - self.state - .new_type_solved(f_decl.hir_id.clone(), sig.ret.clone()); - } - } - } - - fn visit_function_decl(&mut self, f: &FunctionDecl) { - self.state.new_type_id(f.hir_id.clone()); - self.state.new_type_id(f.name.hir_id.clone()); - - self.body_arguments - .insert(f.body_id.clone(), f.arguments.clone()); - } - - fn visit_prototype(&mut self, p: &Prototype) { - self.state.new_type_id(p.hir_id.clone()); - self.state.new_type_id(p.name.hir_id.clone()); - } - - fn visit_fn_body(&mut self, fn_body: &FnBody) { - let args = self.body_arguments.get(&fn_body.id).unwrap().clone(); - - walk_list!(self, visit_argument_decl, &args); - - self.visit_body(&fn_body.body); - } - - fn visit_literal(&mut self, lit: &Literal) { - let t = match &lit.kind { - LiteralKind::Number(_n) => Type::Primitive(PrimitiveType::Int64), - LiteralKind::Float(_f) => Type::Primitive(PrimitiveType::Float64), - LiteralKind::String(s) => Type::Primitive(PrimitiveType::String(s.len())), - LiteralKind::Bool(_b) => Type::Primitive(PrimitiveType::Bool), - }; - - self.state.new_type_solved(lit.hir_id.clone(), t); - } - - fn visit_identifier_path(&mut self, id: &IdentifierPath) { - self.visit_identifier(id.path.iter().last().unwrap()); - } - - fn visit_identifier(&mut self, id: &Identifier) { - self.state.new_type_id(id.hir_id.clone()); - } - - fn visit_if(&mut self, r#if: &If) { - self.state.new_type_id(r#if.hir_id.clone()); - - self.visit_expression(&r#if.predicat); - - self.state.solve_type( - r#if.predicat.get_terminal_hir_id(), - Type::Primitive(PrimitiveType::Bool), - ); - - self.visit_body(&r#if.body); - - if let Some(e) = &r#if.else_ { - self.visit_else(e); - } - } - - fn visit_function_call(&mut self, fc: &FunctionCall) { - self.state.new_type_id(fc.hir_id.clone()); - - self.visit_expression(&fc.op); - - walk_list!(self, visit_expression, &fc.args); - } - - fn visit_native_operator(&mut self, op: &NativeOperator) { - let t = match op.kind { - NativeOperatorKind::IEq - | NativeOperatorKind::IGT - | NativeOperatorKind::IGE - | NativeOperatorKind::ILT - | NativeOperatorKind::ILE - | NativeOperatorKind::FEq - | NativeOperatorKind::FGT - | NativeOperatorKind::FGE - | NativeOperatorKind::FLT - | NativeOperatorKind::FLE - | NativeOperatorKind::BEq => PrimitiveType::Bool, - NativeOperatorKind::IAdd - | NativeOperatorKind::ISub - | NativeOperatorKind::IDiv - | NativeOperatorKind::IMul => PrimitiveType::Int64, - NativeOperatorKind::FAdd - | NativeOperatorKind::FSub - | NativeOperatorKind::FDiv - | NativeOperatorKind::FMul => PrimitiveType::Float64, - }; - - self.state - .new_type_solved(op.hir_id.clone(), Type::Primitive(t)); - } -} diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index bc52e449..9254cc64 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -1,11 +1,11 @@ use std::collections::BTreeMap; use crate::{ - ast::{resolve::ResolutionMap, FuncType, PrimitiveType, Type, TypeSignature}, + ast::{resolve::ResolutionMap, FuncType, PrimitiveType, Type}, diagnostics::{Diagnostic, Diagnostics}, hir::visit::*, hir::*, - walk_list, Envs, + walk_list, walk_map, Envs, }; #[derive(Debug)] @@ -29,14 +29,14 @@ impl<'a> ConstraintContext<'a> { if !self.envs.set_current_fn(( entry_point.hir_id.clone(), - TypeSignature::default().with_ret(Type::int64()), + FuncType::default().with_ret(Type::int64()), )) { return; } self.tmp_resolutions .entry(entry_point.hir_id.clone()) - .or_insert_with(|| ResolutionMap::default()); + .or_insert_with(ResolutionMap::default); self.visit_function_decl(&entry_point); } @@ -68,7 +68,7 @@ impl<'a> ConstraintContext<'a> { if let Some(existing_impls) = self.hir.trait_methods.get(&p.name.name) { if let Some(f) = self.hir.get_trait_method( (*p.name).clone(), - &fc.to_type_signature(self.envs.get_current_env().unwrap()) + &fc.to_func_type(self.envs.get_current_env().unwrap()) .merge_with(&p.signature), ) { self.setup_trait_call(fc, &f); @@ -77,12 +77,11 @@ impl<'a> ConstraintContext<'a> { Diagnostic::new_unresolved_trait_call( self.envs.spans.get(&call_hir_id.clone()).unwrap().clone(), call_hir_id.clone(), - fc.to_type_signature(self.envs.get_current_env().unwrap()) + fc.to_func_type(self.envs.get_current_env().unwrap()) .merge_with(&p.signature), existing_impls.keys().cloned().collect(), ), ); - return; } } else { self.setup_prototype_call(fc, p); @@ -110,7 +109,7 @@ impl<'a> ConstraintContext<'a> { .unwrap() .insert(fc.op.get_hir_id(), f.hir_id.clone()); - self.setup_function_call(fc, &f); + self.setup_function_call(fc, f); } pub fn setup_identifier_call(&mut self, fc: &FunctionCall, id: &Identifier) { @@ -136,10 +135,26 @@ impl<'a> ConstraintContext<'a> { self.envs.set_type(&fc.get_hir_id(), &p.signature.ret); self.envs - .set_type(&fc.op.get_hir_id(), &p.signature.to_func_type()); + .set_type(&fc.op.get_hir_id(), &Type::FuncType(p.signature.clone())); } pub fn setup_function_call(&mut self, fc: &FunctionCall, f: &FunctionDecl) { + if f.signature.arguments.len() != fc.args.len() { + self.envs + .diagnostics + .push_error(Diagnostic::new_type_conflict( + self.envs.spans.get(&fc.op.get_hir_id()).unwrap().clone(), + fc.to_func_type(self.envs.get_current_env().unwrap()) + .to_type(), + f.signature.to_type(), + fc.to_func_type(self.envs.get_current_env().unwrap()) + .to_type(), + f.signature.to_type(), + )); + + return; + } + // Creating a fresh signature by merging arguments types with function signature let sig = f.signature.apply_partial_types( &f.arguments @@ -153,27 +168,51 @@ impl<'a> ConstraintContext<'a> { self.envs.get_type(arg_id).cloned().or_else(|| { if let HirNode::FunctionDecl(f2) = - self.hir.arena.get(&self.resolve(&arg_id)?)? + self.hir.arena.get(&self.resolve(arg_id)?)? { // Solving the func arg in the scope of the arg // Adds a link like `arg` => `out fn` where the arg is defined self.tmp_resolutions .entry(f.hir_id.clone()) - .or_insert_with(|| ResolutionMap::default()) + .or_insert_with(ResolutionMap::default) .insert(arg.get_hir_id(), f2.hir_id.clone()); - self.envs.set_type(&arg_id, &f.signature.to_func_type()); + self.envs.set_type(arg_id, &f.signature.to_type()); - Some(f.signature.to_func_type()) + Some(f.signature.to_type()) } else { None } }) }) - .collect(), + .collect::>(), None, ); + if sig.arguments + != fc + .to_func_type(self.envs.get_current_env().unwrap()) + .arguments + { + self.envs + .diagnostics + .push_error(Diagnostic::new_type_conflict( + self.envs.spans.get(&fc.op.get_hir_id()).unwrap().clone(), + fc.to_func_type(self.envs.get_current_env().unwrap()) + .to_type(), + sig.to_type(), + fc.to_func_type(self.envs.get_current_env().unwrap()) + .to_type(), + sig.to_type(), + )); + return; + // panic!( + // "BAD CALL {:#?} {:#?}", + // fc.to_func_type(self.envs.get_current_env().unwrap()), + // sig + // ); + } + // Carring about recursion if self.envs.get_current_fn().0 == f.hir_id { warn!("Recursion ! {:#?}", sig); @@ -184,7 +223,7 @@ impl<'a> ConstraintContext<'a> { &self.hir.bodies.get(&f.body_id).unwrap().get_hir_id(), ); - self.envs.set_type(&fc.op.get_hir_id(), &sig.to_func_type()); + self.envs.set_type(&fc.op.get_hir_id(), &sig.to_type()); return; } @@ -201,7 +240,7 @@ impl<'a> ConstraintContext<'a> { // TODO: might be unnecessary self.tmp_resolutions .entry(f.hir_id.clone()) - .or_insert_with(|| ResolutionMap::default()); + .or_insert_with(ResolutionMap::default); // We go down the rabbit hole // @@ -225,11 +264,11 @@ impl<'a> ConstraintContext<'a> { .map(|arg| *arg.clone()) .collect(); - new_f_sig = new_f_type_inner.to_type_signature(); + new_f_sig = new_f_type_inner.clone(); *new_f_type_inner.ret.clone() } else { new_f_sig = sig.clone(); - sig.ret.clone() + *sig.ret }; // Fix the current sig if some types were still unknown @@ -256,7 +295,7 @@ impl<'a> ConstraintContext<'a> { fc.args.iter().enumerate().for_each(|(i, arg)| { if let Some(_reso_id) = self.resolve_rec(&arg.get_hir_id()) { self.envs - .set_type(&arg.get_hir_id().clone(), new_f_arg_types.get(i).unwrap()); + .set_type(&arg.get_hir_id(), new_f_arg_types.get(i).unwrap()); } }); } @@ -275,12 +314,11 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { // walk_function_decl(self, f); walk_list!(self, visit_argument_decl, &f.arguments); - self.visit_fn_body(&self.hir.get_body(&f.body_id).unwrap()); + self.visit_fn_body(self.hir.get_body(&f.body_id).unwrap()); self.envs.set_type( &f.hir_id, &Type::FuncType(FuncType::new( - f.name.name.clone(), f.arguments .iter() .map(|arg| self.envs.get_type(&arg.get_hir_id()).unwrap()) @@ -288,9 +326,9 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { .collect(), self.envs .get_type(&self.hir.get_body(&f.body_id).unwrap().get_hir_id()) - .or(Some(&Type::forall("z"))) - .unwrap() - .clone(), + .cloned() + .or_else(|| Some(Type::forall("z"))) + .unwrap(), )), ); @@ -303,7 +341,9 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { } fn visit_prototype(&mut self, p: &Prototype) { - self.envs.set_type(&p.hir_id, &p.signature.to_func_type()); + if p.signature.is_solved() { + self.envs.set_type(&p.hir_id, &p.signature.to_type()); + } self.tmp_resolutions .get_mut(&self.envs.get_current_fn().0) @@ -322,14 +362,14 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { s.defs.iter().for_each(|p| { self.envs - .set_type(&p.hir_id, &struct_t.defs.get(&p.name.name).unwrap()); + .set_type(&p.hir_id, struct_t.defs.get(&p.name.name).unwrap()); }); } fn visit_struct_ctor(&mut self, s: &StructCtor) { let s_decl = self.hir.structs.get(&s.name.get_name()).unwrap(); - self.visit_struct_decl(&s_decl); + self.visit_struct_decl(s_decl); let t = s_decl.to_type(); @@ -337,16 +377,18 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { let struct_t = t.into_struct_type(); - s.defs.iter().for_each(|(k, p)| { + walk_map!(self, visit_expression, &s.defs); + + s.defs.iter().for_each(|(k, expr)| { self.envs - .set_type(&p.get_hir_id(), &struct_t.defs.get(&k.name).unwrap()); + .set_type(&expr.get_hir_id(), struct_t.defs.get(&k.name).unwrap()); }); } fn visit_body(&mut self, body: &'a Body) { body.stmts .iter() - .for_each(|stmt| self.visit_statement(&stmt)); + .for_each(|stmt| self.visit_statement(stmt)); } fn visit_assign(&mut self, assign: &'a Assign) { @@ -380,30 +422,30 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { fn visit_expression(&mut self, expr: &'a Expression) { match &*expr.kind { - ExpressionKind::Lit(lit) => self.visit_literal(&lit), - ExpressionKind::Return(expr) => self.visit_expression(&expr), - ExpressionKind::Identifier(id) => self.visit_identifier_path(&id), - ExpressionKind::StructCtor(s) => self.visit_struct_ctor(&s), + ExpressionKind::Lit(lit) => self.visit_literal(lit), + ExpressionKind::Return(expr) => self.visit_expression(expr), + ExpressionKind::Identifier(id) => self.visit_identifier_path(id), + ExpressionKind::StructCtor(s) => self.visit_struct_ctor(s), ExpressionKind::NativeOperation(op, left, right) => { - self.visit_identifier(&left); - self.visit_identifier(&right); + self.visit_identifier(left); + self.visit_identifier(right); //FIXME: Put this in another func let arg_t = match op.kind { NativeOperatorKind::IEq - | NativeOperatorKind::IGT - | NativeOperatorKind::IGE - | NativeOperatorKind::ILT - | NativeOperatorKind::ILE + | NativeOperatorKind::Igt + | NativeOperatorKind::Ige + | NativeOperatorKind::Ilt + | NativeOperatorKind::Ile | NativeOperatorKind::IAdd | NativeOperatorKind::ISub | NativeOperatorKind::IDiv | NativeOperatorKind::IMul => PrimitiveType::Int64, NativeOperatorKind::FEq - | NativeOperatorKind::FGT - | NativeOperatorKind::FGE - | NativeOperatorKind::FLT - | NativeOperatorKind::FLE + | NativeOperatorKind::Fgt + | NativeOperatorKind::Fge + | NativeOperatorKind::Flt + | NativeOperatorKind::Fle | NativeOperatorKind::FAdd | NativeOperatorKind::FSub | NativeOperatorKind::FDiv @@ -416,14 +458,14 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { self.envs .set_type(&right.hir_id.clone(), &Type::Primitive(arg_t)); - self.visit_native_operator(&op); + self.visit_native_operator(op); } ExpressionKind::FunctionCall(fc) => { self.visit_expression(&fc.op); walk_list!(self, visit_expression, &fc.args); - self.setup_call(&fc, &fc.op.get_hir_id()); + self.setup_call(fc, &fc.op.get_hir_id()); } ExpressionKind::Indice(i) => { self.visit_expression(&i.op); @@ -439,17 +481,18 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { Type::Primitive(PrimitiveType::Int64) => { if let ExpressionKind::Lit(literal) = &*i.value.kind { if literal.as_number() >= size as i64 { - self.envs.diagnostics.push_error( - Diagnostic::new_out_of_bounds( - self.envs - .spans - .get(&i.value.get_hir_id()) - .unwrap() - .clone(), - i.value.as_literal().as_number() as u64, - size as u64, - ), - ) + // Deactivated for now + // self.envs.diagnostics.push_error( + // Diagnostic::new_out_of_bounds( + // self.envs + // .spans + // .get(&i.value.get_hir_id()) + // .unwrap() + // .clone(), + // i.value.as_literal().as_number() as u64, + // size as u64, + // ), + // ) } } } @@ -484,10 +527,10 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { match &self.envs.get_type(&d.op.get_hir_id()).unwrap().clone() { t @ Type::Struct(struct_t) => { - self.envs.set_type(&d.op.get_hir_id(), &t); + self.envs.set_type(&d.op.get_hir_id(), t); self.envs - .set_type(&d.get_hir_id(), &struct_t.defs.get(&d.value.name).unwrap()); + .set_type(&d.get_hir_id(), struct_t.defs.get(&d.value.name).unwrap()); } other => { let value_t = self.envs.get_type(&d.value.get_hir_id()).unwrap().clone(); @@ -544,7 +587,7 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { } fn visit_identifier_path(&mut self, id: &'a IdentifierPath) { - self.visit_identifier(&id.path.iter().last().unwrap()); + self.visit_identifier(id.path.iter().last().unwrap()); } fn visit_identifier(&mut self, id: &Identifier) { @@ -561,15 +604,15 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { fn visit_native_operator(&mut self, op: &NativeOperator) { let t = match op.kind { NativeOperatorKind::IEq - | NativeOperatorKind::IGT - | NativeOperatorKind::IGE - | NativeOperatorKind::ILT - | NativeOperatorKind::ILE + | NativeOperatorKind::Igt + | NativeOperatorKind::Ige + | NativeOperatorKind::Ilt + | NativeOperatorKind::Ile | NativeOperatorKind::FEq - | NativeOperatorKind::FGT - | NativeOperatorKind::FGE - | NativeOperatorKind::FLT - | NativeOperatorKind::FLE + | NativeOperatorKind::Fgt + | NativeOperatorKind::Fge + | NativeOperatorKind::Flt + | NativeOperatorKind::Fle | NativeOperatorKind::BEq => PrimitiveType::Bool, NativeOperatorKind::IAdd | NativeOperatorKind::ISub @@ -585,14 +628,14 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { } } -pub fn solve<'a>(root: &mut Root) -> (BTreeMap>, Diagnostics) { +pub fn solve(root: &mut Root) -> (BTreeMap>, Diagnostics) { let diagnostics = Diagnostics::default(); let infer_state = Envs::new(diagnostics, root.get_hir_spans()); - let mut constraint_ctx = ConstraintContext::new(infer_state, &root); + let mut constraint_ctx = ConstraintContext::new(infer_state, root); - constraint_ctx.constraint(&root); + constraint_ctx.constraint(root); let tmp_resolutions = constraint_ctx.tmp_resolutions.clone(); diff --git a/src/lib/infer/constraint2.rs b/src/lib/infer/constraint2.rs deleted file mode 100644 index 24e4cfd3..00000000 --- a/src/lib/infer/constraint2.rs +++ /dev/null @@ -1,388 +0,0 @@ -use std::collections::HashMap; - -use crate::{ - ast::{FuncType, PrimitiveType, Type, TypeSignature}, - diagnostics::Diagnostics, - hir::visit::*, - hir::*, - walk_list, walk_map, Envs, -}; - -#[derive(Debug)] -struct ConstraintContext<'a> { - hir: &'a Root, - envs: Envs, -} - -impl<'a> ConstraintContext<'a> { - pub fn new(envs: Envs, hir: &'a Root) -> Self { - Self { envs, hir } - } - - pub fn constraint(&mut self, root: &'a Root) { - let entry_point = root.get_function_by_name("main").unwrap(); - - self.envs.set_current_fn(( - entry_point.hir_id.clone(), - TypeSignature::default().with_ret(Type::int64()), - )); - - self.visit_function_decl(&entry_point); - } - - pub fn get_envs(self) -> Envs { - self.envs - } -} - -impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { - fn visit_root(&mut self, _r: &'a Root) {} - fn visit_top_level(&mut self, _t: &'a TopLevel) {} - fn visit_trait(&mut self, _t: &'a Trait) {} - - fn visit_function_decl(&mut self, f: &'a FunctionDecl) { - self.envs.apply_args_type(f); - - walk_function_decl(self, f); - - self.visit_fn_body(&self.hir.get_body(&f.body_id).unwrap()); - - // RET TO CHECK - self.envs.set_type( - &f.hir_id, - &Type::FuncType(FuncType::new( - f.name.name.clone(), - f.arguments - .iter() - .map(|arg| self.envs.get_type(&arg.get_hir_id()).unwrap()) - .cloned() - .collect(), - self.envs - .get_type(&self.hir.get_body(&f.body_id).unwrap().get_hir_id()) - .unwrap() - .clone(), - )), - ); - - self.envs.set_type_eq(&f.name.hir_id, &f.hir_id); - } - - fn visit_body(&mut self, body: &'a Body) { - body.stmts - .iter() - .for_each(|stmt| self.visit_statement(&stmt)); - } - - fn visit_assign(&mut self, assign: &'a Assign) { - self.visit_identifier(&assign.name); - self.visit_expression(&assign.value); - - self.envs - .set_type_eq(&assign.name.get_hir_id(), &assign.value.get_hir_id()); - } - - fn visit_if(&mut self, r#if: &'a If) { - self.visit_expression(&r#if.predicat); - - self.visit_body(&r#if.body); - - // self.state.add_constraint(Constraint::Eq( - // self.state - // .get_type_id(r#if.body.get_terminal_hir_id()) - // .unwrap(), - // self.state.get_type_id(r#if.hir_id.clone()).unwrap(), - // )); - - if let Some(e) = &r#if.else_ { - match &**e { - Else::Body(b) => { - // self.state.add_constraint(Constraint::Eq( - // self.state - // .get_type_id(r#if.body.get_terminal_hir_id()) - // .unwrap(), - // self.state.get_type_id(b.get_terminal_hir_id()).unwrap(), - // )); - - self.visit_body(b); - } - Else::If(i) => { - self.visit_if(i); - } - } - } - } - - fn visit_expression(&mut self, expr: &'a Expression) { - match &*expr.kind { - ExpressionKind::Lit(lit) => self.visit_literal(&lit), - ExpressionKind::Return(expr) => self.visit_expression(&expr), - ExpressionKind::Identifier(id) => self.visit_identifier_path(&id), - ExpressionKind::NativeOperation(op, left, right) => { - self.visit_identifier(&left); - self.visit_identifier(&right); - - //FIXME - let arg_t = match op.kind { - NativeOperatorKind::IEq - | NativeOperatorKind::IGT - | NativeOperatorKind::IGE - | NativeOperatorKind::ILT - | NativeOperatorKind::ILE - | NativeOperatorKind::IAdd - | NativeOperatorKind::ISub - | NativeOperatorKind::IDiv - | NativeOperatorKind::IMul => PrimitiveType::Int64, - NativeOperatorKind::FEq - | NativeOperatorKind::FGT - | NativeOperatorKind::FGE - | NativeOperatorKind::FLT - | NativeOperatorKind::FLE - | NativeOperatorKind::FAdd - | NativeOperatorKind::FSub - | NativeOperatorKind::FDiv - | NativeOperatorKind::FMul => PrimitiveType::Float64, - NativeOperatorKind::BEq => PrimitiveType::Bool, - }; - - self.envs - .set_type(&left.hir_id.clone(), &Type::Primitive(arg_t.clone())); - self.envs - .set_type(&right.hir_id.clone(), &Type::Primitive(arg_t)); - - self.visit_native_operator(&op); - } - ExpressionKind::FunctionCall(fc) => { - self.visit_expression(&fc.op); - - walk_list!(self, visit_expression, &fc.args); - let op_hir_id = fc.op.get_terminal_hir_id(); - - // self.state.add_constraint(Constraint::Callable( - // self.state.get_type_id(fc.op.get_terminal_hir_id()).unwrap(), - // self.state.get_type_id(fc.get_hir_id()).unwrap(), - // )); - - if let Some(top_id) = self.hir.resolutions.get_recur(&op_hir_id) { - if let Some(reso) = self.hir.arena.get(&top_id) { - match reso { - HirNode::Prototype(p) => { - // let sig_ret_t_id = self - // .state - // .get_or_create_type_id_by_type(&p.signature.ret) - // .unwrap(); - - // let constraint = Constraint::Callable( - // self.state.get_type_id(fc.op.get_terminal_hir_id()).unwrap(), - // sig_ret_t_id.clone(), - // ); - - // self.state.add_constraint(Constraint::Eq( - // self.state.get_type_id(fc.hir_id.clone()).unwrap(), - // sig_ret_t_id.clone(), - // )); - - // for (i, arg) in p.signature.args.iter().enumerate() { - // let constraint = Constraint::Eq( - // self.state.get_or_create_type_id_by_type(arg).unwrap(), - // self.state - // .get_type_id( - // fc.args.get(i).unwrap().get_terminal_hir_id(), - // ) - // .unwrap(), - // ); - - // self.state.add_constraint(constraint); - // } - - // self.state.add_constraint(constraint); - } - HirNode::FunctionDecl(f) => { - // let sig = f.signature.with_partial_types(self.state.); - let sig = f.signature.apply_partial_types( - &f.arguments - .iter() - .enumerate() - .into_iter() - .map(|(i, arg)| { - self.envs - .get_type(&fc.args.get(i).unwrap().get_hir_id()) - .cloned() - }) - .collect(), - None, - ); - - let old_f = self.envs.get_current_fn(); - - self.envs.set_current_fn((top_id, sig.clone())); - - self.visit_function_decl(f); - - let new_f_type = self.envs.get_type(&f.hir_id).unwrap().clone(); - self.envs.set_current_fn(old_f); - - self.envs.set_type(&fc.get_hir_id(), &sig.ret); - self.envs.set_type(&fc.op.get_hir_id(), &new_f_type); - - // let body = self.hir.get_body(f.body_id.clone()).unwrap(); - - // let body_hir_id = body.get_terminal_hir_id(); - // let body_type_id = - // self.state.get_type_id(body_hir_id.clone()).unwrap(); - - // self.state.add_constraint(Constraint::Eq( - // self.state.get_type_id(fc.hir_id.clone()).unwrap(), - // body_type_id, - // )); - - // self.state.add_constraint(Constraint::Callable( - // self.state.get_type_id(fc.op.get_terminal_hir_id()).unwrap(), - // body_type_id, - // )); - - // for (i, arg) in f.arguments.iter().enumerate() { - // self.state.add_constraint(Constraint::Eq( - // self.state.get_type_id(arg.name.hir_id.clone()).unwrap(), - // self.state - // .get_type_id( - // fc.args.get(i).unwrap().get_terminal_hir_id(), - // ) - // .unwrap(), - // )); - // } - } - _ => (), - } - } else { - panic!("NO ARENA ITEM FOR HIR={:?}", top_id); - } - } else { - panic!("No reso"); - } - } - } - } - - // fn visit_function_decl(&mut self, f: &FunctionDecl) { - // let args = f - // .arguments - // .iter() - // .map(|arg| self.state.get_type_id(arg.name.hir_id.clone()).unwrap()) - // .collect(); - - // if let Some(body) = self.hir.get_body(f.body_id.clone()) { - // let body_hir_id = body.get_terminal_hir_id(); - // let body_type_id = self.state.get_type_id(body_hir_id.clone()).unwrap(); - - // self.state.add_constraint(Constraint::Callable( - // self.state.get_type_id(f.hir_id.clone()).unwrap(), - // body_type_id, - // )); - - // self.state.add_constraint(Constraint::Eq( - // self.state.get_type_id(f.hir_id.clone()).unwrap(), - // self.state.get_type_id(f.name.hir_id.clone()).unwrap(), - // )); - - // self.state.solve_type( - // f.hir_id.clone(), - // Type::FuncType(FuncType::new(f.get_name().name, args, body_type_id)), - // ); - // } - // } - fn visit_literal(&mut self, lit: &Literal) { - let t = match &lit.kind { - LiteralKind::Number(_n) => Type::Primitive(PrimitiveType::Int64), - LiteralKind::Float(_f) => Type::Primitive(PrimitiveType::Float64), - LiteralKind::String(s) => Type::Primitive(PrimitiveType::String(s.len())), - LiteralKind::Bool(_b) => Type::Primitive(PrimitiveType::Bool), - }; - - self.envs.set_type(&lit.hir_id, &t); - } - - fn visit_prototype(&mut self, p: &Prototype) { - // let args = p - // .signature - // .args - // .iter() - // .map(|t| self.state.get_or_create_type_id_by_type(t).unwrap()) - // .collect(); - - // let f = Type::FuncType(FuncType::new( - // (*p.name).clone(), - // args, - // self.state - // .get_or_create_type_id_by_type(&p.signature.ret) - // .unwrap(), - // )); - - // self.state.solve_type(p.hir_id.clone(), f); - } - - fn visit_identifier_path(&mut self, id: &'a IdentifierPath) { - self.visit_identifier(&id.path.iter().last().unwrap()); - } - - fn visit_identifier(&mut self, id: &Identifier) { - if let Some(reso) = self.hir.resolutions.get(&id.hir_id) { - if self.envs.get_type(&reso).is_some() { - self.envs.set_type_eq(&id.get_hir_id(), &reso); - } else { - error!( - "UNKNOWN IDENTIFIER RESOLUTION TYPE ID {:?}, reso {:?}", - id, reso - ); - } - - // self.state.add_constraint(Constraint::Eq( - // self.state.get_type_id(id.hir_id.clone()).unwrap(), - // self.state.get_type_id(reso.clone()).unwrap(), - // )); - } else { - error!("No identifier resolution {:?}", id); - } - } -} - -pub fn solve<'a>(root: &mut Root) -> Diagnostics { - let mut diagnostics = Diagnostics::default(); - - let infer_state = Envs::default(); - - // let mut annotate_ctx = AnnotateContext::new(infer_state, root.trait_methods.clone()); - // annotate_ctx.annotate(&root); - - let mut constraint_ctx = ConstraintContext::new(infer_state, &root); - - constraint_ctx.constraint(&root); - - let mut envs = constraint_ctx.get_envs(); - - root.type_envs = envs; - - // if let Err(diags) = infer_state.solve() { - // for diag in diags { - // diagnostics.push_error(diag.clone()); - // } - // } - - // let node_type_ids = infer_state.get_node_types(); - - // // here we consume infer_state - // let (types, diags) = infer_state.get_types(); - - // root.node_types = node_type_ids - // .iter() - // .map(|(hir_id, t_id)| (hir_id.clone(), types.get(t_id).unwrap().clone())) - // .collect(); - - // root.node_type_ids = node_type_ids; - // root.types = types; - - // for diag in diags { - // diagnostics.push_error(diag.clone()); - // } - - diagnostics -} diff --git a/src/lib/infer/mod.rs b/src/lib/infer/mod.rs index a0346c93..d67874d4 100644 --- a/src/lib/infer/mod.rs +++ b/src/lib/infer/mod.rs @@ -1,6 +1,6 @@ mod constraint; mod mangle; -mod monomorphizer; +mod monomorphize; mod state; pub use self::state::*; @@ -13,13 +13,12 @@ pub fn infer( config: &Config, ) -> Result { let (tmp_resolutions, diags) = constraint::solve(root); - // super::hir::hir_printer::print(&*root); parsing_ctx.diagnostics.append(diags); parsing_ctx.return_if_error()?; - let mut new_root = monomorphizer::monomophize(root, tmp_resolutions); + let mut new_root = monomorphize::monomophize(root, tmp_resolutions); mangle::mangle(&mut new_root); diff --git a/src/lib/infer/monomorphizer/mod.rs b/src/lib/infer/monomorphize/mod.rs similarity index 100% rename from src/lib/infer/monomorphizer/mod.rs rename to src/lib/infer/monomorphize/mod.rs diff --git a/src/lib/infer/monomorphizer/monomorphizer.rs b/src/lib/infer/monomorphize/monomorphizer.rs similarity index 79% rename from src/lib/infer/monomorphizer/monomorphizer.rs rename to src/lib/infer/monomorphize/monomorphizer.rs index c23c772f..ac668109 100644 --- a/src/lib/infer/monomorphizer/monomorphizer.rs +++ b/src/lib/infer/monomorphize/monomorphizer.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ - ast::{resolve::ResolutionMap, Type, TypeSignature}, + ast::{resolve::ResolutionMap, FuncType, Type}, hir::visit_mut::*, hir::*, Env, @@ -14,13 +14,13 @@ pub struct Monomorphizer<'a> { pub new_resolutions: ResolutionMap, pub old_ordered_resolutions: HashMap>, // fn_call => [fn_decl] pub body_arguments: BTreeMap>, - pub generated_fn_hir_id: HashMap<(HirId, TypeSignature), HirId>, // (Old_fn_id, target_sig) => generated fn hir_id + pub generated_fn_hir_id: HashMap<(HirId, FuncType), HirId>, // (Old_fn_id, target_sig) => generated fn hir_id pub tmp_resolutions: BTreeMap>, pub structs: HashMap, } impl<'a> Monomorphizer<'a> { - pub fn get_fn_envs_pairs(&self) -> Vec<(HirId, HashMap)> { + pub fn get_fn_envs_pairs(&self) -> Vec<(HirId, HashMap)> { self.root .type_envs .get_inner() @@ -35,7 +35,7 @@ impl<'a> Monomorphizer<'a> { .top_levels .iter() .filter(|top| match &top.kind { - TopLevelKind::Prototype(_) => true, + TopLevelKind::Prototype(p) => p.signature.is_solved(), _ => false, }) .cloned() @@ -43,15 +43,19 @@ impl<'a> Monomorphizer<'a> { for top in &prototypes { if let TopLevelKind::Prototype(p) = &top.kind { + let f_type = p.signature.clone(); + self.root .node_types - .insert(p.hir_id.clone(), p.signature.to_func_type()); + .insert(p.hir_id.clone(), Type::FuncType(f_type.clone())); self.root .node_types - .insert(p.name.hir_id.clone(), p.signature.to_func_type()); + .insert(p.name.hir_id.clone(), Type::FuncType(f_type.clone())); } } + // The collect here is needed as we NEED the generated_fn_hir_id.insert() side effect + #[allow(clippy::needless_collect)] let fresh_top_levels_flat = self .get_fn_envs_pairs() .into_iter() @@ -70,19 +74,22 @@ impl<'a> Monomorphizer<'a> { .type_envs .set_current_fn((proto_id.clone(), sig.clone())); + new_f.signature = sig.clone(); + self.visit_function_decl(&mut new_f); self.generated_fn_hir_id .insert((proto_id.clone(), sig.clone()), new_f.hir_id.clone()); self.trans_resolutions - .insert(old_f.hir_id.clone(), new_f.hir_id.clone()); + .insert(old_f.hir_id, new_f.hir_id.clone()); Some((proto_id.clone(), new_f, sig)) } HirNode::Prototype(p) => { self.generated_fn_hir_id - .insert((proto_id.clone(), sig.clone()), p.hir_id.clone()); + .insert((proto_id.clone(), sig), p.hir_id.clone()); + None } _ => { @@ -95,38 +102,35 @@ impl<'a> Monomorphizer<'a> { .flatten() .collect::>(); - let fresh_top_levels = fresh_top_levels_flat - .into_iter() - .map(|(proto_id, mut new_f, sig)| { - self.root - .type_envs - .set_current_fn((proto_id.clone(), sig.clone())); + let fresh_top_levels = + fresh_top_levels_flat + .into_iter() + .map(|(proto_id, mut new_f, sig)| { + self.root.type_envs.set_current_fn((proto_id, sig)); - let fn_body = self.root.bodies.get(&new_f.body_id).unwrap(); + let fn_body = self.root.bodies.get(&new_f.body_id).unwrap(); - let mut new_fn_body = fn_body.clone(); + let mut new_fn_body = fn_body.clone(); - new_f.body_id = self.root.hir_map.next_body_id(); - new_fn_body.id = new_f.body_id.clone(); + new_f.body_id = self.root.hir_map.next_body_id(); + new_fn_body.id = new_f.body_id.clone(); - self.body_arguments - .insert(new_f.body_id.clone(), new_f.arguments.clone()); + self.body_arguments + .insert(new_f.body_id.clone(), new_f.arguments.clone()); - self.visit_fn_body(&mut new_fn_body); + self.visit_fn_body(&mut new_fn_body); - new_fn_body.name = new_f.name.clone(); - new_fn_body.fn_id = new_f.hir_id.clone(); + new_fn_body.name = new_f.name.clone(); + new_fn_body.fn_id = new_f.hir_id.clone(); - new_f.arguments = self.body_arguments.get(&new_f.body_id).unwrap().clone(); + new_f.arguments = self.body_arguments.get(&new_f.body_id).unwrap().clone(); - (new_f, new_fn_body) - }) - .collect::>(); + (new_f, new_fn_body) + }); let mut new_root = Root::default(); let (tops, bodies) = fresh_top_levels - .into_iter() .map(|(f, body)| { let top = TopLevel { kind: TopLevelKind::Function(f), @@ -152,13 +156,10 @@ impl<'a> Monomorphizer<'a> { } pub fn duplicate_hir_id(&mut self, old_hir_id: &HirId) -> HirId { - let new_hir_id = self - .root + self.root .hir_map .duplicate_hir_mapping(old_hir_id.clone()) - .unwrap(); - - new_hir_id + .unwrap() } pub fn resolve(&self, id: &HirId) -> Option { @@ -192,6 +193,8 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { } } + fn visit_prototype(&mut self, _p: &'a mut Prototype) {} + fn visit_function_decl(&mut self, f: &'a mut FunctionDecl) { let old_f_hir_id = f.hir_id.clone(); @@ -230,20 +233,13 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { .iter() .filter(|(pointer, _pointee)| *pointer == old_pointer_id) .for_each(|(existing_pointer, existing_pointee)| { - self.trans_resolutions - .get(existing_pointer) - .map(|new_pointer_id| { - self.trans_resolutions.get(existing_pointee).map( - |new_pointee_id| { - // println!( - // "NEW RESO FRON TRANS {:?} {:?}", - // new_pointer_id, new_pointee_id - // ); - self.new_resolutions - .insert(new_pointer_id.clone(), new_pointee_id.clone()); - }, - ); - }); + if let Some(new_pointer_id) = self.trans_resolutions.get(existing_pointer) { + if let Some(new_pointee_id) = + self.trans_resolutions.get(existing_pointee) + { + self.new_resolutions.insert(new_pointer_id, new_pointee_id); + } + } }); }); @@ -253,7 +249,7 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { fn visit_if(&mut self, r#if: &'a mut If) { let old_if_id = r#if.hir_id.clone(); - r#if.hir_id = self.duplicate_hir_id(&mut r#if.hir_id); + r#if.hir_id = self.duplicate_hir_id(&r#if.hir_id); if let Some(t) = self.root.type_envs.get_type(&old_if_id) { self.root.node_types.insert(r#if.hir_id.clone(), t.clone()); @@ -302,16 +298,17 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { .unwrap() { HirNode::FunctionDecl(_) => { - self.new_resolutions.insert( - fc.op.get_hir_id(), - self.generated_fn_hir_id - .get(&( - self.resolve_rec(&old_fc_op).unwrap(), - fc.to_type_signature(&self.root.node_types), - )) - .unwrap() - .clone(), - ); + // println!("ENV {:#?}", self.root.type_envs); + if let Some(generated_fn) = self.generated_fn_hir_id.get(&( + self.resolve_rec(&old_fc_op).unwrap(), + fc.to_func_type(&self.root.node_types), + )) { + self.new_resolutions + .insert(fc.op.get_hir_id(), generated_fn.clone()); + } else { + // self. + panic!("BUG: Cannot find function from signature"); + } self.trans_resolutions.remove(&old_fc_op); } @@ -320,10 +317,7 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { if let Type::FuncType(f_type) = f_type { // Traits - if let Some(f) = self - .root - .get_trait_method((*p.name).clone(), &f_type.to_type_signature()) - { + if let Some(f) = self.root.get_trait_method((*p.name).clone(), f_type) { if let Some(trans_res) = self.trans_resolutions.get(&f.hir_id) { self.new_resolutions.insert(fc.op.get_hir_id(), trans_res); } else { @@ -345,7 +339,7 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { } } - // self.trans_resolutions.remove(&old_fc_op); + self.trans_resolutions.remove(&old_fc_op); } _ => { // FIXME: This may be bad @@ -356,11 +350,11 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { for (i, arg) in fc.args.iter().enumerate() { if let Type::FuncType(f) = self.root.node_types.get(&arg.get_hir_id()).unwrap() { - if let Some(reso) = self.resolve(&old_fc_args.get(i).unwrap()) { + if let Some(reso) = self.resolve(old_fc_args.get(i).unwrap()) { self.new_resolutions.insert( arg.get_hir_id(), self.generated_fn_hir_id - .get(&(reso, f.to_type_signature())) + .get(&(reso, f.clone())) .unwrap() .clone(), ); @@ -368,7 +362,7 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { println!("NO RESO FOR {:#?}", arg.get_hir_id()) } - // self.trans_resolutions.remove(&old_fc_args.get(i).unwrap()); + self.trans_resolutions.remove(&old_fc_args.get(i).unwrap()); } } } @@ -427,7 +421,7 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { .unwrap() .clone(); self.root.node_types.insert(p.get_hir_id(), t.clone()); - self.root.node_types.insert(p.name.get_hir_id(), t.clone()); + self.root.node_types.insert(p.name.get_hir_id(), t); }); self.structs.insert(s.name.get_name(), s.clone()); diff --git a/src/lib/infer/state.rs b/src/lib/infer/state.rs index 14c08be5..b817f1a6 100644 --- a/src/lib/infer/state.rs +++ b/src/lib/infer/state.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ - ast::{Type, TypeSignature}, + ast::{FuncType, Type}, diagnostics::{Diagnostic, Diagnostics}, hir::*, parser::Span, @@ -15,8 +15,8 @@ pub type Env = BTreeMap; #[derive(Debug, Default, Clone)] pub struct Envs { - fns: BTreeMap>, - current_fn: (HirId, TypeSignature), + fns: BTreeMap>, + current_fn: (HirId, FuncType), pub spans: HashMap, pub diagnostics: Diagnostics, } @@ -41,7 +41,7 @@ impl Envs { .and_then(|map| map.get(&self.current_fn.1)) } - pub fn set_current_fn(&mut self, f: (HirId, TypeSignature)) -> bool { + pub fn set_current_fn(&mut self, f: (HirId, FuncType)) -> bool { // if !f.1.are_args_solved() { // self.diagnostics.push_error(Diagnostic::new_unresolved_type( // self.spans.get(&f.0).unwrap().clone(), @@ -53,16 +53,16 @@ impl Envs { self.fns .entry(f.0.clone()) - .or_insert_with(|| HashMap::new()) + .or_insert_with(HashMap::new) .entry(f.1.clone()) - .or_insert_with(|| Env::default()); + .or_insert_with(Env::default); self.current_fn = f; - return true; + true } - pub fn get_current_fn(&self) -> (HirId, TypeSignature) { + pub fn get_current_fn(&self) -> (HirId, FuncType) { self.current_fn.clone() } @@ -79,25 +79,27 @@ impl Envs { .insert(dest.clone(), src.clone()); match (src, previous.clone()) { - (Type::FuncType(src_f), Some(Type::FuncType(prev_f))) if *src_f != prev_f => { - if prev_f.to_type_signature().is_solved() && src_f.to_type_signature().is_solved() { + (Type::FuncType(src_f), Some(Type::FuncType(prev_f))) if !src_f.eq(&prev_f) => { + if prev_f.is_solved() && src_f.is_solved() { self.diagnostics.push_error(Diagnostic::new_type_conflict( self.spans.get(dest).unwrap().clone(), src.clone(), previous.clone().unwrap(), src.clone(), - previous.clone().unwrap(), + previous.unwrap(), )); } } - (src, Some(previous)) if *src != previous => { - self.diagnostics.push_error(Diagnostic::new_type_conflict( - self.spans.get(dest).unwrap().clone(), - src.clone(), - previous.clone(), - src.clone(), - previous, - )); + (src, Some(previous)) if !src.eq(&previous) => { + if previous.is_solved() && src.is_solved() { + self.diagnostics.push_error(Diagnostic::new_type_conflict( + self.spans.get(dest).unwrap().clone(), + src.clone(), + previous.clone(), + src.clone(), + previous, + )); + } } _ => (), } @@ -112,38 +114,31 @@ impl Envs { } pub fn apply_args_type(&mut self, f: &FunctionDecl) { - let eq_types = f - .arguments - .iter() + f.arguments + .clone() + .into_iter() .enumerate() - .map(|(i, arg)| { - ( - arg.get_hir_id(), - self.current_fn.1.args.get(i).unwrap().clone(), + .for_each(|(i, arg)| { + self.set_type( + &arg.get_hir_id(), + &self.current_fn.1.arguments.get(i).unwrap().clone(), ) - }) - .collect::>(); - - eq_types.into_iter().for_each(|(id, t)| { - self.set_type(&id, &t); - }); + }); } - pub fn get_fn_types(&self, f: &HirId) -> Option<&HashMap> { + pub fn get_fn_types(&self, f: &HirId) -> Option<&HashMap> { self.fns.get(f) } - pub fn get_inner(&self) -> &BTreeMap> { + pub fn get_inner(&self) -> &BTreeMap> { &self.fns } pub fn add_empty(&mut self, hir_id: &HirId) { - self.fns - .entry(hir_id.clone()) - .or_insert_with(|| HashMap::new()); + self.fns.entry(hir_id.clone()).or_insert_with(HashMap::new); } - pub fn amend_current_sig(&mut self, new_sig: &TypeSignature) { + pub fn amend_current_sig(&mut self, new_sig: &FuncType) { if self.current_fn.1 == *new_sig { return; } diff --git a/src/lib/parser/lexer.rs b/src/lib/parser/lexer.rs index 1a180737..909ecc36 100644 --- a/src/lib/parser/lexer.rs +++ b/src/lib/parser/lexer.rs @@ -13,11 +13,9 @@ bitflags! { macro_rules! closure_vec { ($($m:path),*,) => { { - let mut res = vec![]; - - $(res.push(Box::new($m as for<'r> fn(&'r mut Lexer<'a>) -> Option));)* - - res + vec![ + $(Box::new($m as for<'r> fn(&'r mut Lexer<'a>) -> Option),)* + ] } }; } @@ -53,7 +51,7 @@ impl<'a> Lexer<'a> { pub fn next(&mut self) -> Token { if self.end { - return self.new_token(TokenType::EOF, self.cur_idx, "".to_string()); + return self.new_token(TokenType::Eof, self.cur_idx, "".to_string()); } if let Some(t) = self.try_indent() { @@ -108,7 +106,7 @@ impl<'a> Lexer<'a> { } if self.cur_idx >= self.input.len() - 1 { - return self.new_token(TokenType::EOF, self.cur_idx, "".to_string()); + return self.new_token(TokenType::Eof, self.cur_idx, "".to_string()); } self.ctx @@ -119,7 +117,7 @@ impl<'a> Lexer<'a> { self.end = true; - self.new_token(TokenType::EOF, self.cur_idx, "".to_string()) + self.new_token(TokenType::Eof, self.cur_idx, "".to_string()) } fn has_separator(&self, token_len: usize, sep: Sep) -> bool { @@ -422,14 +420,12 @@ impl<'a> Lexer<'a> { if self .accepted_operator_chars .iter() - .find(|c| **c == self.last_char) - .is_some() + .any(|c| *c == self.last_char) { while self .accepted_operator_chars .iter() - .find(|c| **c == self.last_char) - .is_some() + .any(|c| *c == self.last_char) { identifier.push(self.last_char); @@ -453,7 +449,7 @@ impl<'a> Lexer<'a> { let mut res = None; let ops = vec![ "~IAdd", "~ISub", "~IMul", "~IDiv", "~FAdd", "~FSub", "~FMul", "~FDiv", "~IEq", - "~IGT", "~IGE", "~ILT", "~ILE", "~FEq", "~FGT", "~FGE", "~FLT", "~FLE", "~BEq", + "~Igt", "~Ige", "~Ilt", "~Ile", "~FEq", "~Fgt", "~Fge", "~Flt", "~Fle", "~BEq", ]; for op in ops { @@ -473,7 +469,7 @@ impl<'a> Lexer<'a> { fn try_end_of(&mut self) -> Option { if self.last_char == '\n' { let res = Some(Token { - t: TokenType::EOL, + t: TokenType::Eol, span: self.ctx.new_span(self.cur_idx, self.cur_idx), txt: "\n".to_string(), }); @@ -582,7 +578,7 @@ impl<'a> Lexer<'a> { res.push(next.clone()); - if next.t == TokenType::EOF { + if next.t == TokenType::Eof { break; } } diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index 898ddb84..8a5e5ea4 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -78,7 +78,7 @@ pub fn parse_mod(name: String, ctx: &mut ParsingCtx) -> Result { pub cur_tok_id: TokenId, save: Vec, pub block_indent: u8, - func_sigs: HashMap, + func_sigs: HashMap, pub struct_types: HashMap, } @@ -167,14 +167,14 @@ impl<'a> Parser<'a> { match self.tokens.get(self.cur_tok_id as usize + distance) { Some(a) => a.clone(), _ => Token { - t: TokenType::EOF, + t: TokenType::Eof, span: Span::new_placeholder(), txt: "".to_string(), }, } } - pub fn add_func_sig(&mut self, name: String, sig: TypeSignature) { + pub fn add_func_sig(&mut self, name: String, sig: FuncType) { self.func_sigs.insert(name, sig); } @@ -191,10 +191,10 @@ impl Parse for Root { .top_levels .iter() .find(|top| match &top.kind { - TopLevelKind::Function(f) => *f.name == "main".to_string(), + TopLevelKind::Function(f) => f.name.name == "main", _ => false, }) - .ok_or_else(|| Diagnostic::new_no_main())?; + .ok_or_else(Diagnostic::new_no_main)?; Ok(Root { spans: HashMap::new(), @@ -210,7 +210,7 @@ impl Parse for Mod { fn parse(ctx: &mut Parser) -> Result { let mut res = vec![]; - while TokenType::EOF != ctx.cur_tok().t { + while TokenType::Eof != ctx.cur_tok().t { match TopLevel::parse(ctx) { Ok(top) => res.push(top), Err(e) => { @@ -221,7 +221,7 @@ impl Parse for Mod { }; } - expect!(TokenType::EOF, ctx); + expect!(TokenType::Eof, ctx); Ok(Mod { tokens: ctx.tokens.clone(), @@ -315,7 +315,7 @@ impl Parse for TopLevel { } }; - while ctx.cur_tok().t == TokenType::EOL { + while ctx.cur_tok().t == TokenType::Eol { ctx.consume(); } @@ -338,22 +338,15 @@ impl Parse for StructDecl { let name = try_or_restore!(Type::parse(ctx), ctx); // TODO: resolve type here ? else it is infered as Trait(name) - // - ctx.consume(); // EOL + ctx.consume(); // Eol - loop { - if let TokenType::Indent(_) = ctx.cur_tok().t { - ctx.consume(); // indent - - let f = Prototype::parse(ctx)?; + while let TokenType::Indent(_) = ctx.cur_tok().t { + ctx.consume(); // indent - defs.push(f); + defs.push(Prototype::parse(ctx)?); - expect!(TokenType::EOL, ctx); - } else { - break; - } + expect!(TokenType::Eol, ctx); } ctx.save_pop(); @@ -379,26 +372,18 @@ impl Parse for Trait { let name = try_or_restore!(Type::parse(ctx), ctx); - while ctx.cur_tok().t != TokenType::EOL { + while ctx.cur_tok().t != TokenType::Eol { types.push(Type::parse(ctx)?); } - ctx.consume(); // EOL + ctx.consume(); // Eol - loop { - if let TokenType::Indent(_) = ctx.cur_tok().t { - ctx.consume(); // indent - - let f = Prototype::parse(ctx)?; + while let TokenType::Indent(_) = ctx.cur_tok().t { + ctx.consume(); // indent - // f.mangle(name.get_name()); + defs.push(Prototype::parse(ctx)?); - defs.push(f); - - expect!(TokenType::EOL, ctx); - } else { - break; - } + expect!(TokenType::Eol, ctx); } ctx.save_pop(); @@ -416,27 +401,22 @@ impl Parse for Impl { let name = try_or_restore!(Type::parse(ctx), ctx); - while ctx.cur_tok().t != TokenType::EOL { + while ctx.cur_tok().t != TokenType::Eol { types.push(Type::parse(ctx)?); } - ctx.consume(); // EOL + ctx.consume(); // Eol ctx.block_indent += 1; - loop { - if let TokenType::Indent(_) = ctx.cur_tok().t { - ctx.consume(); // indent - let f = FunctionDecl::parse(ctx)?; - // f.mangle(&types.iter().map(|t| t.get_name()).collect::>()); + while let TokenType::Indent(_) = ctx.cur_tok().t { + ctx.consume(); // indent - defs.push(f); + defs.push(FunctionDecl::parse(ctx)?); - expect!(TokenType::EOL, ctx); - } else { - break; - } + expect!(TokenType::Eol, ctx); } + ctx.block_indent -= 1; ctx.save_pop(); @@ -456,7 +436,7 @@ impl Parse for Prototype { expect_or_restore!(TokenType::DoubleSemiColon, ctx); - let signature = try_or_restore!(TypeSignature::parse(ctx), ctx); + let signature = try_or_restore!(FuncType::parse(ctx), ctx); ctx.save_pop(); @@ -506,7 +486,7 @@ impl Parse for FunctionDecl { Ok(FunctionDecl { name, - signature: TypeSignature::from_args_nb(arguments.len()), + signature: FuncType::from_args_nb(arguments.len()), arguments, body, identity: Identity::new(token_id, token.span), @@ -555,7 +535,7 @@ impl Parse for Body { fn parse(ctx: &mut Parser) -> Result { let mut multi = false; - if ctx.cur_tok().t == TokenType::EOL { + if ctx.cur_tok().t == TokenType::Eol { multi = true; ctx.block_indent += 1; @@ -567,8 +547,8 @@ impl Parse for Body { loop { ctx.save(); - if ctx.cur_tok().t == TokenType::EOL { - while ctx.cur_tok().t == TokenType::EOL { + if ctx.cur_tok().t == TokenType::Eol { + while ctx.cur_tok().t == TokenType::Eol { ctx.consume(); } } else { @@ -614,17 +594,15 @@ impl Parse for Statement { fn parse(ctx: &mut Parser) -> Result { let kind = if ctx.cur_tok().t == TokenType::If { match If::parse(ctx) { - Ok(expr) => StatementKind::If(expr), + Ok(expr) => StatementKind::If(Box::new(expr)), Err(_e) => error!("Expected if".to_string(), ctx), } + } else if let Ok(assign) = Assign::parse(ctx) { + StatementKind::Assign(Box::new(assign)) } else { - if let Ok(assign) = Assign::parse(ctx) { - StatementKind::Assign(assign) - } else { - match Expression::parse(ctx) { - Ok(expr) => StatementKind::Expression(expr), - Err(_e) => error!("Expected expression".to_string(), ctx), - } + match Expression::parse(ctx) { + Ok(expr) => StatementKind::Expression(Box::new(expr)), + Err(_e) => error!("Expected expression".to_string(), ctx), } }; @@ -688,8 +666,23 @@ impl Parse for Assign { expect_or_restore!(TokenType::Operator("=".to_string()), ctx); + let mut multi = false; + + if matches!(ctx.cur_tok().t, TokenType::Eol) { + ctx.consume(); // Eol + ctx.consume(); // Indent + + multi = true; + + ctx.block_indent += 1; + } + let value = try_or_restore!(Expression::parse(ctx), ctx); + if multi { + ctx.block_indent -= 1; + } + ctx.save_pop(); Ok(Assign { @@ -711,14 +704,14 @@ impl Parse for If { let expr = try_or_restore!(Expression::parse(ctx), ctx); - expect_or_restore!(TokenType::EOL, ctx); + expect_or_restore!(TokenType::Eol, ctx); expect_or_restore!(TokenType::Indent(ctx.block_indent), ctx); expect_or_restore!(TokenType::Then, ctx); let body = try_or_restore!(Body::parse(ctx), ctx); // in case of single line body - if ctx.cur_tok().t == TokenType::EOL { - expect!(TokenType::EOL, ctx); + if ctx.cur_tok().t == TokenType::Eol { + expect!(TokenType::Eol, ctx); // expect_or_restore!(TokenType::Indent(ctx.block_indent + 2), ctx); } @@ -815,33 +808,48 @@ impl Parse for StructCtor { let name = try_or_restore!(Type::parse(ctx), ctx); - ctx.consume(); // EOL + ctx.consume(); // Eol - let mut cur_indent = ctx.block_indent + 1; - loop { - if let TokenType::Indent(i) = ctx.cur_tok().t { - if i != cur_indent { - break; - } + ctx.block_indent += 1; + + while let TokenType::Indent(i) = ctx.cur_tok().t { + if i != ctx.block_indent { + break; + } - cur_indent = i; + ctx.consume(); // indent - ctx.consume(); // indent + let def_name = try_or_restore!(Identifier::parse(ctx), ctx); - let def_name = try_or_restore!(Identifier::parse(ctx), ctx); + expect_or_restore!(TokenType::SemiColon, ctx); - expect_or_restore!(TokenType::SemiColon, ctx); + let mut multi = false; - let expr = try_or_restore!(Expression::parse(ctx), ctx); + if matches!(ctx.cur_tok().t, TokenType::Eol) { + ctx.consume(); // Eol + ctx.consume(); // Indent - defs.insert(def_name, expr); + multi = true; - expect!(TokenType::EOL, ctx); - } else { - break; + ctx.block_indent += 1; + } + + let expr = try_or_restore!(Expression::parse(ctx), ctx); + + if multi { + ctx.block_indent -= 1; + } + + defs.insert(def_name, expr); + + if matches!(ctx.cur_tok().t, TokenType::Eol) { + ctx.consume(); } + // expect!(TokenType::Eol, ctx); } + ctx.block_indent -= 1; + ctx.save_pop(); Ok(StructCtor { @@ -966,7 +974,7 @@ impl Parse for SecondaryExpr { ctx.save_pop(); - return Ok(SecondaryExpr::Indice(expr)); + return Ok(SecondaryExpr::Indice(Box::new(expr))); } } else if TokenType::Dot == ctx.cur_tok().t { ctx.save(); @@ -978,10 +986,8 @@ impl Parse for SecondaryExpr { return Ok(SecondaryExpr::Dot(expr)); } - } else { - if let Ok(args) = Arguments::parse(ctx) { - return Ok(SecondaryExpr::Arguments(args)); - } + } else if let Ok(args) = Arguments::parse(ctx) { + return Ok(SecondaryExpr::Arguments(args)); } error!("Expected secondary".to_string(), ctx); @@ -1017,7 +1023,7 @@ impl Parse for LiteralKind { if let TokenType::Bool(b) = ctx.cur_tok().t { ctx.consume(); - let v = if b { true } else { false }; + let v = b; return Ok(LiteralKind::Bool(v)); } @@ -1057,7 +1063,7 @@ impl Parse for Array { } } } - return Ok(Array { values }); + Ok(Array { values }) } } @@ -1112,15 +1118,13 @@ impl Parse for Arguments { ctx.save(); // TODO: factorise this with a match! macro ? - if TokenType::OpenParens == ctx.cur_tok().t { - if TokenType::CloseParens == ctx.seek(1).t { - ctx.consume(); - ctx.consume(); + if TokenType::OpenParens == ctx.cur_tok().t && TokenType::CloseParens == ctx.seek(1).t { + ctx.consume(); + ctx.consume(); - ctx.save_pop(); + ctx.save_pop(); - return Ok(res); - } + return Ok(res); } loop { @@ -1169,15 +1173,15 @@ impl Parse for NativeOperator { "~FMul" => NativeOperatorKind::FMul, "~FDiv" => NativeOperatorKind::FDiv, "~IEq" => NativeOperatorKind::IEq, - "~IGT" => NativeOperatorKind::IGT, - "~IGE" => NativeOperatorKind::IGE, - "~ILT" => NativeOperatorKind::ILT, - "~ILE" => NativeOperatorKind::ILE, + "~Igt" => NativeOperatorKind::Igt, + "~Ige" => NativeOperatorKind::Ige, + "~Ilt" => NativeOperatorKind::Ilt, + "~Ile" => NativeOperatorKind::Ile, "~FEq" => NativeOperatorKind::FEq, - "~FGT" => NativeOperatorKind::FGT, - "~FGE" => NativeOperatorKind::FGE, - "~FLT" => NativeOperatorKind::FLT, - "~FLE" => NativeOperatorKind::FLE, + "~Fgt" => NativeOperatorKind::Fgt, + "~Fge" => NativeOperatorKind::Fge, + "~Flt" => NativeOperatorKind::Flt, + "~Fle" => NativeOperatorKind::Fle, "~BEq" => NativeOperatorKind::BEq, _ => error!("Unknown native operator".to_string(), ctx), }; @@ -1199,31 +1203,50 @@ impl Parse for Type { ctx.consume(); if let Some(prim) = PrimitiveType::from_name(&token.txt) { - return Ok(Type::Primitive(prim)); + Ok(Type::Primitive(prim)) } else { if let Some(s) = ctx.struct_types.get(&token.txt) { return Ok(s.to_type()); } - return Ok(Type::Trait(token.txt)); + Ok(Type::Trait(token.txt)) } - } else if token.txt.len() == 1 && token.txt.chars().nth(0).unwrap().is_lowercase() { + } else if token.txt.len() == 1 && token.txt.chars().next().unwrap().is_lowercase() { ctx.consume(); - return Ok(Type::ForAll(token.txt)); + Ok(Type::ForAll(token.txt)) + } else if TokenType::OpenArray == token.t { + ctx.consume(); + + let inner_t = Type::parse(ctx)?; + + // FIXME: FIXED ARRAY SIZE OF 1KB ! + let t = Type::Primitive(PrimitiveType::Array(Box::new(inner_t), 1024)); + + expect!(TokenType::CloseArray, ctx); + + Ok(t) + } else if TokenType::OpenParens == token.t { + ctx.consume(); + + let t = Type::FuncType(FuncType::parse(ctx)?); + + expect!(TokenType::CloseParens, ctx); + + Ok(t) } else { panic!("Not a type"); } } } -impl Parse for TypeSignature { +impl Parse for FuncType { fn parse(ctx: &mut Parser) -> Result { - let mut args = vec![]; + let mut arguments = vec![]; loop { let t = Type::parse(ctx)?; - args.push(t); + arguments.push(Box::new(t)); if ctx.cur_tok().t != TokenType::Arrow { break; @@ -1232,13 +1255,8 @@ impl Parse for TypeSignature { ctx.consume(); } - let ret = args.pop().unwrap(); - - let mut t_sig = TypeSignature::default(); - - t_sig.args = args; - t_sig.ret = ret; + let ret = arguments.pop().unwrap(); - Ok(t_sig) + Ok(FuncType { arguments, ret }) } } diff --git a/src/lib/parser/parsing_context.rs b/src/lib/parser/parsing_context.rs index fd1a05b3..cd05f3ce 100644 --- a/src/lib/parser/parsing_context.rs +++ b/src/lib/parser/parsing_context.rs @@ -29,10 +29,10 @@ impl ParsingCtx { } } - pub fn add_file(&mut self, file: SourceFile) { + pub fn add_file(&mut self, file: &SourceFile) { self.current_file = Some(file.file_path.clone()); - self.files.insert(file.file_path.clone(), file); + self.files.insert(file.file_path.clone(), file.clone()); } pub fn get_current_file(&self) -> SourceFile { @@ -57,10 +57,8 @@ impl ParsingCtx { self.diagnostics.list.len().to_string().yellow(), "warnings".yellow(), ); - } else { - if self.config.verbose { - println!("[{}] Compilation successful", "Success".green(),); - } + } else if self.config.verbose { + println!("[{}] Compilation successful", "Success".green(),); } } @@ -74,11 +72,10 @@ impl ParsingCtx { .iter() .enumerate() .partition(|(i, _diag)| { - if let DiagnosticType::Error = *self.diagnostics.list_types.get(*i).unwrap() { - true - } else { - false - } + matches!( + *self.diagnostics.list_types.get(*i).unwrap(), + DiagnosticType::Error + ) }); println!( @@ -129,7 +126,7 @@ impl ParsingCtx { ); } - self.add_file(new_file.clone()); + self.add_file(&new_file); Ok(new_file) } diff --git a/src/lib/parser/source_file.rs b/src/lib/parser/source_file.rs index 1486d0df..04c105b7 100644 --- a/src/lib/parser/source_file.rs +++ b/src/lib/parser/source_file.rs @@ -25,7 +25,7 @@ impl SourceFile { mod_path.set_extension(""); Ok(SourceFile { - file_path: PathBuf::from(in_name.clone()), + file_path: PathBuf::from(in_name), mod_path, content: file, }) diff --git a/src/lib/parser/token.rs b/src/lib/parser/token.rs index 79ce4257..b8401c60 100644 --- a/src/lib/parser/token.rs +++ b/src/lib/parser/token.rs @@ -55,13 +55,13 @@ pub enum TokenType { Indent(u8), // whitespaces - EOL, - EOF, + Eol, + Eof, } impl Default for TokenType { fn default() -> TokenType { - TokenType::EOF + TokenType::Eof } } diff --git a/src/lib/rock.rs b/src/lib/rock.rs index b4e32273..df81254d 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -34,22 +34,22 @@ mod tests; pub use crate::helpers::config::Config; -pub fn parse_file(in_name: String, out_name: String, config: Config) -> Result<(), Diagnostic> { +pub fn parse_file(in_name: String, out_name: String, config: &Config) -> Result<(), Diagnostic> { let mut source_file = SourceFile::from_file(in_name)?; source_file.mod_path = PathBuf::from("root"); - parse_str(source_file, out_name, config) + parse_str(&source_file, out_name, config) } pub fn parse_str( - input: SourceFile, + input: &SourceFile, _output_name: String, - config: Config, + config: &Config, ) -> Result<(), Diagnostic> { - let mut parsing_ctx = ParsingCtx::new(&config); + let mut parsing_ctx = ParsingCtx::new(config); - parsing_ctx.add_file(input.clone()); + parsing_ctx.add_file(input); // Text to Ast debug!(" -> Parsing"); @@ -65,11 +65,11 @@ pub fn parse_str( // Infer Hir debug!(" -> Infer HIR"); - let new_hir = infer::infer(&mut hir, &mut parsing_ctx, &config)?; + let new_hir = infer::infer(&mut hir, &mut parsing_ctx, config)?; // Generate code debug!(" -> Lower to LLVM IR"); - let parsing_ctx = codegen::generate(&config, parsing_ctx, new_hir)?; + let parsing_ctx = codegen::generate(config, parsing_ctx, new_hir)?; // debug!(" -> Save MetaData"); // PackageMetaData { hir } @@ -92,12 +92,12 @@ pub mod test { fn build(input: String, config: Config) -> bool { let file = SourceFile { - file_path: PathBuf::from("src/lib").join(config.project_config.entry_point.clone()), + file_path: PathBuf::from("src/lib").join(&config.project_config.entry_point), mod_path: PathBuf::from("main"), content: input, }; - if let Err(_e) = parse_str(file, "main".to_string(), config.clone()) { + if let Err(_e) = parse_str(&file, "main".to_string(), &config) { return false; } @@ -154,29 +154,31 @@ pub mod test { true } - pub fn run(path: &str, input: String, config: Config) -> i64 { + pub fn run(path: &str, input: String, config: Config) -> (i64, String) { let path = Path::new("src/lib/").join(path); let build_path = path.parent().unwrap().join("build"); - let mut config = config.clone(); + let mut config = config; config.build_folder = build_path; fs::create_dir_all(config.build_folder.clone()).unwrap(); if !build(input, config.clone()) { - return -1; + return (-1, String::new()); } let cmd = Command::new(config.build_folder.join("a.out").to_str().unwrap()) .output() .expect("failed to execute BINARY"); - fs::remove_dir_all(config.build_folder.clone()).unwrap(); + let stdout = String::from_utf8(cmd.stderr).unwrap(); + + fs::remove_dir_all(config.build_folder).unwrap(); match cmd.status.code() { - Some(code) => code.into(), - None => -1, + Some(code) => (code.into(), stdout), + None => (-1, stdout), } } } diff --git a/src/lib/testcases/basic/0_arg_fn/main.rk.stdout b/src/lib/testcases/basic/0_arg_fn/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/1_arg_fn/main.rk.stdout b/src/lib/testcases/basic/1_arg_fn/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/2_arg_fn/main.rk.stdout b/src/lib/testcases/basic/2_arg_fn/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/array/main.rk.stdout b/src/lib/testcases/basic/array/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/bool_false/main.rk.stdout b/src/lib/testcases/basic/bool_false/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/bool_true/main.rk.stdout b/src/lib/testcases/basic/bool_true/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/deep_monomorph/main.rk.stdout b/src/lib/testcases/basic/deep_monomorph/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/dot_assign/main.rk.stdout b/src/lib/testcases/basic/dot_assign/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/extern/main.rk.stdout b/src/lib/testcases/basic/extern/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/fn_arg/main.rk.stdout b/src/lib/testcases/basic/fn_arg/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/fn_arg_array/main.rk b/src/lib/testcases/basic/fn_arg_array/main.rk new file mode 100644 index 00000000..0d3b6ddb --- /dev/null +++ b/src/lib/testcases/basic/fn_arg_array/main.rk @@ -0,0 +1,7 @@ +x a = a[0] + +exec f a = f a + +main = + exec x, [2.2, 3.3] + exec x, [42, 2] diff --git a/src/lib/testcases/basic/fn_arg_array/main.rk.out b/src/lib/testcases/basic/fn_arg_array/main.rk.out new file mode 100644 index 00000000..f70d7bba --- /dev/null +++ b/src/lib/testcases/basic/fn_arg_array/main.rk.out @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/lib/testcases/basic/fn_arg_array/main.rk.stdout b/src/lib/testcases/basic/fn_arg_array/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/if_else/main.rk.stdout b/src/lib/testcases/basic/if_else/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/indice_assign/main.rk.stdout b/src/lib/testcases/basic/indice_assign/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/let/main.rk.stdout b/src/lib/testcases/basic/let/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/main/main.rk.stdout b/src/lib/testcases/basic/main/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/monomorph/main.rk.stdout b/src/lib/testcases/basic/monomorph/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/monomorph_in_trait/main.rk.stdout b/src/lib/testcases/basic/monomorph_in_trait/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/multiline_struct_const/main.rk b/src/lib/testcases/basic/multiline_struct_const/main.rk new file mode 100644 index 00000000..4beec3c8 --- /dev/null +++ b/src/lib/testcases/basic/multiline_struct_const/main.rk @@ -0,0 +1,11 @@ +struct Foo + toto :: Int64 + titi :: Float64 + +main = + let lol = + Foo + toto: 42 + titi: 10.2 + + lol.toto diff --git a/src/lib/testcases/basic/multiline_struct_const/main.rk.out b/src/lib/testcases/basic/multiline_struct_const/main.rk.out new file mode 100644 index 00000000..f70d7bba --- /dev/null +++ b/src/lib/testcases/basic/multiline_struct_const/main.rk.out @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/lib/testcases/basic/multiline_struct_const/main.rk.stdout b/src/lib/testcases/basic/multiline_struct_const/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/nested_array/main.rk.stdout b/src/lib/testcases/basic/nested_array/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/nested_struct/main.rk.stdout b/src/lib/testcases/basic/nested_struct/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk b/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk new file mode 100644 index 00000000..58fa03dc --- /dev/null +++ b/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk @@ -0,0 +1,17 @@ +struct Bar + mdr :: Int64 + +struct Foo + toto :: Bar + titi :: Float64 + +main = + let lol = + Foo + toto: + Bar + mdr: 42 + titi: + 10.2 + + lol.toto.mdr diff --git a/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk.out b/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk.out new file mode 100644 index 00000000..f70d7bba --- /dev/null +++ b/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk.out @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk.stdout b/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/op_func/main.rk.stdout b/src/lib/testcases/basic/op_func/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/operator_precedence/main.rk.stdout b/src/lib/testcases/basic/operator_precedence/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/reassign/main.rk.stdout b/src/lib/testcases/basic/reassign/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/recur/main.rk.stdout b/src/lib/testcases/basic/recur/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/simple_struct/main.rk.stdout b/src/lib/testcases/basic/simple_struct/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/struct_index/main.rk.stdout b/src/lib/testcases/basic/struct_index/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/trait_monomorph/main.rk.stdout b/src/lib/testcases/basic/trait_monomorph/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/trait_use_before_decl/main.rk.stdout b/src/lib/testcases/basic/trait_use_before_decl/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/fails/basic/fn_bad_arg/main.rk b/src/lib/testcases/fails/basic/fn_bad_arg/main.rk new file mode 100644 index 00000000..5ae7c8e2 --- /dev/null +++ b/src/lib/testcases/fails/basic/fn_bad_arg/main.rk @@ -0,0 +1,4 @@ +f :: Int64 -> Int64 +f a = a + +main = f 2.2 diff --git a/src/lib/testcases/fails/basic/fn_bad_arg/main.rk.out b/src/lib/testcases/fails/basic/fn_bad_arg/main.rk.out new file mode 100644 index 00000000..d7d17fcb --- /dev/null +++ b/src/lib/testcases/fails/basic/fn_bad_arg/main.rk.out @@ -0,0 +1 @@ +-1 \ No newline at end of file diff --git a/src/lib/testcases/fails/basic/fn_bad_arg/main.rk.stdout b/src/lib/testcases/fails/basic/fn_bad_arg/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk b/src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk new file mode 100644 index 00000000..feb6c97f --- /dev/null +++ b/src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk @@ -0,0 +1,3 @@ +f a = a + +main = f 2, 2 diff --git a/src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk.out b/src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk.out new file mode 100644 index 00000000..d7d17fcb --- /dev/null +++ b/src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk.out @@ -0,0 +1 @@ +-1 \ No newline at end of file diff --git a/src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk.stdout b/src/lib/testcases/fails/basic/fn_bad_arg_nb/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk b/src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk new file mode 100644 index 00000000..7dc514b8 --- /dev/null +++ b/src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk @@ -0,0 +1,3 @@ +f a b = a + +main = f 2 diff --git a/src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk.out b/src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk.out new file mode 100644 index 00000000..d7d17fcb --- /dev/null +++ b/src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk.out @@ -0,0 +1 @@ +-1 \ No newline at end of file diff --git a/src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk.stdout b/src/lib/testcases/fails/basic/fn_bad_arg_nb2/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/fails/basic/struct_bad_field_type/main.rk b/src/lib/testcases/fails/basic/struct_bad_field_type/main.rk new file mode 100644 index 00000000..8e098548 --- /dev/null +++ b/src/lib/testcases/fails/basic/struct_bad_field_type/main.rk @@ -0,0 +1,11 @@ +struct Foo + toto :: Int64 + titi :: Float64 + +main = + let lol = + Foo + toto: 10.2 + titi: 10.2 + + lol.toto diff --git a/src/lib/testcases/fails/basic/struct_bad_field_type/main.rk.out b/src/lib/testcases/fails/basic/struct_bad_field_type/main.rk.out new file mode 100644 index 00000000..d7d17fcb --- /dev/null +++ b/src/lib/testcases/fails/basic/struct_bad_field_type/main.rk.out @@ -0,0 +1 @@ +-1 \ No newline at end of file diff --git a/src/lib/testcases/fails/basic/struct_bad_field_type/main.rk.stdout b/src/lib/testcases/fails/basic/struct_bad_field_type/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/mods/basic_mod/main.rk.stdout b/src/lib/testcases/mods/basic_mod/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/mods/build/main.rk.stdout b/src/lib/testcases/mods/build/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/mods/full_fact/eq.rk b/src/lib/testcases/mods/full_fact/eq.rk index 368d82dc..097cd64f 100644 --- a/src/lib/testcases/mods/full_fact/eq.rk +++ b/src/lib/testcases/mods/full_fact/eq.rk @@ -13,17 +13,17 @@ trait Eq a impl Eq Int64 == e f = ~IEq e f - <= e f = ~ILE e f - >= e f = ~IGE e f - < e f = ~ILT e f - > e f = ~IGT e f + <= e f = ~Ile e f + >= e f = ~Ige e f + < e f = ~Ilt e f + > e f = ~Igt e f impl Eq Float64 == g h = ~FEq g h - <= g h = ~FLE g h - >= g h = ~FGE g h - < g h = ~FLT g h - > g h = ~FGT g h + <= g h = ~Fle g h + >= g h = ~Fge g h + < g h = ~Flt g h + > g h = ~Fgt g h impl Eq Bool == i j = ~BEq i j diff --git a/src/lib/testcases/mods/full_fact/main.rk.stdout b/src/lib/testcases/mods/full_fact/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/mods/func_arg_resolution/main.rk.stdout b/src/lib/testcases/mods/func_arg_resolution/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/mods/nested_trait_resolution/main.rk.stdout b/src/lib/testcases/mods/nested_trait_resolution/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/mods/unused_fn/main.rk.stdout b/src/lib/testcases/mods/unused_fn/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/mods/unused_impl_fn/main.rk.stdout b/src/lib/testcases/mods/unused_impl_fn/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/test_template b/src/lib/testcases/test_template index ada29b5b..58a7c701 100644 --- a/src/lib/testcases/test_template +++ b/src/lib/testcases/test_template @@ -1,4 +1,4 @@ #[test] fn {name}() {{ - run("{path}", include_str!("{path}"), include_str!("{path}.out")); + run("{path}", include_str!("{path}"), include_str!("{path}.out"), include_str!("{path}.stdout")); }} diff --git a/src/lib/testcases/trait/build/main.rk.stdout b/src/lib/testcases/trait/build/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/trait/late_resolution/main.rk.stdout b/src/lib/testcases/trait/late_resolution/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/trait/multi_resolution/main.rk.stdout b/src/lib/testcases/trait/multi_resolution/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/tests.rs b/src/lib/tests.rs index c05c3b67..727888f1 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -1,146 +1,175 @@ use std::path::PathBuf; #[allow(dead_code)] -fn run(path: &str, input: &str, expected_output: &str) { +fn run(path: &str, input: &str, expected_ret: &str, expected_output: &str) { let mut config = super::Config::default(); config.project_config.entry_point = PathBuf::from(path); - let expected_output = expected_output.parse::().unwrap(); + let expected_ret = expected_ret.parse::().unwrap(); - let actual_output = super::test::run(path, input.to_string(), config.clone()); + let (ret_code, stdout) = super::test::run(path, input.to_string(), config); - assert_eq!(expected_output, actual_output); + assert_eq!(expected_ret, ret_code); + assert_eq!(expected_output, stdout); } #[test] fn testcases_trait_late_resolution_main() { - run("testcases/trait/late_resolution/main.rk", include_str!("testcases/trait/late_resolution/main.rk"), include_str!("testcases/trait/late_resolution/main.rk.out")); + run("testcases/trait/late_resolution/main.rk", include_str!("testcases/trait/late_resolution/main.rk"), include_str!("testcases/trait/late_resolution/main.rk.out"), include_str!("testcases/trait/late_resolution/main.rk.stdout")); } #[test] fn testcases_trait_multi_resolution_main() { - run("testcases/trait/multi_resolution/main.rk", include_str!("testcases/trait/multi_resolution/main.rk"), include_str!("testcases/trait/multi_resolution/main.rk.out")); + run("testcases/trait/multi_resolution/main.rk", include_str!("testcases/trait/multi_resolution/main.rk"), include_str!("testcases/trait/multi_resolution/main.rk.out"), include_str!("testcases/trait/multi_resolution/main.rk.stdout")); +} +#[test] +fn testcases_fails_basic_fn_bad_arg_nb2_main() { + run("testcases/fails/basic/fn_bad_arg_nb2/main.rk", include_str!("testcases/fails/basic/fn_bad_arg_nb2/main.rk"), include_str!("testcases/fails/basic/fn_bad_arg_nb2/main.rk.out"), include_str!("testcases/fails/basic/fn_bad_arg_nb2/main.rk.stdout")); +} +#[test] +fn testcases_fails_basic_fn_bad_arg_nb_main() { + run("testcases/fails/basic/fn_bad_arg_nb/main.rk", include_str!("testcases/fails/basic/fn_bad_arg_nb/main.rk"), include_str!("testcases/fails/basic/fn_bad_arg_nb/main.rk.out"), include_str!("testcases/fails/basic/fn_bad_arg_nb/main.rk.stdout")); +} +#[test] +fn testcases_fails_basic_struct_bad_field_type_main() { + run("testcases/fails/basic/struct_bad_field_type/main.rk", include_str!("testcases/fails/basic/struct_bad_field_type/main.rk"), include_str!("testcases/fails/basic/struct_bad_field_type/main.rk.out"), include_str!("testcases/fails/basic/struct_bad_field_type/main.rk.stdout")); +} +#[test] +fn testcases_fails_basic_fn_bad_arg_main() { + run("testcases/fails/basic/fn_bad_arg/main.rk", include_str!("testcases/fails/basic/fn_bad_arg/main.rk"), include_str!("testcases/fails/basic/fn_bad_arg/main.rk.out"), include_str!("testcases/fails/basic/fn_bad_arg/main.rk.stdout")); } #[test] fn testcases_mods_unused_impl_fn_main() { - run("testcases/mods/unused_impl_fn/main.rk", include_str!("testcases/mods/unused_impl_fn/main.rk"), include_str!("testcases/mods/unused_impl_fn/main.rk.out")); + run("testcases/mods/unused_impl_fn/main.rk", include_str!("testcases/mods/unused_impl_fn/main.rk"), include_str!("testcases/mods/unused_impl_fn/main.rk.out"), include_str!("testcases/mods/unused_impl_fn/main.rk.stdout")); } #[test] fn testcases_mods_unused_fn_main() { - run("testcases/mods/unused_fn/main.rk", include_str!("testcases/mods/unused_fn/main.rk"), include_str!("testcases/mods/unused_fn/main.rk.out")); + run("testcases/mods/unused_fn/main.rk", include_str!("testcases/mods/unused_fn/main.rk"), include_str!("testcases/mods/unused_fn/main.rk.out"), include_str!("testcases/mods/unused_fn/main.rk.stdout")); } #[test] fn testcases_mods_nested_trait_resolution_main() { - run("testcases/mods/nested_trait_resolution/main.rk", include_str!("testcases/mods/nested_trait_resolution/main.rk"), include_str!("testcases/mods/nested_trait_resolution/main.rk.out")); + run("testcases/mods/nested_trait_resolution/main.rk", include_str!("testcases/mods/nested_trait_resolution/main.rk"), include_str!("testcases/mods/nested_trait_resolution/main.rk.out"), include_str!("testcases/mods/nested_trait_resolution/main.rk.stdout")); } #[test] fn testcases_mods_full_fact_main() { - run("testcases/mods/full_fact/main.rk", include_str!("testcases/mods/full_fact/main.rk"), include_str!("testcases/mods/full_fact/main.rk.out")); + run("testcases/mods/full_fact/main.rk", include_str!("testcases/mods/full_fact/main.rk"), include_str!("testcases/mods/full_fact/main.rk.out"), include_str!("testcases/mods/full_fact/main.rk.stdout")); } #[test] fn testcases_mods_func_arg_resolution_main() { - run("testcases/mods/func_arg_resolution/main.rk", include_str!("testcases/mods/func_arg_resolution/main.rk"), include_str!("testcases/mods/func_arg_resolution/main.rk.out")); + run("testcases/mods/func_arg_resolution/main.rk", include_str!("testcases/mods/func_arg_resolution/main.rk"), include_str!("testcases/mods/func_arg_resolution/main.rk.out"), include_str!("testcases/mods/func_arg_resolution/main.rk.stdout")); } #[test] fn testcases_mods_basic_mod_main() { - run("testcases/mods/basic_mod/main.rk", include_str!("testcases/mods/basic_mod/main.rk"), include_str!("testcases/mods/basic_mod/main.rk.out")); + run("testcases/mods/basic_mod/main.rk", include_str!("testcases/mods/basic_mod/main.rk"), include_str!("testcases/mods/basic_mod/main.rk.out"), include_str!("testcases/mods/basic_mod/main.rk.stdout")); } #[test] fn testcases_basic_bool_true_main() { - run("testcases/basic/bool_true/main.rk", include_str!("testcases/basic/bool_true/main.rk"), include_str!("testcases/basic/bool_true/main.rk.out")); + run("testcases/basic/bool_true/main.rk", include_str!("testcases/basic/bool_true/main.rk"), include_str!("testcases/basic/bool_true/main.rk.out"), include_str!("testcases/basic/bool_true/main.rk.stdout")); } #[test] fn testcases_basic_op_func_main() { - run("testcases/basic/op_func/main.rk", include_str!("testcases/basic/op_func/main.rk"), include_str!("testcases/basic/op_func/main.rk.out")); + run("testcases/basic/op_func/main.rk", include_str!("testcases/basic/op_func/main.rk"), include_str!("testcases/basic/op_func/main.rk.out"), include_str!("testcases/basic/op_func/main.rk.stdout")); +} +#[test] +fn testcases_basic_multiline_struct_const_main() { + run("testcases/basic/multiline_struct_const/main.rk", include_str!("testcases/basic/multiline_struct_const/main.rk"), include_str!("testcases/basic/multiline_struct_const/main.rk.out"), include_str!("testcases/basic/multiline_struct_const/main.rk.stdout")); } #[test] fn testcases_basic_2_arg_fn_main() { - run("testcases/basic/2_arg_fn/main.rk", include_str!("testcases/basic/2_arg_fn/main.rk"), include_str!("testcases/basic/2_arg_fn/main.rk.out")); + run("testcases/basic/2_arg_fn/main.rk", include_str!("testcases/basic/2_arg_fn/main.rk"), include_str!("testcases/basic/2_arg_fn/main.rk.out"), include_str!("testcases/basic/2_arg_fn/main.rk.stdout")); } #[test] fn testcases_basic_monomorph_in_trait_main() { - run("testcases/basic/monomorph_in_trait/main.rk", include_str!("testcases/basic/monomorph_in_trait/main.rk"), include_str!("testcases/basic/monomorph_in_trait/main.rk.out")); + run("testcases/basic/monomorph_in_trait/main.rk", include_str!("testcases/basic/monomorph_in_trait/main.rk"), include_str!("testcases/basic/monomorph_in_trait/main.rk.out"), include_str!("testcases/basic/monomorph_in_trait/main.rk.stdout")); } #[test] fn testcases_basic_trait_use_before_decl_main() { - run("testcases/basic/trait_use_before_decl/main.rk", include_str!("testcases/basic/trait_use_before_decl/main.rk"), include_str!("testcases/basic/trait_use_before_decl/main.rk.out")); + run("testcases/basic/trait_use_before_decl/main.rk", include_str!("testcases/basic/trait_use_before_decl/main.rk"), include_str!("testcases/basic/trait_use_before_decl/main.rk.out"), include_str!("testcases/basic/trait_use_before_decl/main.rk.stdout")); +} +#[test] +fn testcases_basic_nested_struct_dect_multiline_main() { + run("testcases/basic/nested_struct_dect_multiline/main.rk", include_str!("testcases/basic/nested_struct_dect_multiline/main.rk"), include_str!("testcases/basic/nested_struct_dect_multiline/main.rk.out"), include_str!("testcases/basic/nested_struct_dect_multiline/main.rk.stdout")); } #[test] fn testcases_basic_array_main() { - run("testcases/basic/array/main.rk", include_str!("testcases/basic/array/main.rk"), include_str!("testcases/basic/array/main.rk.out")); + run("testcases/basic/array/main.rk", include_str!("testcases/basic/array/main.rk"), include_str!("testcases/basic/array/main.rk.out"), include_str!("testcases/basic/array/main.rk.stdout")); } #[test] fn testcases_basic_nested_struct_main() { - run("testcases/basic/nested_struct/main.rk", include_str!("testcases/basic/nested_struct/main.rk"), include_str!("testcases/basic/nested_struct/main.rk.out")); + run("testcases/basic/nested_struct/main.rk", include_str!("testcases/basic/nested_struct/main.rk"), include_str!("testcases/basic/nested_struct/main.rk.out"), include_str!("testcases/basic/nested_struct/main.rk.stdout")); } #[test] fn testcases_basic_simple_struct_main() { - run("testcases/basic/simple_struct/main.rk", include_str!("testcases/basic/simple_struct/main.rk"), include_str!("testcases/basic/simple_struct/main.rk.out")); + run("testcases/basic/simple_struct/main.rk", include_str!("testcases/basic/simple_struct/main.rk"), include_str!("testcases/basic/simple_struct/main.rk.out"), include_str!("testcases/basic/simple_struct/main.rk.stdout")); } #[test] fn testcases_basic_reassign_main() { - run("testcases/basic/reassign/main.rk", include_str!("testcases/basic/reassign/main.rk"), include_str!("testcases/basic/reassign/main.rk.out")); + run("testcases/basic/reassign/main.rk", include_str!("testcases/basic/reassign/main.rk"), include_str!("testcases/basic/reassign/main.rk.out"), include_str!("testcases/basic/reassign/main.rk.stdout")); } #[test] fn testcases_basic_indice_assign_main() { - run("testcases/basic/indice_assign/main.rk", include_str!("testcases/basic/indice_assign/main.rk"), include_str!("testcases/basic/indice_assign/main.rk.out")); + run("testcases/basic/indice_assign/main.rk", include_str!("testcases/basic/indice_assign/main.rk"), include_str!("testcases/basic/indice_assign/main.rk.out"), include_str!("testcases/basic/indice_assign/main.rk.stdout")); } #[test] fn testcases_basic_dot_assign_main() { - run("testcases/basic/dot_assign/main.rk", include_str!("testcases/basic/dot_assign/main.rk"), include_str!("testcases/basic/dot_assign/main.rk.out")); + run("testcases/basic/dot_assign/main.rk", include_str!("testcases/basic/dot_assign/main.rk"), include_str!("testcases/basic/dot_assign/main.rk.out"), include_str!("testcases/basic/dot_assign/main.rk.stdout")); } #[test] fn testcases_basic_extern_main() { - run("testcases/basic/extern/main.rk", include_str!("testcases/basic/extern/main.rk"), include_str!("testcases/basic/extern/main.rk.out")); + run("testcases/basic/extern/main.rk", include_str!("testcases/basic/extern/main.rk"), include_str!("testcases/basic/extern/main.rk.out"), include_str!("testcases/basic/extern/main.rk.stdout")); } #[test] fn testcases_basic_1_arg_fn_main() { - run("testcases/basic/1_arg_fn/main.rk", include_str!("testcases/basic/1_arg_fn/main.rk"), include_str!("testcases/basic/1_arg_fn/main.rk.out")); + run("testcases/basic/1_arg_fn/main.rk", include_str!("testcases/basic/1_arg_fn/main.rk"), include_str!("testcases/basic/1_arg_fn/main.rk.out"), include_str!("testcases/basic/1_arg_fn/main.rk.stdout")); } #[test] fn testcases_basic_monomorph_main() { - run("testcases/basic/monomorph/main.rk", include_str!("testcases/basic/monomorph/main.rk"), include_str!("testcases/basic/monomorph/main.rk.out")); + run("testcases/basic/monomorph/main.rk", include_str!("testcases/basic/monomorph/main.rk"), include_str!("testcases/basic/monomorph/main.rk.out"), include_str!("testcases/basic/monomorph/main.rk.stdout")); } #[test] fn testcases_basic_bool_false_main() { - run("testcases/basic/bool_false/main.rk", include_str!("testcases/basic/bool_false/main.rk"), include_str!("testcases/basic/bool_false/main.rk.out")); + run("testcases/basic/bool_false/main.rk", include_str!("testcases/basic/bool_false/main.rk"), include_str!("testcases/basic/bool_false/main.rk.out"), include_str!("testcases/basic/bool_false/main.rk.stdout")); } #[test] fn testcases_basic_main_main() { - run("testcases/basic/main/main.rk", include_str!("testcases/basic/main/main.rk"), include_str!("testcases/basic/main/main.rk.out")); + run("testcases/basic/main/main.rk", include_str!("testcases/basic/main/main.rk"), include_str!("testcases/basic/main/main.rk.out"), include_str!("testcases/basic/main/main.rk.stdout")); } #[test] fn testcases_basic_fn_arg_main() { - run("testcases/basic/fn_arg/main.rk", include_str!("testcases/basic/fn_arg/main.rk"), include_str!("testcases/basic/fn_arg/main.rk.out")); + run("testcases/basic/fn_arg/main.rk", include_str!("testcases/basic/fn_arg/main.rk"), include_str!("testcases/basic/fn_arg/main.rk.out"), include_str!("testcases/basic/fn_arg/main.rk.stdout")); } #[test] fn testcases_basic_recur_main() { - run("testcases/basic/recur/main.rk", include_str!("testcases/basic/recur/main.rk"), include_str!("testcases/basic/recur/main.rk.out")); + run("testcases/basic/recur/main.rk", include_str!("testcases/basic/recur/main.rk"), include_str!("testcases/basic/recur/main.rk.out"), include_str!("testcases/basic/recur/main.rk.stdout")); } #[test] fn testcases_basic_struct_index_main() { - run("testcases/basic/struct_index/main.rk", include_str!("testcases/basic/struct_index/main.rk"), include_str!("testcases/basic/struct_index/main.rk.out")); + run("testcases/basic/struct_index/main.rk", include_str!("testcases/basic/struct_index/main.rk"), include_str!("testcases/basic/struct_index/main.rk.out"), include_str!("testcases/basic/struct_index/main.rk.stdout")); } #[test] fn testcases_basic_nested_array_main() { - run("testcases/basic/nested_array/main.rk", include_str!("testcases/basic/nested_array/main.rk"), include_str!("testcases/basic/nested_array/main.rk.out")); + run("testcases/basic/nested_array/main.rk", include_str!("testcases/basic/nested_array/main.rk"), include_str!("testcases/basic/nested_array/main.rk.out"), include_str!("testcases/basic/nested_array/main.rk.stdout")); } #[test] fn testcases_basic_if_else_main() { - run("testcases/basic/if_else/main.rk", include_str!("testcases/basic/if_else/main.rk"), include_str!("testcases/basic/if_else/main.rk.out")); + run("testcases/basic/if_else/main.rk", include_str!("testcases/basic/if_else/main.rk"), include_str!("testcases/basic/if_else/main.rk.out"), include_str!("testcases/basic/if_else/main.rk.stdout")); } #[test] fn testcases_basic_operator_precedence_main() { - run("testcases/basic/operator_precedence/main.rk", include_str!("testcases/basic/operator_precedence/main.rk"), include_str!("testcases/basic/operator_precedence/main.rk.out")); + run("testcases/basic/operator_precedence/main.rk", include_str!("testcases/basic/operator_precedence/main.rk"), include_str!("testcases/basic/operator_precedence/main.rk.out"), include_str!("testcases/basic/operator_precedence/main.rk.stdout")); } #[test] fn testcases_basic_let_main() { - run("testcases/basic/let/main.rk", include_str!("testcases/basic/let/main.rk"), include_str!("testcases/basic/let/main.rk.out")); + run("testcases/basic/let/main.rk", include_str!("testcases/basic/let/main.rk"), include_str!("testcases/basic/let/main.rk.out"), include_str!("testcases/basic/let/main.rk.stdout")); +} +#[test] +fn testcases_basic_fn_arg_array_main() { + run("testcases/basic/fn_arg_array/main.rk", include_str!("testcases/basic/fn_arg_array/main.rk"), include_str!("testcases/basic/fn_arg_array/main.rk.out"), include_str!("testcases/basic/fn_arg_array/main.rk.stdout")); } #[test] fn testcases_basic_0_arg_fn_main() { - run("testcases/basic/0_arg_fn/main.rk", include_str!("testcases/basic/0_arg_fn/main.rk"), include_str!("testcases/basic/0_arg_fn/main.rk.out")); + run("testcases/basic/0_arg_fn/main.rk", include_str!("testcases/basic/0_arg_fn/main.rk"), include_str!("testcases/basic/0_arg_fn/main.rk.out"), include_str!("testcases/basic/0_arg_fn/main.rk.stdout")); } #[test] fn testcases_basic_trait_monomorph_main() { - run("testcases/basic/trait_monomorph/main.rk", include_str!("testcases/basic/trait_monomorph/main.rk"), include_str!("testcases/basic/trait_monomorph/main.rk.out")); + run("testcases/basic/trait_monomorph/main.rk", include_str!("testcases/basic/trait_monomorph/main.rk"), include_str!("testcases/basic/trait_monomorph/main.rk.out"), include_str!("testcases/basic/trait_monomorph/main.rk.stdout")); } diff --git a/std/src/eq.rk b/std/src/eq.rk index 368d82dc..097cd64f 100644 --- a/std/src/eq.rk +++ b/std/src/eq.rk @@ -13,17 +13,17 @@ trait Eq a impl Eq Int64 == e f = ~IEq e f - <= e f = ~ILE e f - >= e f = ~IGE e f - < e f = ~ILT e f - > e f = ~IGT e f + <= e f = ~Ile e f + >= e f = ~Ige e f + < e f = ~Ilt e f + > e f = ~Igt e f impl Eq Float64 == g h = ~FEq g h - <= g h = ~FLE g h - >= g h = ~FGE g h - < g h = ~FLT g h - > g h = ~FGT g h + <= g h = ~Fle g h + >= g h = ~Fge g h + < g h = ~Flt g h + > g h = ~Fgt g h impl Eq Bool == i j = ~BEq i j From fe499da21b1df012ce51946c7cd0bd91994c49fa Mon Sep 17 00:00:00 2001 From: Champii Date: Fri, 1 Oct 2021 00:13:56 +0000 Subject: [PATCH 04/74] Generated files for new version --- Cargo.toml | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 5c41648c..afd6987c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.6-typesignature-parse" +version = "0.1.6-develop" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index ae853b38..0042a87f 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.6-typesignature-parse +# Rock v0.1.6-develop -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=typesignature_parse)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. @@ -41,10 +41,10 @@ How to install and run the compiler: Linux x86_64 only -[Rock v0.1.6-typesignature-parse](https://github.com/Champii/Rock/releases/download/v0.1.6-typesignature-parse/rock) (Tested on arch, btw) +[Rock v0.1.6-develop](https://github.com/Champii/Rock/releases/download/v0.1.6-develop/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.6-typesignature-parse/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.6-develop/rock chmod +x rock ./rock -V ``` From f018da5f1109b060a8285cafdcac3bdda11373e2 Mon Sep 17 00:00:00 2001 From: Florian Greiner Date: Fri, 1 Oct 2021 02:19:01 +0200 Subject: [PATCH 05/74] Merge --- Cargo.lock | 2 +- src/lib/tests.rs | 8 ++++++++ 2 files changed, 9 insertions(+), 1 deletion(-) diff --git a/Cargo.lock b/Cargo.lock index 7a4b7d54..1a431ca4 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -313,7 +313,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rock" -version = "0.1.6-typesignature-parse" +version = "0.1.6-develop" dependencies = [ "bincode", "bitflags", diff --git a/src/lib/tests.rs b/src/lib/tests.rs index 727888f1..395bbb71 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -130,6 +130,14 @@ fn testcases_basic_bool_false_main() { run("testcases/basic/bool_false/main.rk", include_str!("testcases/basic/bool_false/main.rk"), include_str!("testcases/basic/bool_false/main.rk.out"), include_str!("testcases/basic/bool_false/main.rk.stdout")); } #[test] +fn testcases_basic_struct_array_field_main() { + run("testcases/basic/struct_array_field/main.rk", include_str!("testcases/basic/struct_array_field/main.rk"), include_str!("testcases/basic/struct_array_field/main.rk.out")); +} +#[test] +fn testcases_basic_struct_array_field_main() { + run("testcases/basic/struct_array_field/main.rk", include_str!("testcases/basic/struct_array_field/main.rk"), include_str!("testcases/basic/struct_array_field/main.rk.out")); +} +#[test] fn testcases_basic_main_main() { run("testcases/basic/main/main.rk", include_str!("testcases/basic/main/main.rk"), include_str!("testcases/basic/main/main.rk.out"), include_str!("testcases/basic/main/main.rk.stdout")); } From 082a229e5358e779ac386c9a4f226c1f9d1fd284 Mon Sep 17 00:00:00 2001 From: Florian Greiner Date: Fri, 1 Oct 2021 02:19:16 +0200 Subject: [PATCH 06/74] Merge --- src/lib/tests.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/lib/tests.rs b/src/lib/tests.rs index 395bbb71..cdcba452 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -138,6 +138,10 @@ fn testcases_basic_struct_array_field_main() { run("testcases/basic/struct_array_field/main.rk", include_str!("testcases/basic/struct_array_field/main.rk"), include_str!("testcases/basic/struct_array_field/main.rk.out")); } #[test] +fn testcases_basic_struct_array_field_main() { + run("testcases/basic/struct_array_field/main.rk", include_str!("testcases/basic/struct_array_field/main.rk"), include_str!("testcases/basic/struct_array_field/main.rk.out")); +} +#[test] fn testcases_basic_main_main() { run("testcases/basic/main/main.rk", include_str!("testcases/basic/main/main.rk"), include_str!("testcases/basic/main/main.rk.out"), include_str!("testcases/basic/main/main.rk.stdout")); } From 1c1038e2874ee0f1c4eb33006826f010edc02db1 Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Oct 2021 06:57:36 -0700 Subject: [PATCH 07/74] Mostly cleanup (#40) * Cleanup of type from implementation * Separated struct type into its own module * Separated Types into their own module * Better FuncType implementation * Clippy * Factorized some code in ty::Type * More sensible module and macro exports * Separated resolver from ast * Cleanup, import and code concision * Exchanged concat_idents for paste macro in trait generation * Generated files for new version Co-authored-by: Florian Greiner --- .github/templates/README.md | 14 +- Cargo.lock | 13 +- Cargo.toml | 2 +- README.md | 22 +- src/bin/main.rs | 9 +- src/lib/ast/ast_print.rs | 92 +++---- src/lib/ast/identity.rs | 6 +- src/lib/ast/mod.rs | 9 +- src/lib/ast/span_collector.rs | 36 ++- src/lib/ast/tree.rs | 128 ++-------- src/lib/ast/visit.rs | 96 ++++--- src/lib/ast_lowering/ast_lowering_context.rs | 5 +- src/lib/ast_lowering/hir_map.rs | 5 +- src/lib/codegen/codegen_context.rs | 13 +- src/lib/diagnostics/diagnostic.rs | 4 +- src/lib/helpers/class_name.rs | 1 - src/lib/helpers/walk_helpers.rs | 2 - src/lib/hir/arena.rs | 19 +- src/lib/hir/hir_printer.rs | 2 +- src/lib/hir/tree.rs | 65 ++--- src/lib/hir/visit.rs | 79 +++--- src/lib/hir/visit_mut.rs | 79 +++--- src/lib/infer/constraint.rs | 206 ++++++++------- src/lib/infer/mangle.rs | 6 +- src/lib/infer/monomorphize/mod.rs | 2 +- src/lib/infer/monomorphize/monomorphizer.rs | 58 +++-- src/lib/infer/state.rs | 10 +- src/lib/parser/mod.rs | 8 +- src/lib/parser/parser_impl.rs | 12 +- src/lib/parser/parsing_context.rs | 6 +- src/lib/parser/token.rs | 6 +- src/lib/{ast/resolve => resolver}/mod.rs | 33 +-- .../resolve => resolver}/resolution_map.rs | 3 +- .../{ast/resolve => resolver}/resolve_ctx.rs | 12 +- .../resolve => resolver}/unused_collector.rs | 12 +- src/lib/rock.rs | 45 ++-- .../basic/struct_array_field/main.rk | 11 + .../basic/struct_array_field/main.rk.out | 1 + .../basic/struct_array_field/main.rk.stdout | 0 src/lib/tests.rs | 4 + src/lib/{ast/type.rs => ty/func_type.rs} | 240 ++++-------------- src/lib/ty/mod.rs | 9 + src/lib/{ast => ty}/primitive_type.rs | 36 ++- src/lib/ty/struct_type.rs | 84 ++++++ src/lib/ty/type.rs | 224 ++++++++++++++++ 45 files changed, 917 insertions(+), 812 deletions(-) rename src/lib/{ast/resolve => resolver}/mod.rs (60%) rename src/lib/{ast/resolve => resolver}/resolution_map.rs (94%) rename src/lib/{ast/resolve => resolver}/resolve_ctx.rs (96%) rename src/lib/{ast/resolve => resolver}/unused_collector.rs (92%) create mode 100644 src/lib/testcases/basic/struct_array_field/main.rk create mode 100644 src/lib/testcases/basic/struct_array_field/main.rk.out create mode 100644 src/lib/testcases/basic/struct_array_field/main.rk.stdout rename src/lib/{ast/type.rs => ty/func_type.rs} (53%) create mode 100644 src/lib/ty/mod.rs rename src/lib/{ast => ty}/primitive_type.rs (62%) create mode 100644 src/lib/ty/struct_type.rs create mode 100644 src/lib/ty/type.rs diff --git a/.github/templates/README.md b/.github/templates/README.md index a686b590..c0fd0e8b 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -8,13 +8,13 @@ It's highly inspired from Livescript, and will borrow (pun intended) some featur # VTable - [Features]( #features ) -- [Development notes]( #development-notes ) - [Install]( #install ) - [Using released binary]( #using-released-binary ) - [With cargo from Git]( #with-cargo-from-git ) - [From sources]( #from-sources ) - [Quickstart]( #quickstart ) - [Showcases]( #showcases ) +- [Development notes]( #development-notes ) ## Features @@ -25,12 +25,6 @@ It's highly inspired from Livescript, and will borrow (pun intended) some featur - Parametric Polymorphism by default - Compile to LLVM IR -## Development notes - -This project, its syntax and its APIs are subject to change at any moment. -This is a personal project, so please bear with me -(Differently put: this is a big red hot pile of experimental garbage right now) - ## Install Warning: This project has only been tested on Linux x86_64. @@ -217,3 +211,9 @@ rock run ``` Prints `MyName` + +## Development notes + +This project, its syntax and its APIs are subject to change at any moment. +This is a personal project, so please bear with me +(Differently put: this is a big red hot pile of experimental garbage right now) diff --git a/Cargo.lock b/Cargo.lock index 7a4b7d54..8d2335b5 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -84,16 +84,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "concat-idents" -version = "1.1.3" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6f90860248d75014b7b103db8fee4f291c07bfb41306cdf77a0a5ab7a10d2f" -dependencies = [ - "quote", - "syn", -] - [[package]] name = "either" version = "1.6.1" @@ -313,13 +303,12 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rock" -version = "0.1.6-typesignature-parse" +version = "0.1.6-function-in-struct-field" dependencies = [ "bincode", "bitflags", "clap", "colored", - "concat-idents", "either", "env_logger", "inkwell", diff --git a/Cargo.toml b/Cargo.toml index afd6987c..07d0297f 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.6-develop" +version = "0.1.6-function-in-struct-field" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 0042a87f..df19b7a6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.6-develop +# Rock v0.1.6-function-in-struct-field -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=function_in_struct_field)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. @@ -8,13 +8,13 @@ It's highly inspired from Livescript, and will borrow (pun intended) some featur # VTable - [Features]( #features ) -- [Development notes]( #development-notes ) - [Install]( #install ) - [Using released binary]( #using-released-binary ) - [With cargo from Git]( #with-cargo-from-git ) - [From sources]( #from-sources ) - [Quickstart]( #quickstart ) - [Showcases]( #showcases ) +- [Development notes]( #development-notes ) ## Features @@ -25,12 +25,6 @@ It's highly inspired from Livescript, and will borrow (pun intended) some featur - Parametric Polymorphism by default - Compile to LLVM IR -## Development notes - -This project, its syntax and its APIs are subject to change at any moment. -This is a personal project, so please bear with me -(Differently put: this is a big red hot pile of experimental garbage right now) - ## Install Warning: This project has only been tested on Linux x86_64. @@ -41,10 +35,10 @@ How to install and run the compiler: Linux x86_64 only -[Rock v0.1.6-develop](https://github.com/Champii/Rock/releases/download/v0.1.6-develop/rock) (Tested on arch, btw) +[Rock v0.1.6-function-in-struct-field](https://github.com/Champii/Rock/releases/download/v0.1.6-function-in-struct-field/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.6-develop/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.6-function-in-struct-field/rock chmod +x rock ./rock -V ``` @@ -217,3 +211,9 @@ rock run ``` Prints `MyName` + +## Development notes + +This project, its syntax and its APIs are subject to change at any moment. +This is a personal project, so please bear with me +(Differently put: this is a big red hot pile of experimental garbage right now) diff --git a/src/bin/main.rs b/src/bin/main.rs index 7650dfb8..1b111a5d 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -5,8 +5,7 @@ extern crate rock; extern crate log; use clap::{App, Arg, SubCommand}; -use std::process::Command; -use std::{fs, path::PathBuf}; +use std::{fs, path::PathBuf, process::Command}; pub mod logger; @@ -20,7 +19,7 @@ fn build(config: &Config) -> bool { fs::create_dir_all(config.build_folder.clone()).unwrap(); - if let Err(diagnostic) = rock::parse_file(entry_file.to_string(), "".to_string(), config) { + if let Err(diagnostic) = rock::parse_file(entry_file.to_string(), config) { if let DiagnosticKind::NoError = diagnostic.get_kind() { } else { println!("Error: {}", diagnostic.get_kind()); @@ -171,12 +170,8 @@ fn main() { if let Some(_matches) = matches.subcommand_matches("build") { build(&config); - - } else if let Some(_matches) = matches.subcommand_matches("run") { run(config); - - } else { println!("{}", matches.usage()); } diff --git a/src/lib/ast/ast_print.rs b/src/lib/ast/ast_print.rs index 7d97b5c3..adc8fae3 100644 --- a/src/lib/ast/ast_print.rs +++ b/src/lib/ast/ast_print.rs @@ -3,21 +3,16 @@ use std::fmt::Debug; use crate::ast::visit::*; use crate::ast::*; use crate::helpers::*; -use crate::parser::*; +use crate::ty::*; +use paste::paste; pub struct AstPrintContext { indent: usize, - tokens: Vec, - _input: SourceFile, } impl AstPrintContext { - pub fn new(tokens: Vec, input: SourceFile) -> Self { - Self { - indent: 0, - _input: input, - tokens, - } + pub fn new() -> Self { + Self { indent: 0 } } pub fn increment(&mut self) { @@ -28,10 +23,6 @@ impl AstPrintContext { self.indent -= 1; } - pub fn get_token(&self, token_id: TokenId) -> Option { - self.tokens.get(token_id).cloned() - } - pub fn indent(&self) -> usize { self.indent } @@ -54,8 +45,8 @@ impl AstPrintContext { macro_rules! impl_visitor_trait { ($( - $name:ident, $method:ident - )*) => { + $name:ty + )+) => { impl<'ast> Visitor<'ast> for AstPrintContext { fn visit_name(&mut self, name: &str) { self.print_primitive(name); @@ -72,51 +63,50 @@ macro_rules! impl_visitor_trait { self.print_primitive(val); } - $( - concat_idents!(fn_name = visit_, $method { - fn fn_name(&mut self, $method: &'ast $name) { - self.print($method); + paste! { + $( + fn [](&mut self, node: &'ast $name) { + + self.print(node); self.increment(); - concat_idents!(walk_fn_name = walk_, $method { - walk_fn_name(self, $method); - }); + [](self, node); self.decrement(); } - }); - )* + )+ + } } }; } impl_visitor_trait!( - Root, root - Mod, r#mod - TopLevel, top_level - StructDecl, struct_decl - Use, r#use - Trait, r#trait - Assign, assign - Impl, r#impl - FunctionDecl, function_decl - Identifier, identifier - ArgumentDecl, argument_decl - Body, body - Statement, statement - Expression, expression - If, r#if - Else, r#else - UnaryExpr, unary - StructCtor, struct_ctor - Operator, operator - PrimaryExpr, primary_expr - SecondaryExpr, secondary_expr - Operand, operand - Argument, argument - Literal, literal - Array, array - NativeOperator, native_operator - FuncType, func_type + Root + Mod + TopLevel + StructDecl + Use + Trait + Assign + Impl + FunctionDecl + Identifier + ArgumentDecl + Body + Statement + Expression + If + Else + UnaryExpr + StructCtor + Operator + PrimaryExpr + SecondaryExpr + Operand + Argument + Literal + Array + NativeOperator + FuncType ); diff --git a/src/lib/ast/identity.rs b/src/lib/ast/identity.rs index 8b33e1ba..5defa86e 100644 --- a/src/lib/ast/identity.rs +++ b/src/lib/ast/identity.rs @@ -2,8 +2,7 @@ use std::sync::atomic::{AtomicU64, Ordering}; use crate::parser::{Span, TokenId}; -use crate::infer::NodeId; -use crate::infer::TypeId; +use crate::ast::NodeId; static GLOBAL_NEXT_NODE_ID: AtomicU64 = AtomicU64::new(0); @@ -12,7 +11,6 @@ pub struct Identity { pub node_id: NodeId, pub token_id: TokenId, pub span: Span, - pub type_id: TypeId, pub scope_depth: u8, } @@ -22,7 +20,6 @@ impl Identity { span, node_id: Self::next_node_id(), token_id, - type_id: 0, scope_depth: 0, } } @@ -32,7 +29,6 @@ impl Identity { span: Span::new_placeholder(), node_id: 0, token_id: 0, - type_id: 0, scope_depth: 0, } } diff --git a/src/lib/ast/mod.rs b/src/lib/ast/mod.rs index d3e6aa17..5a533149 100644 --- a/src/lib/ast/mod.rs +++ b/src/lib/ast/mod.rs @@ -2,16 +2,13 @@ pub mod ast_print; mod identity; -mod primitive_type; -pub mod resolve; pub mod span_collector; mod tree; -mod r#type; pub mod visit; pub use identity::*; -pub use primitive_type::*; -pub use r#type::*; -pub use resolve::resolve; pub use tree::*; pub use visit::*; + +// TODO: Make it the same way as HirId and FnBodyId ? +pub type NodeId = u64; diff --git a/src/lib/ast/span_collector.rs b/src/lib/ast/span_collector.rs index 0720484b..627846b8 100644 --- a/src/lib/ast/span_collector.rs +++ b/src/lib/ast/span_collector.rs @@ -1,9 +1,9 @@ use paste::paste; use std::collections::HashMap; -use crate::{ast::visit::*}; +use crate::ast::visit::*; +use crate::parser::Span; use crate::{ast::visit::Visitor, ast::*}; -use crate::{parser::Span, NodeId}; #[derive(Debug, Default)] pub struct SpanCollector { @@ -27,7 +27,7 @@ impl SpanCollector { } macro_rules! generate_span_collector { - ($($expr:ty,)+) => { + ($($expr:ty)+) => { impl<'a> Visitor<'a> for SpanCollector { paste! { $( @@ -43,15 +43,23 @@ macro_rules! generate_span_collector { } generate_span_collector!( - Mod, - TopLevel, - Prototype, - Use, - FunctionDecl, - Identifier, - ArgumentDecl, - If, - PrimaryExpr, - Literal, - NativeOperator, + Mod + TopLevel + Prototype + Use + FunctionDecl + Identifier + ArgumentDecl + If + PrimaryExpr + Literal + NativeOperator ); + +pub fn collect_spans(root: &Root) -> HashMap { + let mut span_collector = SpanCollector::new(); + + span_collector.visit_root(root); + + span_collector.take_list() +} diff --git a/src/lib/ast/tree.rs b/src/lib/ast/tree.rs index df145860..466c80f4 100644 --- a/src/lib/ast/tree.rs +++ b/src/lib/ast/tree.rs @@ -1,13 +1,12 @@ use std::collections::HashMap; -use crate::{ast::identity::Identity, parser::Token}; -use crate::{parser::Span, NodeId}; - -use crate::ast::resolve::ResolutionMap; -use crate::generate_has_name; -use crate::helpers::*; - -use super::{FuncType, StructType, Type}; +use crate::{ + ast::{identity::Identity, NodeId}, + helpers::*, + parser::{Span, Token}, + resolver::ResolutionMap, + ty::{FuncType, Type}, +}; #[derive(Debug, Clone)] pub struct Root { @@ -25,85 +24,7 @@ pub struct Mod { pub identity: Identity, } -impl Mod { - pub fn filter_unused_top_levels(&mut self, unused: Vec) { - let mut unused_trait_method_names = vec![]; - - self.top_levels = self - .top_levels - .iter_mut() - .filter_map(|top_level| { - match &mut top_level.kind { - TopLevelKind::Function(f) => { - if unused.contains(&f.identity.node_id) { - warn!("Unused function {:?}", f.name); - - return None; - } - } - TopLevelKind::Trait(t) => { - let mut defs = vec![]; - - for f in &t.defs { - if unused.contains(&f.identity.node_id) { - unused_trait_method_names.push(f.name.clone()); - - warn!("Unused trait method {:?}", f.name); - } else { - defs.push(f.clone()); - } - } - - if defs.is_empty() { - return None; - } - - let mut t2 = t.clone(); - t2.defs = defs.clone(); - - return Some(TopLevel { - kind: TopLevelKind::Trait(t2), - ..top_level.clone() - }); - } - TopLevelKind::Impl(i) => { - let mut defs = vec![]; - - for f in &i.defs { - if unused_trait_method_names.contains(&f.name) { - warn!("Unused impl method {:?}", f.name); - } else { - defs.push(f.clone()); - } - } - - if defs.is_empty() { - return None; - } - - let mut i2 = i.clone(); - i2.defs = defs.clone(); - - return Some(TopLevel { - kind: TopLevelKind::Impl(i2), - ..top_level.clone() - }); - } - TopLevelKind::Mod(id, m) => { - m.filter_unused_top_levels(unused.clone()); - - return Some(TopLevel { - kind: TopLevelKind::Mod(id.clone(), m.clone()), - ..top_level.clone() - }); - } - _ => (), - }; - Some(top_level.clone()) - }) - .collect(); - } -} +impl Mod {} #[derive(Debug, Clone)] pub struct TopLevel { @@ -130,25 +51,6 @@ pub struct StructDecl { pub defs: Vec, } -impl StructDecl { - pub fn to_type(&self) -> Type { - Type::Struct(StructType { - name: self.name.get_name(), - defs: self - .defs - .iter() - .map(|proto| { - if proto.signature.arguments.is_empty() { - (proto.name.name.clone(), proto.signature.ret.clone()) - } else { - (proto.name.name.clone(), Box::new(proto.signature.to_type())) - } - }) - .collect(), - }) - } -} - #[derive(Debug, Clone)] pub struct StructCtor { pub identity: Identity, @@ -240,10 +142,6 @@ impl IdentifierPath { child } - pub fn last_segment(&self) -> Identifier { - self.path.iter().last().unwrap().clone() - } - pub fn last_segment_ref(&self) -> &Identifier { self.path.iter().last().unwrap() } @@ -389,6 +287,7 @@ pub struct Expression { } impl Expression { + #[allow(dead_code)] pub fn is_literal(&self) -> bool { match &self.kind { ExpressionKind::UnaryExpr(unary) => unary.is_literal(), @@ -396,6 +295,7 @@ impl Expression { } } + #[allow(dead_code)] pub fn is_identifier(&self) -> bool { match &self.kind { ExpressionKind::UnaryExpr(unary) => unary.is_identifier(), @@ -403,10 +303,12 @@ impl Expression { } } + #[allow(dead_code)] pub fn is_binop(&self) -> bool { matches!(&self.kind, ExpressionKind::BinopExpr(_, _, _)) } + #[allow(dead_code)] pub fn is_indice(&self) -> bool { match &self.kind { ExpressionKind::UnaryExpr(unary) => unary.is_indice(), @@ -414,12 +316,14 @@ impl Expression { } } + #[allow(dead_code)] pub fn from_unary(unary: &UnaryExpr) -> Expression { Expression { kind: ExpressionKind::UnaryExpr(unary.clone()), } } + #[allow(dead_code)] pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> Expression { Expression { kind: ExpressionKind::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { @@ -494,6 +398,7 @@ pub struct PrimaryExpr { } impl PrimaryExpr { + #[allow(dead_code)] pub fn has_secondaries(&self) -> bool { self.secondaries.is_some() } @@ -521,10 +426,12 @@ impl Operand { } } + #[allow(dead_code)] pub fn is_literal(&self) -> bool { matches!(&self.kind, OperandKind::Literal(_)) } + #[allow(dead_code)] pub fn is_identifier(&self) -> bool { matches!(&self.kind, OperandKind::Identifier(_)) } @@ -538,6 +445,7 @@ pub enum OperandKind { } impl OperandKind { + #[allow(dead_code)] pub fn to_identifier_path(&self) -> IdentifierPath { if let OperandKind::Identifier(id) = self { id.clone() diff --git a/src/lib/ast/visit.rs b/src/lib/ast/visit.rs index 9bcdfd58..502a91e2 100644 --- a/src/lib/ast/visit.rs +++ b/src/lib/ast/visit.rs @@ -1,12 +1,12 @@ -use concat_idents::concat_idents; +use paste::paste; -use crate::walk_list; -use crate::{ast::*, walk_map}; +use crate::ast::*; +use crate::ty::*; macro_rules! generate_visitor_trait { ($( - $name:ident, $method:ident - )*) => { + $name:ty + )+) => { pub trait Visitor<'ast>: Sized { fn visit_name(&mut self, _name: &str) {} @@ -15,51 +15,49 @@ macro_rules! generate_visitor_trait { T: std::fmt::Debug, {} - $( - concat_idents!(fn_name = visit_, $method { - fn fn_name(&mut self, $method: &'ast $name) { - concat_idents!(fn2_name = walk_, $method { - fn2_name(self, $method); - }); + paste! { + $( + fn [](&mut self, node: &'ast $name) { + [](self, node); } - }); - )* + )+ + } } }; } generate_visitor_trait!( - Root, root - Mod, r#mod - TopLevel, top_level - Assign, assign - AssignLeftSide, assign_left_side - Prototype, prototype - Use, r#use - Trait, r#trait - Impl, r#impl - FunctionDecl, function_decl - StructDecl, struct_decl - Identifier, identifier - IdentifierPath, identifier_path - ArgumentDecl, argument_decl - Body, body - Statement, statement - Expression, expression - If, r#if - Else, r#else - UnaryExpr, unary - Operator, operator - PrimaryExpr, primary_expr - SecondaryExpr, secondary_expr - Operand, operand - Argument, argument - Literal, literal - StructCtor, struct_ctor - Array, array - NativeOperator, native_operator - FuncType, func_type - Type, r#type + Root + Mod + TopLevel + Assign + AssignLeftSide + Prototype + Use + Trait + Impl + FunctionDecl + StructDecl + Identifier + IdentifierPath + ArgumentDecl + Body + Statement + Expression + If + Else + UnaryExpr + Operator + PrimaryExpr + SecondaryExpr + Operand + Argument + Literal + StructCtor + Array + NativeOperator + FuncType + Type ); pub fn walk_root<'a, V: Visitor<'a>>(visitor: &mut V, root: &'a Root) { @@ -184,11 +182,11 @@ pub fn walk_else<'a, V: Visitor<'a>>(visitor: &mut V, r#else: &'a Else) { pub fn walk_expression<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a Expression) { match &expr.kind { ExpressionKind::BinopExpr(unary, operator, expr) => { - visitor.visit_unary(unary); + visitor.visit_unary_expr(unary); visitor.visit_operator(operator); visitor.visit_expression(&*expr); } - ExpressionKind::UnaryExpr(unary) => visitor.visit_unary(unary), + ExpressionKind::UnaryExpr(unary) => visitor.visit_unary_expr(unary), ExpressionKind::StructCtor(ctor) => visitor.visit_struct_ctor(ctor), ExpressionKind::NativeOperation(op, left, right) => { visitor.visit_identifier(left); @@ -207,12 +205,12 @@ pub fn walk_struct_ctor<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructCtor) walk_map!(visitor, visit_expression, &s.defs); } -pub fn walk_unary<'a, V: Visitor<'a>>(visitor: &mut V, unary: &'a UnaryExpr) { +pub fn walk_unary_expr<'a, V: Visitor<'a>>(visitor: &mut V, unary: &'a UnaryExpr) { match unary { UnaryExpr::PrimaryExpr(primary) => visitor.visit_primary_expr(primary), UnaryExpr::UnaryExpr(op, unary) => { visitor.visit_operator(op); - visitor.visit_unary(&*unary); + visitor.visit_unary_expr(&*unary); } } } @@ -252,7 +250,7 @@ pub fn walk_operand<'a, V: Visitor<'a>>(visitor: &mut V, operand: &'a Operand) { } pub fn walk_argument<'a, V: Visitor<'a>>(visitor: &mut V, argument: &'a Argument) { - visitor.visit_unary(&argument.arg); + visitor.visit_unary_expr(&argument.arg); } pub fn walk_literal<'a, V: Visitor<'a>>(visitor: &mut V, literal: &'a Literal) { diff --git a/src/lib/ast_lowering/ast_lowering_context.rs b/src/lib/ast_lowering/ast_lowering_context.rs index b1c61c9d..a29216fb 100644 --- a/src/lib/ast_lowering/ast_lowering_context.rs +++ b/src/lib/ast_lowering/ast_lowering_context.rs @@ -3,7 +3,8 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ ast::*, hir::{self, Arena, FnBodyId, HirId}, - Envs, + infer::Envs, + ty::*, }; use super::{hir_map::HirMap, return_placement::ReturnInserter, InfixDesugar}; @@ -38,10 +39,8 @@ impl AstLoweringContext { arena: Arena::new(), hir_map: self.hir_map.clone(), resolutions: root.resolutions.lower_resolution_map(&self.hir_map), - node_type_ids: BTreeMap::new(), type_envs: Envs::default(), node_types: BTreeMap::new(), - types: BTreeMap::new(), top_levels: self.top_levels.clone(), bodies: self.bodies.clone(), traits: self.traits.clone(), diff --git a/src/lib/ast_lowering/hir_map.rs b/src/lib/ast_lowering/hir_map.rs index 33e01068..74930e7a 100644 --- a/src/lib/ast_lowering/hir_map.rs +++ b/src/lib/ast_lowering/hir_map.rs @@ -1,6 +1,9 @@ use std::collections::HashMap; -use crate::{ast::*, hir::FnBodyId, hir::HirId, NodeId}; +use crate::{ + ast::*, + hir::{FnBodyId, HirId}, +}; #[derive(Clone, Debug, Default, Serialize, Deserialize)] pub struct HirMap { diff --git a/src/lib/codegen/codegen_context.rs b/src/lib/codegen/codegen_context.rs index 97e35318..e358c9c0 100644 --- a/src/lib/codegen/codegen_context.rs +++ b/src/lib/codegen/codegen_context.rs @@ -11,11 +11,11 @@ use inkwell::{ }; use crate::{ - ast::{PrimitiveType, Type}, diagnostics::Diagnostic, helpers::scopes::Scopes, hir::*, parser::ParsingCtx, + ty::{PrimitiveType, Type}, }; pub struct CodegenContext<'a> { @@ -59,7 +59,7 @@ impl<'a> CodegenContext<'a> { .ptr_type(AddressSpace::Generic) .into() } - Type::FuncType(f) => { + Type::Func(f) => { let ret_t = f.ret.clone(); let args = f @@ -119,7 +119,7 @@ impl<'a> CodegenContext<'a> { pub fn lower_prototype(&mut self, p: &'a Prototype, builder: &'a Builder) -> Result<(), ()> { let t = self.hir.node_types.get(&p.hir_id).unwrap(); - if let Type::FuncType(f_type) = t { + if let Type::Func(f_type) = t { let ret_t = f_type.ret.clone(); let mut args = vec![]; @@ -170,7 +170,7 @@ impl<'a> CodegenContext<'a> { let t = self.hir.node_types.get(&f.hir_id).unwrap(); - if let Type::FuncType(f_type) = t { + if let Type::Func(f_type) = t { let ret_t = f_type.ret.clone(); let args = f @@ -406,7 +406,7 @@ impl<'a> CodegenContext<'a> { builder: &'a Builder, ) -> Result, ()> { let t = self.hir.node_types.get(&s.get_hir_id()).unwrap(); - let struct_t = t.into_struct_type(); + let struct_t = t.as_struct_type(); let llvm_struct_t_ptr = self.lower_type(t, builder).unwrap().into_pointer_type(); let llvm_struct_t = llvm_struct_t_ptr.get_element_type().into_struct_type(); @@ -525,7 +525,7 @@ impl<'a> CodegenContext<'a> { let t = self.hir.node_types.get(&dot.op.get_hir_id()).unwrap(); - let struct_t = t.into_struct_type(); + let struct_t = t.as_struct_type(); let indice = struct_t .defs @@ -626,7 +626,6 @@ impl<'a> CodegenContext<'a> { ) -> Result, ()> { let reso = self.hir.resolutions.get(&id.hir_id).unwrap(); - // println!("SCOPES {:#?}", self.scopes); let val = match self.scopes.get(reso) { None => { let span = self diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index ef653546..2d33952c 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -1,11 +1,11 @@ use std::fmt::Display; +use crate::{diagnostics::DiagnosticType, parser::Span}; use crate::{ - ast::{FuncType, Type}, hir::HirId, parser::SourceFile, + ty::{FuncType, Type}, }; -use crate::{diagnostics::DiagnosticType, parser::Span}; use colored::*; #[derive(Clone, Debug)] diff --git a/src/lib/helpers/class_name.rs b/src/lib/helpers/class_name.rs index ca4871e4..00e97e40 100644 --- a/src/lib/helpers/class_name.rs +++ b/src/lib/helpers/class_name.rs @@ -2,7 +2,6 @@ pub trait HasName { fn get_name(&self) -> String; } -#[macro_export] macro_rules! generate_has_name { ($class:tt) => { impl HasName for $class { diff --git a/src/lib/helpers/walk_helpers.rs b/src/lib/helpers/walk_helpers.rs index 4ea7686d..d5ed61f5 100644 --- a/src/lib/helpers/walk_helpers.rs +++ b/src/lib/helpers/walk_helpers.rs @@ -1,4 +1,3 @@ -#[macro_export] macro_rules! walk_list { ($visitor: expr, $method: ident, $list: expr) => { for elem in $list { @@ -13,7 +12,6 @@ macro_rules! walk_list { } } -#[macro_export] macro_rules! walk_map { ($visitor: expr, $method: ident, $list: expr) => { for (_, elem) in $list { diff --git a/src/lib/hir/arena.rs b/src/lib/hir/arena.rs index 760934a3..5d11dc5b 100644 --- a/src/lib/hir/arena.rs +++ b/src/lib/hir/arena.rs @@ -5,6 +5,14 @@ use paste::paste; use crate::hir::visit::*; use crate::hir::*; +// This is not really an Arena, but more a HirNode Collector +// The name is confusing on its properties and usage, +// as one would expect the arena to own every hir nodes from their creation, +// and give (mut) references when needed. +// Instead, this "Arena" is constructed from a clone of every nodes in the HIR, +// (as you can see bellow in the HirNodeCollector) and serves only as a global +// accessor to the graph's structure and immutable properties. +// Every effective mutable work is done on the hir::Root instead. #[derive(Debug, Default)] pub struct Arena(BTreeMap); @@ -12,18 +20,17 @@ impl Arena { pub fn new() -> Self { Self(BTreeMap::new()) } - // pub fn get_all_of_type(&self, t: HirNode) -> Vec<&HirNode> { - // for (hir_id, hir_node) = self.0 { - // if let - // } - // } } + +// FIXME: Code smell impl std::ops::Deref for Arena { type Target = BTreeMap; fn deref(&self) -> &Self::Target { &self.0 } } + +// FIXME: Code smell impl std::ops::DerefMut for Arena { fn deref_mut(&mut self) -> &mut Self::Target { &mut self.0 @@ -73,8 +80,6 @@ macro_rules! generate_hirnode_collector { } generate_hirnode_collector!( - // Mod, - // Root, TopLevel, Assign, Prototype, diff --git a/src/lib/hir/hir_printer.rs b/src/lib/hir/hir_printer.rs index 15e797ac..2395b5a0 100644 --- a/src/lib/hir/hir_printer.rs +++ b/src/lib/hir/hir_printer.rs @@ -2,11 +2,11 @@ use colored::*; use paste::paste; use std::fmt::Debug; -use crate::ast::Type; use crate::helpers::*; use crate::hir::visit::*; use crate::hir::HasHirId; use crate::hir::*; +use crate::ty::Type; pub struct HirPrinter<'a> { hir: &'a Root, diff --git a/src/lib/hir/tree.rs b/src/lib/hir/tree.rs index 041cc297..7ad6117f 100644 --- a/src/lib/hir/tree.rs +++ b/src/lib/hir/tree.rs @@ -1,11 +1,13 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ - ast::{resolve::ResolutionMap, FuncType, StructType, Type}, + ast::NodeId, ast_lowering::HirMap, hir::hir_id::*, + infer::Envs, parser::Span, - Envs, NodeId, TypeId, + resolver::ResolutionMap, + ty::{FuncType, StructType, Type}, }; use super::{arena::Arena, HasHirId}; @@ -15,9 +17,7 @@ pub struct Root { pub arena: Arena, pub hir_map: HirMap, pub resolutions: ResolutionMap, - pub node_type_ids: BTreeMap, pub type_envs: Envs, - pub types: BTreeMap, pub node_types: BTreeMap, pub traits: HashMap, // TraitHirId => (Trait, TypeId => Impl) pub trait_methods: HashMap>, @@ -34,6 +34,7 @@ impl Root { .find(|top| top.get_terminal_hir_id() == hir_id) } + #[allow(dead_code)] pub fn get_trait_by_method(&self, ident: String) -> Option { self.traits .iter() @@ -55,11 +56,12 @@ impl Root { }) } + #[allow(dead_code)] pub fn match_trait_method(&self, ident: String, applied_type: &Type) -> Option { let map = self.trait_methods.get(&ident)?; map.iter() - .find(|(sig, _)| *sig.arguments[0] == *applied_type) + .find(|(sig, _)| sig.arguments[0] == *applied_type) .map(|(_, fn_decl)| fn_decl.clone()) } @@ -76,6 +78,7 @@ impl Root { }) } + #[allow(dead_code)] pub fn get_function_by_mangled_name(&self, name: &str) -> Option { self.top_levels .iter() @@ -112,6 +115,7 @@ impl Root { }) } + #[allow(dead_code)] pub fn get_type(&self, hir_id: HirId) -> Option { self.type_envs.get_type(&hir_id).cloned() } @@ -133,7 +137,6 @@ pub struct Mod { pub struct Trait { pub name: Type, pub types: Vec, - // pub impls: HashMap>, pub defs: Vec, } @@ -164,7 +167,7 @@ impl StructDecl { } else { ( proto.name.name.clone(), - Box::new(Type::FuncType(proto.signature.clone())), + Box::new(Type::Func(proto.signature.clone())), ) } }) @@ -183,7 +186,6 @@ pub struct StructCtor { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TopLevel { pub kind: TopLevelKind, - // pub hir_id: HirId, } impl TopLevel { @@ -254,32 +256,10 @@ pub struct IdentifierPath { } impl IdentifierPath { - pub fn parent(&self) -> Self { - let mut parent = self.clone(); - - if parent.path.len() > 1 { - parent.path.pop(); - } - - parent - } - - pub fn child(&self, name: Identifier) -> Self { - let mut child = self.clone(); - - child.path.push(name); - - child - } - pub fn last_segment(&self) -> Identifier { self.path.iter().last().unwrap().clone() } - pub fn last_segment_ref(&self) -> &Identifier { - self.path.iter().last().unwrap() - } - pub fn get_terminal_hir_id(&self) -> HirId { self.last_segment().get_hir_id() } @@ -318,13 +298,6 @@ impl FnBody { hir_id: self.name.hir_id.clone(), }); } - - pub fn get_name(&self) -> Identifier { - match &self.mangled_name { - Some(name) => name.clone(), - None => self.name.clone(), - } - } } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -398,12 +371,6 @@ pub struct If { pub else_: Option>, } -impl If { - pub fn get_terminal_hir_id(&self) -> HirId { - self.hir_id.clone() - } -} - #[derive(Debug, Clone, Serialize, Deserialize)] pub enum Else { If(If), @@ -481,6 +448,8 @@ impl Expression { panic!("Not an identifier"); } } + + #[allow(dead_code)] pub fn as_literal(&self) -> Literal { if let ExpressionKind::Lit(l) = &*self.kind { l.clone() @@ -525,13 +494,11 @@ pub struct FunctionCall { impl FunctionCall { pub fn mangle(&mut self, prefixes: Vec) { - match &mut *self.op.kind { - ExpressionKind::Identifier(id) => { - let identifier = id.path.iter_mut().last().unwrap(); + if let ExpressionKind::Identifier(id) = &mut *self.op.kind { + let identifier = id.path.iter_mut().last().unwrap(); - identifier.name = format!("{}_{}", identifier.name, &prefixes.join("_")); - } - _ => unimplemented!("Need to recurse on expr"), // FIXME: recurse on '(expr)' parenthesis expression + identifier.name = format!("{}_{}", identifier.name, &prefixes.join("_")); + // _ => unimplemented!("Need to recurse on expr {:#?}", self), // FIXME: recurse on '(expr)' parenthesis expression } } diff --git a/src/lib/hir/visit.rs b/src/lib/hir/visit.rs index a56b7f42..06e7ccab 100644 --- a/src/lib/hir/visit.rs +++ b/src/lib/hir/visit.rs @@ -1,59 +1,56 @@ -use concat_idents::concat_idents; +use paste::paste; -use crate::{ast::FuncType, walk_list}; -use crate::{ast::Type, hir::*}; +use crate::{hir::*, ty::*}; macro_rules! generate_visitor_trait { ($( - $name:ident, $method:ident - )*) => { - pub trait Visitor<'ast>: Sized { + $name:ident + )+) => { + pub trait Visitor<'hir>: Sized { fn visit_name(&mut self, _name: &str) {} fn visit_primitive(&mut self, _val: T) {} - $( - concat_idents!(fn_name = visit_, $method { - fn fn_name(&mut self, $method: &'ast $name) { - concat_idents!(fn2_name = walk_, $method { - fn2_name(self, $method); - }); + paste! { + $( + fn [](&mut self, node: &'hir $name) { + [](self, node); } - }); - )* + )+ + } } }; } generate_visitor_trait!( - Root, root - TopLevel, top_level - Trait, r#trait - Impl, r#impl - Assign, assign - AssignLeftSide, assign_left_side - Prototype, prototype - FunctionDecl, function_decl - StructDecl, struct_decl - ArgumentDecl, argument_decl - IdentifierPath, identifier_path - Identifier, identifier - FnBody, fn_body - Body, body - Statement, statement - Expression, expression - If, r#if - Else, r#else - FunctionCall, function_call - StructCtor, struct_ctor - Indice, indice - Dot, dot - Literal, literal - Array, array - NativeOperator, native_operator - Type, r#type - FuncType, func_type + Root + TopLevel + Trait + Impl + Assign + AssignLeftSide + Prototype + FunctionDecl + StructDecl + ArgumentDecl + IdentifierPath + Identifier + FnBody + Body + Statement + Expression + If + Else + FunctionCall + StructCtor + Indice + Dot + Literal + Array + NativeOperator + Type + FuncType ); pub fn walk_root<'a, V: Visitor<'a>>(visitor: &mut V, root: &'a Root) { diff --git a/src/lib/hir/visit_mut.rs b/src/lib/hir/visit_mut.rs index b03c9744..ae4c7dd1 100644 --- a/src/lib/hir/visit_mut.rs +++ b/src/lib/hir/visit_mut.rs @@ -1,59 +1,56 @@ -use concat_idents::concat_idents; +use paste::paste; -use crate::{ast::FuncType, walk_list}; -use crate::{ast::Type, hir::*}; +use crate::{hir::*, ty::*}; macro_rules! generate_visitor_mut_trait { ($( - $name:ident, $method:ident - )*) => { - pub trait VisitorMut<'ast>: Sized { + $name:ident + )+) => { + pub trait VisitorMut<'hir>: Sized { fn visit_name(&mut self, _name: &mut String) {} fn visit_primitive(&mut self, _val: T) {} - $( - concat_idents!(fn_name = visit_, $method { - fn fn_name(&mut self, $method: &'ast mut $name) { - concat_idents!(fn2_name = walk_, $method { - fn2_name(self, $method); - }); + paste! { + $( + fn [](&mut self, node: &'hir mut $name) { + [](self, node); } - }); - )* + )+ + } } }; } generate_visitor_mut_trait!( - Root, root - TopLevel, top_level - Trait, r#trait - Impl, r#impl - Prototype, prototype - FunctionDecl, function_decl - StructDecl, struct_decl - Assign, assign - AssignLeftSide, assign_left_side - ArgumentDecl, argument_decl - IdentifierPath, identifier_path - Identifier, identifier - FnBody, fn_body - Body, body - Statement, statement - Expression, expression - If, r#if - Else, r#else - FunctionCall, function_call - StructCtor, struct_ctor - Indice, indice - Dot, dot - Literal, literal - Array, array - NativeOperator, native_operator - Type, r#type - FuncType, func_type + Root + TopLevel + Trait + Impl + Prototype + FunctionDecl + StructDecl + Assign + AssignLeftSide + ArgumentDecl + IdentifierPath + Identifier + FnBody + Body + Statement + Expression + If + Else + FunctionCall + StructCtor + Indice + Dot + Literal + Array + NativeOperator + Type + FuncType ); pub fn walk_root<'a, V: VisitorMut<'a>>(visitor: &mut V, root: &'a mut Root) { diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index 9254cc64..e2fc21e4 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -1,11 +1,12 @@ use std::collections::BTreeMap; use crate::{ - ast::{resolve::ResolutionMap, FuncType, PrimitiveType, Type}, diagnostics::{Diagnostic, Diagnostics}, hir::visit::*, hir::*, - walk_list, walk_map, Envs, + infer::Envs, + resolver::ResolutionMap, + ty::{FuncType, PrimitiveType, Type}, }; #[derive(Debug)] @@ -24,6 +25,13 @@ impl<'a> ConstraintContext<'a> { } } + pub fn add_tmp_resolution_to_current_fn(&mut self, source: &HirId, dest: &HirId) { + self.tmp_resolutions + .entry(self.envs.get_current_fn().0) + .or_insert_with(ResolutionMap::default) + .insert(source.clone(), dest.clone()); + } + pub fn constraint(&mut self, root: &'a Root) { let entry_point = root.get_function_by_name("main").unwrap(); @@ -34,10 +42,6 @@ impl<'a> ConstraintContext<'a> { return; } - self.tmp_resolutions - .entry(entry_point.hir_id.clone()) - .or_insert_with(ResolutionMap::default); - self.visit_function_decl(&entry_point); } @@ -47,10 +51,9 @@ impl<'a> ConstraintContext<'a> { pub fn resolve(&self, id: &HirId) -> Option { self.hir.resolutions.get(id).or_else(|| { - match self.tmp_resolutions.get(&self.envs.get_current_fn().0) { - Some(env) => env.get(id), - None => None, - } + self.tmp_resolutions + .get(&self.envs.get_current_fn().0) + .and_then(|env| env.get(id)) }) } @@ -59,55 +62,70 @@ impl<'a> ConstraintContext<'a> { .and_then(|reso| self.resolve_rec(&reso).or(Some(reso))) } + pub fn resolve_and_get(&self, hir: &HirId) -> Option<&HirNode> { + self.hir + .arena + .get( + &self + .resolve(hir) + .or_else(|| panic!("NO RESO FOR {:?}", hir))?, + ) + .or_else(|| panic!("NO ARENA ITEM FOR {:?}", hir)) + } + // FIXME: This is ugly pub fn setup_call(&mut self, fc: &FunctionCall, call_hir_id: &HirId) { - if let Some(top_id) = self.resolve(call_hir_id) { - if let Some(reso) = self.hir.arena.get(&top_id) { - match reso { - HirNode::Prototype(p) => { - if let Some(existing_impls) = self.hir.trait_methods.get(&p.name.name) { - if let Some(f) = self.hir.get_trait_method( - (*p.name).clone(), - &fc.to_func_type(self.envs.get_current_env().unwrap()) - .merge_with(&p.signature), - ) { - self.setup_trait_call(fc, &f); - } else { + self.resolve_and_get(call_hir_id) + .cloned() + .and_then(|reso| match reso { + HirNode::Prototype(p) => self + .hir + .trait_methods + .get(&p.name.name) + .or_else(|| { + self.setup_prototype_call(fc, &p); + + None + }) + .and_then(|existing_impls| { + let new_sig = fc + .to_func_type(self.envs.get_current_env().unwrap()) + .merge_with(&p.signature); + + self.hir + .get_trait_method(p.name.name.clone(), &new_sig) + .or_else(|| { self.envs.diagnostics.push_error( Diagnostic::new_unresolved_trait_call( self.envs.spans.get(&call_hir_id.clone()).unwrap().clone(), call_hir_id.clone(), - fc.to_func_type(self.envs.get_current_env().unwrap()) - .merge_with(&p.signature), + new_sig, existing_impls.keys().cloned().collect(), ), ); - } - } else { - self.setup_prototype_call(fc, p); - } - } - HirNode::FunctionDecl(f) => { - self.setup_function_call(fc, f); - } - HirNode::Identifier(id) => { - self.setup_identifier_call(fc, id); - } - _ => unimplemented!("Cannot call {:#?}", reso), + + None + }) + }) + .map(|f| { + self.setup_trait_call(fc, &f); + }), + HirNode::FunctionDecl(f) => { + self.setup_function_call(fc, &f); + + Some(()) } - } else { - panic!("NO ARENA ITEM FOR HIR={:?}", top_id); - } - } else { - panic!("No reso hir_id: {:#?}", call_hir_id); - } + HirNode::Identifier(id) => { + self.setup_identifier_call(fc, &id); + + Some(()) + } + _ => unimplemented!("Cannot call {:#?}", reso), + }); } pub fn setup_trait_call(&mut self, fc: &FunctionCall, f: &FunctionDecl) { - self.tmp_resolutions - .get_mut(&self.envs.get_current_fn().0) - .unwrap() - .insert(fc.op.get_hir_id(), f.hir_id.clone()); + self.add_tmp_resolution_to_current_fn(&fc.op.get_hir_id(), &f.hir_id); self.setup_function_call(fc, f); } @@ -135,21 +153,20 @@ impl<'a> ConstraintContext<'a> { self.envs.set_type(&fc.get_hir_id(), &p.signature.ret); self.envs - .set_type(&fc.op.get_hir_id(), &Type::FuncType(p.signature.clone())); + .set_type(&fc.op.get_hir_id(), &Type::Func(p.signature.clone())); } + // FIXME: This is ugly as well pub fn setup_function_call(&mut self, fc: &FunctionCall, f: &FunctionDecl) { if f.signature.arguments.len() != fc.args.len() { self.envs .diagnostics .push_error(Diagnostic::new_type_conflict( self.envs.spans.get(&fc.op.get_hir_id()).unwrap().clone(), - fc.to_func_type(self.envs.get_current_env().unwrap()) - .to_type(), - f.signature.to_type(), - fc.to_func_type(self.envs.get_current_env().unwrap()) - .to_type(), - f.signature.to_type(), + fc.to_func_type(self.envs.get_current_env().unwrap()).into(), + f.signature.clone().into(), + fc.to_func_type(self.envs.get_current_env().unwrap()).into(), + f.signature.clone().into(), )); return; @@ -177,9 +194,9 @@ impl<'a> ConstraintContext<'a> { .or_insert_with(ResolutionMap::default) .insert(arg.get_hir_id(), f2.hir_id.clone()); - self.envs.set_type(arg_id, &f.signature.to_type()); + self.envs.set_type(arg_id, &f.signature.clone().into()); - Some(f.signature.to_type()) + Some(f.signature.clone().into()) } else { None } @@ -198,19 +215,13 @@ impl<'a> ConstraintContext<'a> { .diagnostics .push_error(Diagnostic::new_type_conflict( self.envs.spans.get(&fc.op.get_hir_id()).unwrap().clone(), - fc.to_func_type(self.envs.get_current_env().unwrap()) - .to_type(), - sig.to_type(), - fc.to_func_type(self.envs.get_current_env().unwrap()) - .to_type(), - sig.to_type(), + fc.to_func_type(self.envs.get_current_env().unwrap()).into(), + sig.clone().into(), + fc.to_func_type(self.envs.get_current_env().unwrap()).into(), + sig.clone().into(), )); + return; - // panic!( - // "BAD CALL {:#?} {:#?}", - // fc.to_func_type(self.envs.get_current_env().unwrap()), - // sig - // ); } // Carring about recursion @@ -223,7 +234,7 @@ impl<'a> ConstraintContext<'a> { &self.hir.bodies.get(&f.body_id).unwrap().get_hir_id(), ); - self.envs.set_type(&fc.op.get_hir_id(), &sig.to_type()); + self.envs.set_type(&fc.op.get_hir_id(), &sig.into()); return; } @@ -257,12 +268,8 @@ impl<'a> ConstraintContext<'a> { // Get the func return type either // if it has been defined by the callee // or we take the sig's one - let new_f_ret = if let Type::FuncType(new_f_type_inner) = &new_f_type.clone() { - new_f_arg_types = new_f_type_inner - .arguments - .iter() - .map(|arg| *arg.clone()) - .collect(); + let new_f_ret = if let Type::Func(new_f_type_inner) = &new_f_type.clone() { + new_f_arg_types = new_f_type_inner.arguments.to_vec(); new_f_sig = new_f_type_inner.clone(); *new_f_type_inner.ret.clone() @@ -311,14 +318,13 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { fn visit_function_decl(&mut self, f: &'a FunctionDecl) { self.envs.apply_args_type(f); - // walk_function_decl(self, f); walk_list!(self, visit_argument_decl, &f.arguments); self.visit_fn_body(self.hir.get_body(&f.body_id).unwrap()); self.envs.set_type( &f.hir_id, - &Type::FuncType(FuncType::new( + &Type::Func(FuncType::new( f.arguments .iter() .map(|arg| self.envs.get_type(&arg.get_hir_id()).unwrap()) @@ -334,31 +340,25 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { self.envs.set_type_eq(&f.name.hir_id, &f.hir_id); - self.tmp_resolutions - .get_mut(&self.envs.get_current_fn().0) - .unwrap() - .insert(f.name.hir_id.clone(), f.hir_id.clone()); + self.add_tmp_resolution_to_current_fn(&f.name.hir_id, &f.hir_id); } fn visit_prototype(&mut self, p: &Prototype) { if p.signature.is_solved() { - self.envs.set_type(&p.hir_id, &p.signature.to_type()); + self.envs.set_type(&p.hir_id, &p.signature.clone().into()); } - self.tmp_resolutions - .get_mut(&self.envs.get_current_fn().0) - .unwrap() - .insert(p.name.hir_id.clone(), p.hir_id.clone()); + self.add_tmp_resolution_to_current_fn(&p.name.hir_id, &p.hir_id); walk_prototype(self, p); } fn visit_struct_decl(&mut self, s: &StructDecl) { - let t = s.to_type(); + let t = s.into(); self.envs.set_type(&s.hir_id, &t); - let struct_t = t.into_struct_type(); + let struct_t = t.as_struct_type(); s.defs.iter().for_each(|p| { self.envs @@ -371,17 +371,30 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { self.visit_struct_decl(s_decl); - let t = s_decl.to_type(); + let t = s_decl.into(); self.envs.set_type(&s.hir_id, &t); - let struct_t = t.into_struct_type(); + let struct_t = t.as_struct_type(); walk_map!(self, visit_expression, &s.defs); s.defs.iter().for_each(|(k, expr)| { - self.envs - .set_type(&expr.get_hir_id(), struct_t.defs.get(&k.name).unwrap()); + let declared_type = struct_t.defs.get(&k.name).unwrap(); + + declared_type.is_func().then(|| { + self.envs.get_type(&expr.get_hir_id()).cloned().or_else(|| { + if let HirNode::FunctionDecl(f2) = + self.hir.arena.get(&self.resolve(&expr.get_hir_id())?)? + { + self.add_tmp_resolution_to_current_fn(&k.get_hir_id(), &f2.hir_id); + } + + None + }); + }); + + self.envs.set_type(&expr.get_hir_id(), declared_type); }); } @@ -454,9 +467,8 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { }; self.envs - .set_type(&left.hir_id.clone(), &Type::Primitive(arg_t.clone())); - self.envs - .set_type(&right.hir_id.clone(), &Type::Primitive(arg_t)); + .set_type(&left.hir_id.clone(), &arg_t.clone().into()); + self.envs.set_type(&right.hir_id.clone(), &arg_t.into()); self.visit_native_operator(op); } @@ -531,6 +543,12 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { self.envs .set_type(&d.get_hir_id(), struct_t.defs.get(&d.value.name).unwrap()); + + if let Type::Func(_ft) = &**struct_t.defs.get(&d.value.name).unwrap() { + let resolved = self.resolve(&d.value.get_hir_id()).unwrap(); + + self.add_tmp_resolution_to_current_fn(&d.get_hir_id(), &resolved); + } } other => { let value_t = self.envs.get_type(&d.value.get_hir_id()).unwrap().clone(); @@ -624,7 +642,7 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { | NativeOperatorKind::FMul => PrimitiveType::Float64, }; - self.envs.set_type(&op.hir_id, &Type::Primitive(t)); + self.envs.set_type(&op.hir_id, &t.into()); } } diff --git a/src/lib/infer/mangle.rs b/src/lib/infer/mangle.rs index 385cb844..2404aabd 100644 --- a/src/lib/infer/mangle.rs +++ b/src/lib/infer/mangle.rs @@ -1,6 +1,6 @@ use std::collections::BTreeMap; -use crate::{ast::Type, hir::visit_mut::*, hir::*, walk_list}; +use crate::{hir::visit_mut::*, hir::*, ty::Type}; #[derive(Debug)] pub struct MangleContext { @@ -11,7 +11,7 @@ impl<'a> VisitorMut<'a> for MangleContext { fn visit_function_decl(&mut self, f: &'a mut FunctionDecl) { let t = self.node_types.get(&f.hir_id).unwrap(); - if let Type::FuncType(f_t) = t { + if let Type::Func(f_t) = t { f.mangle(f_t.to_prefixes()); } else { panic!("Not a function {:?}", t); @@ -21,7 +21,7 @@ impl<'a> VisitorMut<'a> for MangleContext { fn visit_function_call(&mut self, fc: &'a mut FunctionCall) { let t = self.node_types.get(&fc.op.get_hir_id()).unwrap(); - if let Type::FuncType(f_t) = t { + if let Type::Func(f_t) = t { fc.mangle(f_t.to_prefixes()); self.visit_expression(&mut fc.op); diff --git a/src/lib/infer/monomorphize/mod.rs b/src/lib/infer/monomorphize/mod.rs index 995911ac..758e512f 100644 --- a/src/lib/infer/monomorphize/mod.rs +++ b/src/lib/infer/monomorphize/mod.rs @@ -1,8 +1,8 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ - ast::resolve::ResolutionMap, hir::{HirId, Root}, + resolver::ResolutionMap, }; use self::monomorphizer::Monomorphizer; diff --git a/src/lib/infer/monomorphize/monomorphizer.rs b/src/lib/infer/monomorphize/monomorphizer.rs index ac668109..72d923bf 100644 --- a/src/lib/infer/monomorphize/monomorphizer.rs +++ b/src/lib/infer/monomorphize/monomorphizer.rs @@ -1,10 +1,11 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ - ast::{resolve::ResolutionMap, FuncType, Type}, hir::visit_mut::*, hir::*, - Env, + infer::Env, + resolver::ResolutionMap, + ty::{FuncType, Type}, }; #[derive(Debug)] @@ -43,14 +44,12 @@ impl<'a> Monomorphizer<'a> { for top in &prototypes { if let TopLevelKind::Prototype(p) = &top.kind { - let f_type = p.signature.clone(); + let f_type: Type = p.signature.clone().into(); self.root .node_types - .insert(p.hir_id.clone(), Type::FuncType(f_type.clone())); - self.root - .node_types - .insert(p.name.hir_id.clone(), Type::FuncType(f_type.clone())); + .insert(p.hir_id.clone(), f_type.clone()); + self.root.node_types.insert(p.name.hir_id.clone(), f_type); } } @@ -315,7 +314,7 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { HirNode::Prototype(p) => { let f_type = self.root.type_envs.get_type(&old_fc_op).unwrap(); - if let Type::FuncType(f_type) = f_type { + if let Type::Func(f_type) = f_type { // Traits if let Some(f) = self.root.get_trait_method((*p.name).clone(), f_type) { if let Some(trans_res) = self.trans_resolutions.get(&f.hir_id) { @@ -327,10 +326,6 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { fc.op.get_hir_id(), f.hir_id, ); - // self.new_resolutions.insert( - // fc.op.get_hir_id(), - // self.resolve(&f.hir_id.clone()).unwrap(), - // ); } // Extern Prototypes } else { @@ -344,12 +339,12 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { _ => { // FIXME: This may be bad // self.new_resolutions - // .insert(fc.op.get_hir_id(), self.resolve_rec(&old_fc_op).unwrap()); + // .insert(fc.op.get_hir_id(), self.resolve_rec(&old_fc_op).unwrap()); } } for (i, arg) in fc.args.iter().enumerate() { - if let Type::FuncType(f) = self.root.node_types.get(&arg.get_hir_id()).unwrap() { + if let Type::Func(f) = self.root.node_types.get(&arg.get_hir_id()).unwrap() { if let Some(reso) = self.resolve(old_fc_args.get(i).unwrap()) { self.new_resolutions.insert( arg.get_hir_id(), @@ -362,7 +357,7 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { println!("NO RESO FOR {:#?}", arg.get_hir_id()) } - self.trans_resolutions.remove(&old_fc_args.get(i).unwrap()); + self.trans_resolutions.remove(old_fc_args.get(i).unwrap()); } } } @@ -415,7 +410,7 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { s.defs.iter().for_each(|p| { let t = *s .to_type() - .into_struct_type() + .as_struct_type() .defs .get(&p.name.name) .unwrap() @@ -443,7 +438,36 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { self.trans_resolutions.insert(old_hir_id, s.hir_id.clone()); - walk_struct_ctor(self, s); + self.visit_type(&mut s.name); + + s.defs = s + .defs + .iter_mut() + .map(|(old_k, def)| { + let mut k = old_k.clone(); + self.visit_identifier(&mut k); + let old_def_id = def.get_hir_id(); + self.visit_expression(def); + + if let Type::Func(ft) = self.root.node_types.get(&def.get_hir_id()).unwrap() { + if let Some(reso) = self.resolve(&old_def_id) { + if let HirNode::FunctionDecl(_f2) = self.root.arena.get(&reso).unwrap() { + self.new_resolutions.insert( + def.get_hir_id(), + self.generated_fn_hir_id + .get(&(reso, ft.clone())) + .unwrap() + .clone(), + ); + + self.trans_resolutions.remove(&old_def_id); + } else { + } + } + } + (k, def.clone()) + }) + .collect(); } fn visit_identifier(&mut self, id: &'a mut Identifier) { diff --git a/src/lib/infer/state.rs b/src/lib/infer/state.rs index b817f1a6..d25e3647 100644 --- a/src/lib/infer/state.rs +++ b/src/lib/infer/state.rs @@ -1,16 +1,12 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ - ast::{FuncType, Type}, diagnostics::{Diagnostic, Diagnostics}, hir::*, parser::Span, + ty::*, }; -pub type NodeId = u64; - -pub type TypeId = u64; - pub type Env = BTreeMap; #[derive(Debug, Default, Clone)] @@ -79,7 +75,7 @@ impl Envs { .insert(dest.clone(), src.clone()); match (src, previous.clone()) { - (Type::FuncType(src_f), Some(Type::FuncType(prev_f))) if !src_f.eq(&prev_f) => { + (Type::Func(src_f), Some(Type::Func(prev_f))) if !src_f.eq(&prev_f) => { if prev_f.is_solved() && src_f.is_solved() { self.diagnostics.push_error(Diagnostic::new_type_conflict( self.spans.get(dest).unwrap().clone(), @@ -126,6 +122,7 @@ impl Envs { }); } + #[allow(dead_code)] pub fn get_fn_types(&self, f: &HirId) -> Option<&HashMap> { self.fns.get(f) } @@ -134,6 +131,7 @@ impl Envs { &self.fns } + #[allow(dead_code)] pub fn add_empty(&mut self, hir_id: &HirId) { self.fns.entry(hir_id.clone()).or_insert_with(HashMap::new); } diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index 8a5e5ea4..792035fd 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -53,11 +53,11 @@ pub fn parse_root(ctx: &mut ParsingCtx) -> Result let (mut ast, tokens) = parse_generic(ctx, |p| p.run_root())?; - ast.r#mod.tokens = tokens.clone(); + ast.r#mod.tokens = tokens; // Debug ast if ctx.config.show_ast { - AstPrintContext::new(tokens, ctx.get_current_file()).visit_root(&ast); + AstPrintContext::new().visit_root(&ast); } Ok(ast) @@ -74,11 +74,11 @@ pub fn parse_mod(name: String, ctx: &mut ParsingCtx) -> Result Result<(), Diagnostic> { let mut scopes = HashMap::new(); @@ -32,20 +30,9 @@ pub fn resolve(root: &mut Root, parsing_ctx: &mut ParsingCtx) -> Result<(), Diag root.resolutions = ctx.resolutions; - // find unused functions here and mark them as such to let them pass infer (to avoid crash) - let mut unused_ctx = UnusedCollector::new(root.resolutions.clone()); - - unused_ctx.visit_root(root); - - let (mut unused_fns, unused_methods) = unused_ctx.take_unused(); + let (mut unused_fns, unused_methods) = unused_collector::collect_unused(root); - // println!("unused {:?}", unused); - - let mut span_collector = SpanCollector::new(); - - span_collector.visit_root(root); - - root.spans = span_collector.take_list(); + root.spans = span_collector::collect_spans(root); for unused_fn in &unused_fns { let span = root.spans.get(unused_fn).unwrap(); @@ -57,7 +44,5 @@ pub fn resolve(root: &mut Root, parsing_ctx: &mut ParsingCtx) -> Result<(), Diag unused_fns.extend(unused_methods); - // root.r#mod.filter_unused_top_levels(unused_fns); - parsing_ctx.return_if_error() } diff --git a/src/lib/ast/resolve/resolution_map.rs b/src/lib/resolver/resolution_map.rs similarity index 94% rename from src/lib/ast/resolve/resolution_map.rs rename to src/lib/resolver/resolution_map.rs index b56a1446..adb652b1 100644 --- a/src/lib/ast/resolve/resolution_map.rs +++ b/src/lib/resolver/resolution_map.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{ast_lowering::HirMap, hir::HirId, NodeId}; +use crate::{ast::NodeId, ast_lowering::HirMap, hir::HirId}; #[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct ResolutionMap(HashMap) @@ -34,6 +34,7 @@ impl ResolutionMap { self.0.clone() } + #[allow(dead_code)] pub fn clear(&mut self) { self.0.clear() } diff --git a/src/lib/ast/resolve/resolve_ctx.rs b/src/lib/resolver/resolve_ctx.rs similarity index 96% rename from src/lib/ast/resolve/resolve_ctx.rs rename to src/lib/resolver/resolve_ctx.rs index 354ab57d..c65f6bbf 100644 --- a/src/lib/ast/resolve/resolve_ctx.rs +++ b/src/lib/resolver/resolve_ctx.rs @@ -1,9 +1,11 @@ use std::collections::HashMap; -use crate::walk_list; use crate::{ - ast::resolve::ResolutionMap, ast::visit::*, ast::*, diagnostics::Diagnostic, - helpers::scopes::*, parser::ParsingCtx, NodeId, + ast::{visit::*, *}, + diagnostics::Diagnostic, + helpers::scopes::*, + parser::ParsingCtx, + resolver::ResolutionMap, }; #[derive(Debug)] @@ -134,9 +136,7 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { fn visit_struct_decl(&mut self, s: &'a StructDecl) { self.push_scope(); - // walk_list!(visitor, visit_prototype, &s.defs); - // s.defs.iter().for_each(|proto| {}); walk_struct_decl(self, s); self.pop_scope() @@ -151,6 +151,8 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { .push_error(Diagnostic::new_unknown_identifier(s.identity.span.clone())), }; + self.visit_type(&s.name); + walk_struct_ctor(self, s); } diff --git a/src/lib/ast/resolve/unused_collector.rs b/src/lib/resolver/unused_collector.rs similarity index 92% rename from src/lib/ast/resolve/unused_collector.rs rename to src/lib/resolver/unused_collector.rs index d9f6f5fb..fa856025 100644 --- a/src/lib/ast/resolve/unused_collector.rs +++ b/src/lib/resolver/unused_collector.rs @@ -1,8 +1,6 @@ use std::collections::HashMap; -use crate::NodeId; -use crate::{ast::resolve::ResolutionMap, ast::visit::*}; -use crate::{ast::*, walk_list}; +use crate::{ast::*, resolver::ResolutionMap}; #[derive(Debug, Default)] pub struct UnusedCollector { @@ -100,3 +98,11 @@ impl<'a> Visitor<'a> for UnusedCollector { } } } + +pub fn collect_unused(root: &Root) -> (Vec, Vec) { + let mut unused_collector = UnusedCollector::new(root.resolutions.clone()); + + unused_collector.visit_root(root); + + unused_collector.take_unused() +} diff --git a/src/lib/rock.rs b/src/lib/rock.rs index df81254d..4527a541 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -8,45 +8,39 @@ extern crate bitflags; #[macro_use] extern crate log; -#[macro_use] -extern crate concat_idents; + +use std::path::PathBuf; #[macro_use] -pub mod ast; +mod helpers; + #[macro_use] -pub mod infer; +mod ast; #[macro_use] -pub mod helpers; - -use std::path::PathBuf; +mod infer; -use diagnostics::Diagnostic; -use parser::{ParsingCtx, SourceFile}; - -// use crate::helpers::config::PackageMetaData; -pub use crate::infer::*; mod ast_lowering; mod codegen; pub mod diagnostics; mod hir; mod parser; +mod resolver; mod tests; +mod ty; -pub use crate::helpers::config::Config; +use diagnostics::Diagnostic; +pub use helpers::config::Config; +use parser::{ParsingCtx, SourceFile}; -pub fn parse_file(in_name: String, out_name: String, config: &Config) -> Result<(), Diagnostic> { +pub fn parse_file(in_name: String, config: &Config) -> Result<(), Diagnostic> { let mut source_file = SourceFile::from_file(in_name)?; source_file.mod_path = PathBuf::from("root"); - parse_str(&source_file, out_name, config) + parse_str(&source_file, config) } -pub fn parse_str( - input: &SourceFile, - _output_name: String, - config: &Config, -) -> Result<(), Diagnostic> { +pub fn parse_str(input: &SourceFile, config: &Config) -> Result<(), Diagnostic> { let mut parsing_ctx = ParsingCtx::new(config); parsing_ctx.add_file(input); @@ -57,7 +51,7 @@ pub fn parse_str( // Name resolving debug!(" -> Resolving"); - ast::resolve(&mut ast, &mut parsing_ctx)?; + resolver::resolve(&mut ast, &mut parsing_ctx)?; // Lowering to HIR debug!(" -> Lowering to HIR"); @@ -71,17 +65,12 @@ pub fn parse_str( debug!(" -> Lower to LLVM IR"); let parsing_ctx = codegen::generate(config, parsing_ctx, new_hir)?; - // debug!(" -> Save MetaData"); - // PackageMetaData { hir } - // .store(&PathBuf::from("/tmp/test.serde")) - // .unwrap(); - parsing_ctx.print_success_diagnostics(); Ok(()) } -pub mod test { +mod test { use super::*; use crate::{parser::SourceFile, Config}; use std::{ @@ -97,7 +86,7 @@ pub mod test { content: input, }; - if let Err(_e) = parse_str(&file, "main".to_string(), &config) { + if let Err(_e) = parse_str(&file, &config) { return false; } diff --git a/src/lib/testcases/basic/struct_array_field/main.rk b/src/lib/testcases/basic/struct_array_field/main.rk new file mode 100644 index 00000000..39c83411 --- /dev/null +++ b/src/lib/testcases/basic/struct_array_field/main.rk @@ -0,0 +1,11 @@ +struct Foo + toto :: [Int64] + titi :: Float64 + +main = + let lol = + Foo + titi: 10.2 + toto: [10, 42] + + lol.toto[1] diff --git a/src/lib/testcases/basic/struct_array_field/main.rk.out b/src/lib/testcases/basic/struct_array_field/main.rk.out new file mode 100644 index 00000000..f70d7bba --- /dev/null +++ b/src/lib/testcases/basic/struct_array_field/main.rk.out @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/lib/testcases/basic/struct_array_field/main.rk.stdout b/src/lib/testcases/basic/struct_array_field/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/tests.rs b/src/lib/tests.rs index 727888f1..c679ba61 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -130,6 +130,10 @@ fn testcases_basic_bool_false_main() { run("testcases/basic/bool_false/main.rk", include_str!("testcases/basic/bool_false/main.rk"), include_str!("testcases/basic/bool_false/main.rk.out"), include_str!("testcases/basic/bool_false/main.rk.stdout")); } #[test] +fn testcases_basic_struct_array_field_main() { + run("testcases/basic/struct_array_field/main.rk", include_str!("testcases/basic/struct_array_field/main.rk"), include_str!("testcases/basic/struct_array_field/main.rk.out"), include_str!("testcases/basic/struct_array_field/main.rk.stdout")); +} +#[test] fn testcases_basic_main_main() { run("testcases/basic/main/main.rk", include_str!("testcases/basic/main/main.rk"), include_str!("testcases/basic/main/main.rk.out"), include_str!("testcases/basic/main/main.rk.stdout")); } diff --git a/src/lib/ast/type.rs b/src/lib/ty/func_type.rs similarity index 53% rename from src/lib/ast/type.rs rename to src/lib/ty/func_type.rs index 3aaee532..d4261178 100644 --- a/src/lib/ast/type.rs +++ b/src/lib/ty/func_type.rs @@ -1,103 +1,11 @@ use colored::*; -use std::{collections::BTreeMap, fmt}; +use std::fmt; -use crate::ast::PrimitiveType; - -#[derive(Clone, Eq, Serialize, Deserialize)] -pub enum Type { - Primitive(PrimitiveType), - FuncType(FuncType), - Struct(StructType), - Trait(String), - ForAll(String), - Undefined(u64), // FIXME: To remove -} - -impl std::hash::Hash for Type { - fn hash(&self, state: &mut H) { - core::mem::discriminant(self).hash(state); - } -} - -impl PartialEq for Type { - fn eq(&self, other: &Type) -> bool { - self.get_name() == other.get_name() - } -} - -impl Type { - pub fn int64() -> Self { - Self::Primitive(PrimitiveType::Int64) - } - - pub fn forall(t: &str) -> Self { - Self::ForAll(String::from(t)) - } - - pub fn is_solved(&self) -> bool { - match self { - Type::Primitive(p) => p.is_solved(), - Type::FuncType(ft) => ft.is_solved(), - Type::Struct(_) => true, - Type::Trait(_) => true, - Type::ForAll(_) => false, - Type::Undefined(_) => false, - } - } - - pub fn get_name(&self) -> String { - match self { - Self::Primitive(p) => p.get_name(), - Self::FuncType(_f) => String::from("(fn)"), - Self::Struct(s) => s.name.clone(), - Self::Trait(t) => t.clone(), - Self::ForAll(n) => String::from(n), - Self::Undefined(s) => s.to_string(), - } - } - - pub fn is_forall(&self) -> bool { - matches!(self, Self::ForAll(_x)) - } - - pub fn into_struct_type(&self) -> StructType { - if let Type::Struct(t) = self { - t.clone() - } else { - panic!("Not a struct type"); - } - } - - pub fn into_func_type(&self) -> FuncType { - if let Type::FuncType(f) = self { - f.clone() - } else { - panic!("Not a func type"); - } - } -} - -impl fmt::Debug for Type { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - let s = match self { - Self::FuncType(f) => format!("{:?}", f), - Self::Struct(s) => format!("{:?}", s), - _ => self.get_name().cyan().to_string(), - }; - - write!(f, "{}", s) - } -} - -impl fmt::Display for Type { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - write!(f, "{}", self.get_name()) - } -} +use super::Type; #[derive(Clone, Eq, Serialize, Deserialize)] pub struct FuncType { - pub arguments: Vec>, + pub arguments: Vec, pub ret: Box, } @@ -140,7 +48,7 @@ impl fmt::Debug for FuncType { impl FuncType { pub fn new(arguments: Vec, ret: Type) -> Self { Self { - arguments: arguments.into_iter().map(Box::new).collect(), + arguments: arguments.into_iter().collect(), ret: Box::new(ret), } } @@ -185,9 +93,9 @@ impl FuncType { match orig .iter() .enumerate() - .find(|(_, orig_t)| **orig_t == **arg_t) + .find(|(_, orig_t)| **orig_t == *arg_t) { - Some((i, _orig_t)) => Box::new(dest[i].clone()), + Some((i, _orig_t)) => dest[i].clone(), None => arg_t.clone(), } }) @@ -209,28 +117,27 @@ impl FuncType { } fn collect_forall_types(&self, arguments: Vec, ret: Type) -> (Vec, Vec) { - let mut orig = vec![]; - let mut dest = vec![]; - - self.arguments.iter().enumerate().for_each(|(i, arg_t)| { - if !arg_t.is_forall() { - warn!("Trying to apply type to a not forall"); + let (mut orig, mut dest): (Vec<_>, Vec<_>) = self + .arguments + .iter() + .enumerate() + .filter_map(|(i, arg_t)| -> Option<(Type, Type)> { + if !arg_t.is_forall() { + warn!("Trying to apply type to a not forall"); - return; - } + return None; + } - if let Some(t) = arguments.get(i) { - orig.push((**arg_t).clone()); - dest.push((*t).clone()); - } - }); + arguments.get(i).map(|t| (arg_t.clone(), t.clone())) + }) + .unzip(); if !ret.is_forall() { warn!("Trying to apply type to a not forall"); } // FIXME: must remplace all occurences of ret - orig.push((*self.ret).clone()); + orig.push(*self.ret.clone()); dest.push(ret); (orig, dest) @@ -241,25 +148,26 @@ impl FuncType { arguments: &[Option], ret: Option, ) -> (Vec, Vec) { - let mut orig = vec![]; - let mut dest = vec![]; - - self.arguments.iter().enumerate().for_each(|(i, arg_t)| { - if !arg_t.is_forall() { - warn!("Trying to apply type to a not forall"); + let (mut orig, mut dest): (Vec<_>, Vec<_>) = self + .arguments + .iter() + .enumerate() + .filter_map(|(i, arg_t)| -> Option<(Type, Type)> { + if !arg_t.is_forall() { + warn!("Trying to apply type to a not forall"); - return; - } + return None; + } - if let Some(t) = arguments.get(i).unwrap() { - orig.push(*arg_t.clone()); - dest.push(t.clone()); - } - }); + arguments + .get(i)? + .as_ref() + .map(|t| (arg_t.clone(), t.clone())) + }) + .unzip(); if let Some(t) = ret { if !t.is_forall() { - // panic!("Trying to apply type to a not forall") warn!("Trying to apply type to a not forall"); } @@ -279,19 +187,17 @@ impl FuncType { .iter() .enumerate() .map(|(i, arg)| { - if let Type::FuncType(f_t) = &**arg { - Box::new( - f_t.merge_with(&arguments.get(i).unwrap().into_func_type()) - .to_type(), - ) + if let Type::Func(f_t) = arg { + f_t.merge_with(&arguments.get(i).unwrap().as_func_type()) + .into() } else { - (*arg).clone() + arg.clone() } }) .collect::>(); - resolved.ret = if let Type::FuncType(f_t) = &*self.ret { - Box::new(f_t.merge_with(&ret.into_func_type()).to_type()) + resolved.ret = if let Type::Func(f_t) = &*self.ret { + Box::new(f_t.merge_with(&ret.as_func_type()).into()) } else { self.ret.clone() }; @@ -309,21 +215,18 @@ impl FuncType { .iter() .enumerate() .map(|(i, arg)| { - if let Type::FuncType(f_t) = &**arg { - let inner = arguments.get(i).unwrap().as_ref().unwrap().into_func_type(); + if let Type::Func(f_t) = arg { + let inner = arguments.get(i).unwrap().as_ref().unwrap().as_func_type(); - Box::new(f_t.merge_with(&inner).to_type()) + f_t.merge_with(&inner).into() } else { - (*arg).clone() + arg.clone() } }) .collect::>(); - resolved.ret = if let Type::FuncType(f_t) = &*self.ret { - Box::new( - f_t.merge_with(&ret.as_ref().unwrap().into_func_type()) - .to_type(), - ) + resolved.ret = if let Type::Func(f_t) = &*self.ret { + Box::new(f_t.merge_with(&ret.as_ref().unwrap().as_func_type()).into()) } else { self.ret.clone() }; @@ -340,7 +243,7 @@ impl FuncType { new.arguments = forall_generator .clone() .take(nb) - .map(|n| Box::new(Type::ForAll(n.to_string()))) + .map(|n| Type::ForAll(n.to_string())) .collect(); new.ret = Box::new(Type::ForAll(forall_generator.nth(nb).unwrap().to_string())); @@ -364,41 +267,10 @@ impl FuncType { pub fn merge_with(&self, other: &Self) -> Self { self.apply_types( - other.arguments.iter().map(|b| (**b).clone()).collect(), + other.arguments.iter().map(|b| (*b).clone()).collect(), *other.ret.clone(), ) } - - pub fn to_type(&self) -> Type { - Type::FuncType(self.clone()) - } -} - -#[derive(Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] -pub struct StructType { - pub name: String, - pub defs: BTreeMap>, -} - -impl fmt::Debug for StructType { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!( - f, - "{} {} {} {}", - self.name.yellow(), - "{".green(), - self.defs - .iter() - .map(|(n, b)| format!("{}: {:?}", n, b)) - .collect::>() - .join(", "), - "}".green(), - ) - } -} - -impl StructType { - // pub fn } #[cfg(test)] @@ -409,8 +281,8 @@ mod tests { fn basic_type_signature() { let sig = FuncType::from_args_nb(2); - assert_eq!(*sig.arguments[0], Type::forall("a")); - assert_eq!(*sig.arguments[1], Type::forall("b")); + assert_eq!(sig.arguments[0], Type::forall("a")); + assert_eq!(sig.arguments[1], Type::forall("b")); assert_eq!(*sig.ret, Type::forall("c")); } @@ -420,8 +292,8 @@ mod tests { let res = sig.apply_forall_types(&vec![Type::forall("b")], &vec![Type::int64()]); - assert_eq!(*res.arguments[0], Type::forall("a")); - assert_eq!(*res.arguments[1], Type::int64()); + assert_eq!(res.arguments[0], Type::forall("a")); + assert_eq!(res.arguments[1], Type::int64()); assert_eq!(*res.ret, Type::forall("c")); } @@ -431,8 +303,8 @@ mod tests { let res = sig.apply_types(vec![Type::int64()], Type::int64()); - assert_eq!(*res.arguments[0], Type::int64()); - assert_eq!(*res.arguments[1], Type::forall("b")); + assert_eq!(res.arguments[0], Type::int64()); + assert_eq!(res.arguments[1], Type::forall("b")); assert_eq!(*res.ret, Type::int64()); } @@ -442,8 +314,8 @@ mod tests { let res = sig.apply_partial_types(&vec![None, Some(Type::int64())], Some(Type::int64())); - assert_eq!(*res.arguments[0], Type::forall("a")); - assert_eq!(*res.arguments[1], Type::int64()); + assert_eq!(res.arguments[0], Type::forall("a")); + assert_eq!(res.arguments[1], Type::int64()); assert_eq!(*res.ret, Type::int64()); } } diff --git a/src/lib/ty/mod.rs b/src/lib/ty/mod.rs new file mode 100644 index 00000000..c5c02cce --- /dev/null +++ b/src/lib/ty/mod.rs @@ -0,0 +1,9 @@ +mod func_type; +mod primitive_type; +mod struct_type; +mod r#type; + +pub use func_type::*; +pub use primitive_type::*; +pub use r#type::*; +pub use struct_type::*; diff --git a/src/lib/ast/primitive_type.rs b/src/lib/ty/primitive_type.rs similarity index 62% rename from src/lib/ast/primitive_type.rs rename to src/lib/ty/primitive_type.rs index 543e6d73..9ee7fd51 100644 --- a/src/lib/ast/primitive_type.rs +++ b/src/lib/ty/primitive_type.rs @@ -1,4 +1,4 @@ -use crate::ast::Type; +use super::Type; #[derive(Debug, Clone, Hash, Eq, PartialEq, Serialize, Deserialize)] pub enum PrimitiveType { @@ -32,7 +32,7 @@ impl PrimitiveType { Self::Int64 => "Int64".to_string(), Self::Float64 => "Float64".to_string(), Self::String => "String".to_string(), - Self::Array(t, size) => format!("[{}; {}]", t.get_name(), size), + Self::Array(t, _size) => format!("[{}]", t.get_name()), } } @@ -49,4 +49,36 @@ impl PrimitiveType { _ => None, } } + + pub fn is_bool(&self) -> bool { + matches!(self, PrimitiveType::Bool) + } + + pub fn is_int8(&self) -> bool { + matches!(self, PrimitiveType::Int8) + } + + pub fn is_int16(&self) -> bool { + matches!(self, PrimitiveType::Int16) + } + + pub fn is_int32(&self) -> bool { + matches!(self, PrimitiveType::Int32) + } + + pub fn is_int64(&self) -> bool { + matches!(self, PrimitiveType::Int64) + } + + pub fn is_float64(&self) -> bool { + matches!(self, PrimitiveType::Float64) + } + + pub fn is_string(&self) -> bool { + matches!(self, PrimitiveType::String) + } + + pub fn is_array(&self) -> bool { + matches!(self, PrimitiveType::Array(_, _)) + } } diff --git a/src/lib/ty/struct_type.rs b/src/lib/ty/struct_type.rs new file mode 100644 index 00000000..0bb156c8 --- /dev/null +++ b/src/lib/ty/struct_type.rs @@ -0,0 +1,84 @@ +use std::{collections::BTreeMap, fmt}; + +use colored::*; + +use crate::{ast, hir}; + +use super::Type; + +#[derive(Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] +pub struct StructType { + pub name: String, + pub defs: BTreeMap>, +} + +impl fmt::Debug for StructType { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "{} {} {} {}", + self.name.yellow(), + "{".green(), + self.defs + .iter() + .map(|(n, b)| format!("{}: {:?}", n, b)) + .collect::>() + .join(", "), + "}".green(), + ) + } +} + +impl From<&ast::StructDecl> for StructType { + fn from(s: &ast::StructDecl) -> Self { + s.into() + } +} + +impl From for StructType { + fn from(s: ast::StructDecl) -> Self { + StructType { + name: s.name.get_name(), + defs: s + .defs + .iter() + .map(|proto| { + if proto.signature.arguments.is_empty() { + (proto.name.name.clone(), proto.signature.ret.clone()) + } else { + ( + proto.name.name.clone(), + Box::new(proto.signature.clone().into()), + ) + } + }) + .collect(), + } + } +} + +impl From for StructType { + fn from(s: hir::StructDecl) -> Self { + StructType { + name: s.name.get_name(), + defs: s + .defs + .iter() + .map(|proto| { + if proto.signature.arguments.is_empty() { + (proto.name.name.clone(), proto.signature.ret.clone()) + } else { + ( + proto.name.name.clone(), + Box::new(proto.signature.clone().into()), + ) + } + }) + .collect(), + } + } +} + +impl StructType { + // pub fn +} diff --git a/src/lib/ty/type.rs b/src/lib/ty/type.rs new file mode 100644 index 00000000..6493264b --- /dev/null +++ b/src/lib/ty/type.rs @@ -0,0 +1,224 @@ +use std::fmt; + +use colored::*; + +use crate::{ast, hir}; + +use super::{FuncType, PrimitiveType, StructType}; + +#[derive(Clone, Eq, Serialize, Deserialize)] +pub enum Type { + Primitive(PrimitiveType), + Func(FuncType), + Struct(StructType), + Trait(String), + ForAll(String), + Undefined(u64), // FIXME: To remove +} + +impl std::hash::Hash for Type { + fn hash(&self, state: &mut H) { + core::mem::discriminant(self).hash(state); + } +} + +impl PartialEq for Type { + fn eq(&self, other: &Type) -> bool { + self.get_name() == other.get_name() + } +} + +macro_rules! generate_primitive_is_check { + ($e:tt) => { + pub fn $e(&self) -> bool { + self.try_as_primitive_type() + .map(|p| p.$e()) + .unwrap_or(false) + } + }; +} + +macro_rules! generate_primitive_checks { + ($($e:tt),+) => { + $( + generate_primitive_is_check!($e); + )+ + }; +} + +impl Type { + pub fn int64() -> Self { + Self::Primitive(PrimitiveType::Int64) + } + + pub fn forall(t: &str) -> Self { + Self::ForAll(String::from(t)) + } + + pub fn is_solved(&self) -> bool { + match self { + Type::Primitive(p) => p.is_solved(), + Type::Func(ft) => ft.is_solved(), + Type::Struct(_) => true, + Type::Trait(_) => true, + Type::ForAll(_) => false, + Type::Undefined(_) => false, + } + } + + pub fn is_primitive(&self) -> bool { + matches!(self, Self::Primitive(_x)) + } + + generate_primitive_checks!( + is_bool, is_int8, is_int16, is_int32, is_float64, is_string, is_array + ); + + pub fn is_struct(&self) -> bool { + matches!(self, Self::Struct(_x)) + } + + pub fn is_trait(&self) -> bool { + matches!(self, Self::Trait(_x)) + } + + pub fn is_func(&self) -> bool { + matches!(self, Self::Func(_x)) + } + + pub fn is_forall(&self) -> bool { + matches!(self, Self::ForAll(_x)) + } + + pub fn get_name(&self) -> String { + match self { + Self::Primitive(p) => p.get_name(), + Self::Func(f) => format!("{:?}", f), + Self::Struct(s) => s.name.clone(), + Self::Trait(t) => t.clone(), + Self::ForAll(n) => String::from(n), + Self::Undefined(s) => s.to_string(), + } + } + + pub fn as_struct_type(&self) -> StructType { + if let Type::Struct(t) = self { + t.clone() + } else { + panic!("Not a struct type"); + } + } + + pub fn as_func_type(&self) -> FuncType { + if let Type::Func(f) = self { + f.clone() + } else { + panic!("Not a func type"); + } + } + + pub fn as_primitive_type(&self) -> PrimitiveType { + if let Type::Primitive(p) = self { + p.clone() + } else { + panic!("Not a primitive"); + } + } + + pub fn try_as_struct_type(&self) -> Option { + match self { + Type::Struct(t) => Some(t.clone()), + _ => None, + } + } + + pub fn try_as_func_type(&self) -> Option { + match self { + Type::Func(f) => Some(f.clone()), + _ => None, + } + } + + pub fn try_as_primitive_type(&self) -> Option { + match self { + Type::Primitive(p) => Some(p.clone()), + _ => None, + } + } +} + +impl fmt::Debug for Type { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + let s = match self { + Self::Func(f) => format!("{:?}", f), + Self::Struct(s) => format!("{:?}", s), + _ => self.get_name().cyan().to_string(), + }; + + write!(f, "{}", s) + } +} + +impl fmt::Display for Type { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.get_name()) + } +} + +impl From for Type { + fn from(t: PrimitiveType) -> Self { + Type::Primitive(t) + } +} + +impl From for Type { + fn from(t: FuncType) -> Self { + Type::Func(t) + } +} + +impl From<&FuncType> for Type { + fn from(t: &FuncType) -> Self { + Type::Func(t.clone()) + } +} + +impl From for Type { + fn from(t: StructType) -> Self { + Type::Struct(t) + } +} + +impl From for Type { + fn from(t: ast::StructDecl) -> Self { + StructType::from(t).into() + } +} + +impl From<&ast::StructDecl> for Type { + fn from(t: &ast::StructDecl) -> Self { + StructType::from(t.clone()).into() + } +} + +impl From for Type { + fn from(t: hir::StructDecl) -> Self { + Type::Struct(t.into()) + } +} + +impl From<&hir::StructDecl> for Type { + fn from(t: &hir::StructDecl) -> Self { + t.clone().into() + } +} + +impl From for Type { + fn from(t: String) -> Self { + if t.len() == 1 && (t.chars().next().unwrap()).is_lowercase() { + Type::ForAll(t) + } else { + Type::Trait(t) + } + } +} From 420b9c15bcfa94c2b4f283e1d2f77175801e7c66 Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Oct 2021 13:57:53 +0000 Subject: [PATCH 08/74] Generated files for new version --- Cargo.toml | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 07d0297f..afd6987c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.6-function-in-struct-field" +version = "0.1.6-develop" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index df19b7a6..97e87924 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.6-function-in-struct-field +# Rock v0.1.6-develop -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=function_in_struct_field)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. @@ -35,10 +35,10 @@ How to install and run the compiler: Linux x86_64 only -[Rock v0.1.6-function-in-struct-field](https://github.com/Champii/Rock/releases/download/v0.1.6-function-in-struct-field/rock) (Tested on arch, btw) +[Rock v0.1.6-develop](https://github.com/Champii/Rock/releases/download/v0.1.6-develop/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.6-function-in-struct-field/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.6-develop/rock chmod +x rock ./rock -V ``` From f872d6f785b7298faa1dea8da7618464dd059816 Mon Sep 17 00:00:00 2001 From: Florian Greiner Date: Sat, 2 Oct 2021 16:36:04 +0200 Subject: [PATCH 09/74] Added LLVM12 requirement in README --- .github/templates/README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/.github/templates/README.md b/.github/templates/README.md index c0fd0e8b..15071bcd 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -43,14 +43,18 @@ chmod +x rock ./rock -V ``` -### With cargo from git +### From source + +You will need LLVM12.0.1 and Clang12.0.1 somewhere in your $PATH + +#### With cargo from git ``` sh cargo install --git https://github.com/Champii/Rock rock -V ``` -### From sources +#### Manual checkout and build from git ``` sh git clone https://github.com/Champii/Rock.git From c77e3c1c11650e2d9f69841cae40dcff0622d9ed Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Oct 2021 14:36:26 +0000 Subject: [PATCH 10/74] Generated files for new version --- README.md | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index e080a680..2dc1bc66 100644 --- a/README.md +++ b/README.md @@ -43,14 +43,18 @@ chmod +x rock ./rock -V ``` -### With cargo from git +### From source + +You will need LLVM12.0.1 and Clang12.0.1 somewhere in your $PATH + +#### With cargo from git ``` sh cargo install --git https://github.com/Champii/Rock rock -V ``` -### From sources +#### Manual checkout and build from git ``` sh git clone https://github.com/Champii/Rock.git From 402df3577f3d9e9c6dc730d64ee8d0063f576db9 Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Oct 2021 08:43:27 -0700 Subject: [PATCH 11/74] Clang instead of llc (#45) * Removed llc to keep only clang as a build dependency * Generated files for new version Co-authored-by: Florian Greiner --- .github/templates/README.md | 6 ++++-- Cargo.toml | 2 +- README.md | 14 ++++++++------ src/bin/main.rs | 31 ++++--------------------------- src/lib/codegen/mod.rs | 2 +- src/lib/rock.rs | 32 ++++---------------------------- 6 files changed, 22 insertions(+), 65 deletions(-) diff --git a/.github/templates/README.md b/.github/templates/README.md index 15071bcd..75d01b71 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -33,6 +33,8 @@ How to install and run the compiler: ### Using released binary +You will need `clang` somewhere in your $PATH + Linux x86_64 only [Rock {version}](https://github.com/Champii/Rock/releases/download/{version}/rock) (Tested on arch, btw) @@ -45,7 +47,7 @@ chmod +x rock ### From source -You will need LLVM12.0.1 and Clang12.0.1 somewhere in your $PATH +You will need `llvm-12.0.1` and `clang-12.0.1` somewhere in your $PATH #### With cargo from git @@ -54,7 +56,7 @@ cargo install --git https://github.com/Champii/Rock rock -V ``` -#### Manual checkout and build from git +#### Manual clone and build from git ``` sh git clone https://github.com/Champii/Rock.git diff --git a/Cargo.toml b/Cargo.toml index f9860a46..ed481e7e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.7-develop" +version = "0.1.7-clang-instead-of-llc" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 2dc1bc66..e921c844 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.7-develop +# Rock v0.1.7-clang-instead-of-llc -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=clang_instead_of_llc)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. @@ -33,19 +33,21 @@ How to install and run the compiler: ### Using released binary +You will need `clang` somewhere in your $PATH + Linux x86_64 only -[Rock v0.1.7-develop](https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock) (Tested on arch, btw) +[Rock v0.1.7-clang-instead-of-llc](https://github.com/Champii/Rock/releases/download/v0.1.7-clang-instead-of-llc/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.7-clang-instead-of-llc/rock chmod +x rock ./rock -V ``` ### From source -You will need LLVM12.0.1 and Clang12.0.1 somewhere in your $PATH +You will need `llvm-12.0.1` and `clang-12.0.1` somewhere in your $PATH #### With cargo from git @@ -54,7 +56,7 @@ cargo install --git https://github.com/Champii/Rock rock -V ``` -#### Manual checkout and build from git +#### Manual clone and build from git ``` sh git clone https://github.com/Champii/Rock.git diff --git a/src/bin/main.rs b/src/bin/main.rs index 1b111a5d..62beac51 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -28,44 +28,20 @@ fn build(config: &Config) -> bool { return false; } - let llc_cmd = Command::new("llc") - .args(&[ - "--relocation-model=pic", - config.build_folder.join("out.ir").to_str().unwrap(), - ]) - .output() - .expect("failed to compile to ir"); - - match llc_cmd.status.code() { - Some(code) => { - if code != 0 { - println!( - "BUG: Cannot compile to ir: \n{}", - String::from_utf8(llc_cmd.stderr).unwrap() - ); - - return false; - } - } - None => println!( - "\nError running: \n{}", - String::from_utf8(llc_cmd.stderr).unwrap() - ), - } let clang_cmd = Command::new("clang") .args(&[ + config.build_folder.join("out.bc").to_str().unwrap(), "-o", config.build_folder.join("a.out").to_str().unwrap(), - config.build_folder.join("out.ir.s").to_str().unwrap(), ]) .output() - .expect("failed to compile to binary"); + .expect("failed to compile to ir"); match clang_cmd.status.code() { Some(code) => { if code != 0 { println!( - "BUG: Cannot compile to binary: {}", + "BUG: Cannot compile: \n{}", String::from_utf8(clang_cmd.stderr).unwrap() ); @@ -77,6 +53,7 @@ fn build(config: &Config) -> bool { String::from_utf8(clang_cmd.stderr).unwrap() ), } + true } diff --git a/src/lib/codegen/mod.rs b/src/lib/codegen/mod.rs index 3a5cc3f0..09d6ef01 100644 --- a/src/lib/codegen/mod.rs +++ b/src/lib/codegen/mod.rs @@ -33,7 +33,7 @@ pub fn generate( if !codegen_ctx .module - .write_bitcode_to_path(&config.build_folder.join("out.ir")) + .write_bitcode_to_path(&config.build_folder.join("out.bc")) { panic!("CANNOT IR WRITE TO PATH"); } diff --git a/src/lib/rock.rs b/src/lib/rock.rs index 4527a541..ac0950f1 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -90,45 +90,20 @@ mod test { return false; } - let llc_cmd = Command::new("llc") - .args(&[ - "--relocation-model=pic", - config.build_folder.join("out.ir").to_str().unwrap(), - ]) - .output() - .expect("failed to execute IR -> ASM"); - - match llc_cmd.status.code() { - Some(code) => { - if code != 0 { - println!( - "BUG: Cannot compile to ir: \n{}", - String::from_utf8(llc_cmd.stderr).unwrap() - ); - - return false; - } - } - None => println!( - "\nError running: \n{}", - String::from_utf8(llc_cmd.stderr).unwrap() - ), - } - let clang_cmd = Command::new("clang") .args(&[ + config.build_folder.join("out.bc").to_str().unwrap(), "-o", config.build_folder.join("a.out").to_str().unwrap(), - config.build_folder.join("out.ir.s").to_str().unwrap(), ]) .output() - .expect("failed to execute ASM -> BINARY"); + .expect("failed to compile to ir"); match clang_cmd.status.code() { Some(code) => { if code != 0 { println!( - "BUG: Cannot compile to binary: {}", + "BUG: Cannot compile: \n{}", String::from_utf8(clang_cmd.stderr).unwrap() ); @@ -140,6 +115,7 @@ mod test { String::from_utf8(clang_cmd.stderr).unwrap() ), } + true } From f7770ea264981c2d9b1747e94cea782717ef159e Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Oct 2021 15:43:46 +0000 Subject: [PATCH 12/74] Generated files for new version --- Cargo.toml | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index ed481e7e..f9860a46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.7-clang-instead-of-llc" +version = "0.1.7-develop" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index e921c844..1a1a99ac 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.7-clang-instead-of-llc +# Rock v0.1.7-develop -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=clang_instead_of_llc)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. @@ -37,10 +37,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.7-clang-instead-of-llc](https://github.com/Champii/Rock/releases/download/v0.1.7-clang-instead-of-llc/rock) (Tested on arch, btw) +[Rock v0.1.7-develop](https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.7-clang-instead-of-llc/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock chmod +x rock ./rock -V ``` From b86e51a659aa547e4f30240cb20ab0d10190d74a Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Oct 2021 19:45:13 +0200 Subject: [PATCH 13/74] Create LICENSE --- LICENSE | 674 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 674 insertions(+) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 00000000..f288702d --- /dev/null +++ b/LICENSE @@ -0,0 +1,674 @@ + GNU GENERAL PUBLIC LICENSE + Version 3, 29 June 2007 + + Copyright (C) 2007 Free Software Foundation, Inc. + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + + Preamble + + The GNU General Public License is a free, copyleft license for +software and other kinds of works. + + The licenses for most software and other practical works are designed +to take away your freedom to share and change the works. By contrast, +the GNU General Public License is intended to guarantee your freedom to +share and change all versions of a program--to make sure it remains free +software for all its users. We, the Free Software Foundation, use the +GNU General Public License for most of our software; it applies also to +any other work released this way by its authors. You can apply it to +your programs, too. + + When we speak of free software, we are referring to freedom, not +price. Our General Public Licenses are designed to make sure that you +have the freedom to distribute copies of free software (and charge for +them if you wish), that you receive source code or can get it if you +want it, that you can change the software or use pieces of it in new +free programs, and that you know you can do these things. + + To protect your rights, we need to prevent others from denying you +these rights or asking you to surrender the rights. Therefore, you have +certain responsibilities if you distribute copies of the software, or if +you modify it: responsibilities to respect the freedom of others. + + For example, if you distribute copies of such a program, whether +gratis or for a fee, you must pass on to the recipients the same +freedoms that you received. You must make sure that they, too, receive +or can get the source code. And you must show them these terms so they +know their rights. + + Developers that use the GNU GPL protect your rights with two steps: +(1) assert copyright on the software, and (2) offer you this License +giving you legal permission to copy, distribute and/or modify it. + + For the developers' and authors' protection, the GPL clearly explains +that there is no warranty for this free software. For both users' and +authors' sake, the GPL requires that modified versions be marked as +changed, so that their problems will not be attributed erroneously to +authors of previous versions. + + Some devices are designed to deny users access to install or run +modified versions of the software inside them, although the manufacturer +can do so. This is fundamentally incompatible with the aim of +protecting users' freedom to change the software. The systematic +pattern of such abuse occurs in the area of products for individuals to +use, which is precisely where it is most unacceptable. Therefore, we +have designed this version of the GPL to prohibit the practice for those +products. If such problems arise substantially in other domains, we +stand ready to extend this provision to those domains in future versions +of the GPL, as needed to protect the freedom of users. + + Finally, every program is threatened constantly by software patents. +States should not allow patents to restrict development and use of +software on general-purpose computers, but in those that do, we wish to +avoid the special danger that patents applied to a free program could +make it effectively proprietary. To prevent this, the GPL assures that +patents cannot be used to render the program non-free. + + The precise terms and conditions for copying, distribution and +modification follow. + + TERMS AND CONDITIONS + + 0. Definitions. + + "This License" refers to version 3 of the GNU General Public License. + + "Copyright" also means copyright-like laws that apply to other kinds of +works, such as semiconductor masks. + + "The Program" refers to any copyrightable work licensed under this +License. Each licensee is addressed as "you". "Licensees" and +"recipients" may be individuals or organizations. + + To "modify" a work means to copy from or adapt all or part of the work +in a fashion requiring copyright permission, other than the making of an +exact copy. The resulting work is called a "modified version" of the +earlier work or a work "based on" the earlier work. + + A "covered work" means either the unmodified Program or a work based +on the Program. + + To "propagate" a work means to do anything with it that, without +permission, would make you directly or secondarily liable for +infringement under applicable copyright law, except executing it on a +computer or modifying a private copy. Propagation includes copying, +distribution (with or without modification), making available to the +public, and in some countries other activities as well. + + To "convey" a work means any kind of propagation that enables other +parties to make or receive copies. Mere interaction with a user through +a computer network, with no transfer of a copy, is not conveying. + + An interactive user interface displays "Appropriate Legal Notices" +to the extent that it includes a convenient and prominently visible +feature that (1) displays an appropriate copyright notice, and (2) +tells the user that there is no warranty for the work (except to the +extent that warranties are provided), that licensees may convey the +work under this License, and how to view a copy of this License. If +the interface presents a list of user commands or options, such as a +menu, a prominent item in the list meets this criterion. + + 1. Source Code. + + The "source code" for a work means the preferred form of the work +for making modifications to it. "Object code" means any non-source +form of a work. + + A "Standard Interface" means an interface that either is an official +standard defined by a recognized standards body, or, in the case of +interfaces specified for a particular programming language, one that +is widely used among developers working in that language. + + The "System Libraries" of an executable work include anything, other +than the work as a whole, that (a) is included in the normal form of +packaging a Major Component, but which is not part of that Major +Component, and (b) serves only to enable use of the work with that +Major Component, or to implement a Standard Interface for which an +implementation is available to the public in source code form. A +"Major Component", in this context, means a major essential component +(kernel, window system, and so on) of the specific operating system +(if any) on which the executable work runs, or a compiler used to +produce the work, or an object code interpreter used to run it. + + The "Corresponding Source" for a work in object code form means all +the source code needed to generate, install, and (for an executable +work) run the object code and to modify the work, including scripts to +control those activities. However, it does not include the work's +System Libraries, or general-purpose tools or generally available free +programs which are used unmodified in performing those activities but +which are not part of the work. For example, Corresponding Source +includes interface definition files associated with source files for +the work, and the source code for shared libraries and dynamically +linked subprograms that the work is specifically designed to require, +such as by intimate data communication or control flow between those +subprograms and other parts of the work. + + The Corresponding Source need not include anything that users +can regenerate automatically from other parts of the Corresponding +Source. + + The Corresponding Source for a work in source code form is that +same work. + + 2. Basic Permissions. + + All rights granted under this License are granted for the term of +copyright on the Program, and are irrevocable provided the stated +conditions are met. This License explicitly affirms your unlimited +permission to run the unmodified Program. The output from running a +covered work is covered by this License only if the output, given its +content, constitutes a covered work. This License acknowledges your +rights of fair use or other equivalent, as provided by copyright law. + + You may make, run and propagate covered works that you do not +convey, without conditions so long as your license otherwise remains +in force. You may convey covered works to others for the sole purpose +of having them make modifications exclusively for you, or provide you +with facilities for running those works, provided that you comply with +the terms of this License in conveying all material for which you do +not control copyright. Those thus making or running the covered works +for you must do so exclusively on your behalf, under your direction +and control, on terms that prohibit them from making any copies of +your copyrighted material outside their relationship with you. + + Conveying under any other circumstances is permitted solely under +the conditions stated below. Sublicensing is not allowed; section 10 +makes it unnecessary. + + 3. Protecting Users' Legal Rights From Anti-Circumvention Law. + + No covered work shall be deemed part of an effective technological +measure under any applicable law fulfilling obligations under article +11 of the WIPO copyright treaty adopted on 20 December 1996, or +similar laws prohibiting or restricting circumvention of such +measures. + + When you convey a covered work, you waive any legal power to forbid +circumvention of technological measures to the extent such circumvention +is effected by exercising rights under this License with respect to +the covered work, and you disclaim any intention to limit operation or +modification of the work as a means of enforcing, against the work's +users, your or third parties' legal rights to forbid circumvention of +technological measures. + + 4. Conveying Verbatim Copies. + + You may convey verbatim copies of the Program's source code as you +receive it, in any medium, provided that you conspicuously and +appropriately publish on each copy an appropriate copyright notice; +keep intact all notices stating that this License and any +non-permissive terms added in accord with section 7 apply to the code; +keep intact all notices of the absence of any warranty; and give all +recipients a copy of this License along with the Program. + + You may charge any price or no price for each copy that you convey, +and you may offer support or warranty protection for a fee. + + 5. Conveying Modified Source Versions. + + You may convey a work based on the Program, or the modifications to +produce it from the Program, in the form of source code under the +terms of section 4, provided that you also meet all of these conditions: + + a) The work must carry prominent notices stating that you modified + it, and giving a relevant date. + + b) The work must carry prominent notices stating that it is + released under this License and any conditions added under section + 7. This requirement modifies the requirement in section 4 to + "keep intact all notices". + + c) You must license the entire work, as a whole, under this + License to anyone who comes into possession of a copy. This + License will therefore apply, along with any applicable section 7 + additional terms, to the whole of the work, and all its parts, + regardless of how they are packaged. This License gives no + permission to license the work in any other way, but it does not + invalidate such permission if you have separately received it. + + d) If the work has interactive user interfaces, each must display + Appropriate Legal Notices; however, if the Program has interactive + interfaces that do not display Appropriate Legal Notices, your + work need not make them do so. + + A compilation of a covered work with other separate and independent +works, which are not by their nature extensions of the covered work, +and which are not combined with it such as to form a larger program, +in or on a volume of a storage or distribution medium, is called an +"aggregate" if the compilation and its resulting copyright are not +used to limit the access or legal rights of the compilation's users +beyond what the individual works permit. Inclusion of a covered work +in an aggregate does not cause this License to apply to the other +parts of the aggregate. + + 6. Conveying Non-Source Forms. + + You may convey a covered work in object code form under the terms +of sections 4 and 5, provided that you also convey the +machine-readable Corresponding Source under the terms of this License, +in one of these ways: + + a) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by the + Corresponding Source fixed on a durable physical medium + customarily used for software interchange. + + b) Convey the object code in, or embodied in, a physical product + (including a physical distribution medium), accompanied by a + written offer, valid for at least three years and valid for as + long as you offer spare parts or customer support for that product + model, to give anyone who possesses the object code either (1) a + copy of the Corresponding Source for all the software in the + product that is covered by this License, on a durable physical + medium customarily used for software interchange, for a price no + more than your reasonable cost of physically performing this + conveying of source, or (2) access to copy the + Corresponding Source from a network server at no charge. + + c) Convey individual copies of the object code with a copy of the + written offer to provide the Corresponding Source. This + alternative is allowed only occasionally and noncommercially, and + only if you received the object code with such an offer, in accord + with subsection 6b. + + d) Convey the object code by offering access from a designated + place (gratis or for a charge), and offer equivalent access to the + Corresponding Source in the same way through the same place at no + further charge. You need not require recipients to copy the + Corresponding Source along with the object code. If the place to + copy the object code is a network server, the Corresponding Source + may be on a different server (operated by you or a third party) + that supports equivalent copying facilities, provided you maintain + clear directions next to the object code saying where to find the + Corresponding Source. Regardless of what server hosts the + Corresponding Source, you remain obligated to ensure that it is + available for as long as needed to satisfy these requirements. + + e) Convey the object code using peer-to-peer transmission, provided + you inform other peers where the object code and Corresponding + Source of the work are being offered to the general public at no + charge under subsection 6d. + + A separable portion of the object code, whose source code is excluded +from the Corresponding Source as a System Library, need not be +included in conveying the object code work. + + A "User Product" is either (1) a "consumer product", which means any +tangible personal property which is normally used for personal, family, +or household purposes, or (2) anything designed or sold for incorporation +into a dwelling. In determining whether a product is a consumer product, +doubtful cases shall be resolved in favor of coverage. For a particular +product received by a particular user, "normally used" refers to a +typical or common use of that class of product, regardless of the status +of the particular user or of the way in which the particular user +actually uses, or expects or is expected to use, the product. A product +is a consumer product regardless of whether the product has substantial +commercial, industrial or non-consumer uses, unless such uses represent +the only significant mode of use of the product. + + "Installation Information" for a User Product means any methods, +procedures, authorization keys, or other information required to install +and execute modified versions of a covered work in that User Product from +a modified version of its Corresponding Source. The information must +suffice to ensure that the continued functioning of the modified object +code is in no case prevented or interfered with solely because +modification has been made. + + If you convey an object code work under this section in, or with, or +specifically for use in, a User Product, and the conveying occurs as +part of a transaction in which the right of possession and use of the +User Product is transferred to the recipient in perpetuity or for a +fixed term (regardless of how the transaction is characterized), the +Corresponding Source conveyed under this section must be accompanied +by the Installation Information. But this requirement does not apply +if neither you nor any third party retains the ability to install +modified object code on the User Product (for example, the work has +been installed in ROM). + + The requirement to provide Installation Information does not include a +requirement to continue to provide support service, warranty, or updates +for a work that has been modified or installed by the recipient, or for +the User Product in which it has been modified or installed. Access to a +network may be denied when the modification itself materially and +adversely affects the operation of the network or violates the rules and +protocols for communication across the network. + + Corresponding Source conveyed, and Installation Information provided, +in accord with this section must be in a format that is publicly +documented (and with an implementation available to the public in +source code form), and must require no special password or key for +unpacking, reading or copying. + + 7. Additional Terms. + + "Additional permissions" are terms that supplement the terms of this +License by making exceptions from one or more of its conditions. +Additional permissions that are applicable to the entire Program shall +be treated as though they were included in this License, to the extent +that they are valid under applicable law. If additional permissions +apply only to part of the Program, that part may be used separately +under those permissions, but the entire Program remains governed by +this License without regard to the additional permissions. + + When you convey a copy of a covered work, you may at your option +remove any additional permissions from that copy, or from any part of +it. (Additional permissions may be written to require their own +removal in certain cases when you modify the work.) You may place +additional permissions on material, added by you to a covered work, +for which you have or can give appropriate copyright permission. + + Notwithstanding any other provision of this License, for material you +add to a covered work, you may (if authorized by the copyright holders of +that material) supplement the terms of this License with terms: + + a) Disclaiming warranty or limiting liability differently from the + terms of sections 15 and 16 of this License; or + + b) Requiring preservation of specified reasonable legal notices or + author attributions in that material or in the Appropriate Legal + Notices displayed by works containing it; or + + c) Prohibiting misrepresentation of the origin of that material, or + requiring that modified versions of such material be marked in + reasonable ways as different from the original version; or + + d) Limiting the use for publicity purposes of names of licensors or + authors of the material; or + + e) Declining to grant rights under trademark law for use of some + trade names, trademarks, or service marks; or + + f) Requiring indemnification of licensors and authors of that + material by anyone who conveys the material (or modified versions of + it) with contractual assumptions of liability to the recipient, for + any liability that these contractual assumptions directly impose on + those licensors and authors. + + All other non-permissive additional terms are considered "further +restrictions" within the meaning of section 10. If the Program as you +received it, or any part of it, contains a notice stating that it is +governed by this License along with a term that is a further +restriction, you may remove that term. If a license document contains +a further restriction but permits relicensing or conveying under this +License, you may add to a covered work material governed by the terms +of that license document, provided that the further restriction does +not survive such relicensing or conveying. + + If you add terms to a covered work in accord with this section, you +must place, in the relevant source files, a statement of the +additional terms that apply to those files, or a notice indicating +where to find the applicable terms. + + Additional terms, permissive or non-permissive, may be stated in the +form of a separately written license, or stated as exceptions; +the above requirements apply either way. + + 8. Termination. + + You may not propagate or modify a covered work except as expressly +provided under this License. Any attempt otherwise to propagate or +modify it is void, and will automatically terminate your rights under +this License (including any patent licenses granted under the third +paragraph of section 11). + + However, if you cease all violation of this License, then your +license from a particular copyright holder is reinstated (a) +provisionally, unless and until the copyright holder explicitly and +finally terminates your license, and (b) permanently, if the copyright +holder fails to notify you of the violation by some reasonable means +prior to 60 days after the cessation. + + Moreover, your license from a particular copyright holder is +reinstated permanently if the copyright holder notifies you of the +violation by some reasonable means, this is the first time you have +received notice of violation of this License (for any work) from that +copyright holder, and you cure the violation prior to 30 days after +your receipt of the notice. + + Termination of your rights under this section does not terminate the +licenses of parties who have received copies or rights from you under +this License. If your rights have been terminated and not permanently +reinstated, you do not qualify to receive new licenses for the same +material under section 10. + + 9. Acceptance Not Required for Having Copies. + + You are not required to accept this License in order to receive or +run a copy of the Program. Ancillary propagation of a covered work +occurring solely as a consequence of using peer-to-peer transmission +to receive a copy likewise does not require acceptance. However, +nothing other than this License grants you permission to propagate or +modify any covered work. These actions infringe copyright if you do +not accept this License. Therefore, by modifying or propagating a +covered work, you indicate your acceptance of this License to do so. + + 10. Automatic Licensing of Downstream Recipients. + + Each time you convey a covered work, the recipient automatically +receives a license from the original licensors, to run, modify and +propagate that work, subject to this License. You are not responsible +for enforcing compliance by third parties with this License. + + An "entity transaction" is a transaction transferring control of an +organization, or substantially all assets of one, or subdividing an +organization, or merging organizations. If propagation of a covered +work results from an entity transaction, each party to that +transaction who receives a copy of the work also receives whatever +licenses to the work the party's predecessor in interest had or could +give under the previous paragraph, plus a right to possession of the +Corresponding Source of the work from the predecessor in interest, if +the predecessor has it or can get it with reasonable efforts. + + You may not impose any further restrictions on the exercise of the +rights granted or affirmed under this License. For example, you may +not impose a license fee, royalty, or other charge for exercise of +rights granted under this License, and you may not initiate litigation +(including a cross-claim or counterclaim in a lawsuit) alleging that +any patent claim is infringed by making, using, selling, offering for +sale, or importing the Program or any portion of it. + + 11. Patents. + + A "contributor" is a copyright holder who authorizes use under this +License of the Program or a work on which the Program is based. The +work thus licensed is called the contributor's "contributor version". + + A contributor's "essential patent claims" are all patent claims +owned or controlled by the contributor, whether already acquired or +hereafter acquired, that would be infringed by some manner, permitted +by this License, of making, using, or selling its contributor version, +but do not include claims that would be infringed only as a +consequence of further modification of the contributor version. For +purposes of this definition, "control" includes the right to grant +patent sublicenses in a manner consistent with the requirements of +this License. + + Each contributor grants you a non-exclusive, worldwide, royalty-free +patent license under the contributor's essential patent claims, to +make, use, sell, offer for sale, import and otherwise run, modify and +propagate the contents of its contributor version. + + In the following three paragraphs, a "patent license" is any express +agreement or commitment, however denominated, not to enforce a patent +(such as an express permission to practice a patent or covenant not to +sue for patent infringement). To "grant" such a patent license to a +party means to make such an agreement or commitment not to enforce a +patent against the party. + + If you convey a covered work, knowingly relying on a patent license, +and the Corresponding Source of the work is not available for anyone +to copy, free of charge and under the terms of this License, through a +publicly available network server or other readily accessible means, +then you must either (1) cause the Corresponding Source to be so +available, or (2) arrange to deprive yourself of the benefit of the +patent license for this particular work, or (3) arrange, in a manner +consistent with the requirements of this License, to extend the patent +license to downstream recipients. "Knowingly relying" means you have +actual knowledge that, but for the patent license, your conveying the +covered work in a country, or your recipient's use of the covered work +in a country, would infringe one or more identifiable patents in that +country that you have reason to believe are valid. + + If, pursuant to or in connection with a single transaction or +arrangement, you convey, or propagate by procuring conveyance of, a +covered work, and grant a patent license to some of the parties +receiving the covered work authorizing them to use, propagate, modify +or convey a specific copy of the covered work, then the patent license +you grant is automatically extended to all recipients of the covered +work and works based on it. + + A patent license is "discriminatory" if it does not include within +the scope of its coverage, prohibits the exercise of, or is +conditioned on the non-exercise of one or more of the rights that are +specifically granted under this License. You may not convey a covered +work if you are a party to an arrangement with a third party that is +in the business of distributing software, under which you make payment +to the third party based on the extent of your activity of conveying +the work, and under which the third party grants, to any of the +parties who would receive the covered work from you, a discriminatory +patent license (a) in connection with copies of the covered work +conveyed by you (or copies made from those copies), or (b) primarily +for and in connection with specific products or compilations that +contain the covered work, unless you entered into that arrangement, +or that patent license was granted, prior to 28 March 2007. + + Nothing in this License shall be construed as excluding or limiting +any implied license or other defenses to infringement that may +otherwise be available to you under applicable patent law. + + 12. No Surrender of Others' Freedom. + + If conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot convey a +covered work so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you may +not convey it at all. For example, if you agree to terms that obligate you +to collect a royalty for further conveying from those to whom you convey +the Program, the only way you could satisfy both those terms and this +License would be to refrain entirely from conveying the Program. + + 13. Use with the GNU Affero General Public License. + + Notwithstanding any other provision of this License, you have +permission to link or combine any covered work with a work licensed +under version 3 of the GNU Affero General Public License into a single +combined work, and to convey the resulting work. The terms of this +License will continue to apply to the part which is the covered work, +but the special requirements of the GNU Affero General Public License, +section 13, concerning interaction through a network will apply to the +combination as such. + + 14. Revised Versions of this License. + + The Free Software Foundation may publish revised and/or new versions of +the GNU General Public License from time to time. Such new versions will +be similar in spirit to the present version, but may differ in detail to +address new problems or concerns. + + Each version is given a distinguishing version number. If the +Program specifies that a certain numbered version of the GNU General +Public License "or any later version" applies to it, you have the +option of following the terms and conditions either of that numbered +version or of any later version published by the Free Software +Foundation. If the Program does not specify a version number of the +GNU General Public License, you may choose any version ever published +by the Free Software Foundation. + + If the Program specifies that a proxy can decide which future +versions of the GNU General Public License can be used, that proxy's +public statement of acceptance of a version permanently authorizes you +to choose that version for the Program. + + Later license versions may give you additional or different +permissions. However, no additional obligations are imposed on any +author or copyright holder as a result of your choosing to follow a +later version. + + 15. Disclaimer of Warranty. + + THERE IS NO WARRANTY FOR THE PROGRAM, TO THE EXTENT PERMITTED BY +APPLICABLE LAW. EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT +HOLDERS AND/OR OTHER PARTIES PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY +OF ANY KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, +THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE PROGRAM +IS WITH YOU. SHOULD THE PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF +ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. Limitation of Liability. + + IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING +WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS +THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES, INCLUDING ANY +GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING OUT OF THE +USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED TO LOSS OF +DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD +PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER PROGRAMS), +EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF +SUCH DAMAGES. + + 17. Interpretation of Sections 15 and 16. + + If the disclaimer of warranty and limitation of liability provided +above cannot be given local legal effect according to their terms, +reviewing courts shall apply local law that most closely approximates +an absolute waiver of all civil liability in connection with the +Program, unless a warranty or assumption of liability accompanies a +copy of the Program in return for a fee. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Programs + + If you develop a new program, and you want it to be of the greatest +possible use to the public, the best way to achieve this is to make it +free software which everyone can redistribute and change under these terms. + + To do so, attach the following notices to the program. It is safest +to attach them to the start of each source file to most effectively +state the exclusion of warranty; and each file should have at least +the "copyright" line and a pointer to where the full notice is found. + + + Copyright (C) + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . + +Also add information on how to contact you by electronic and paper mail. + + If the program does terminal interaction, make it output a short +notice like this when it starts in an interactive mode: + + Copyright (C) + This program comes with ABSOLUTELY NO WARRANTY; for details type `show w'. + This is free software, and you are welcome to redistribute it + under certain conditions; type `show c' for details. + +The hypothetical commands `show w' and `show c' should show the appropriate +parts of the General Public License. Of course, your program's commands +might be different; for a GUI interface, you would use an "about box". + + You should also get your employer (if you work as a programmer) or school, +if any, to sign a "copyright disclaimer" for the program, if necessary. +For more information on this, and how to apply and follow the GNU GPL, see +. + + The GNU General Public License does not permit incorporating your program +into proprietary programs. If your program is a subroutine library, you +may consider it more useful to permit linking proprietary applications with +the library. If this is what you want to do, use the GNU Lesser General +Public License instead of this License. But first, please read +. From c938ffc45fd88a8d7ea626af3f73107f8f058a6a Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Oct 2021 10:51:17 -0700 Subject: [PATCH 14/74] Optimisation pass (#48) * Add (too many) LLVM pass optimizations --- Cargo.toml | 2 +- README.md | 8 ++--- src/bin/main.rs | 7 ++++ src/lib/codegen/codegen_context.rs | 55 ++++++++++++++++++++++++++++++ src/lib/codegen/mod.rs | 12 ++++--- src/lib/helpers/config.rs | 17 +-------- 6 files changed, 76 insertions(+), 25 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f9860a46..b8e307a6 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.7-develop" +version = "0.1.7-optimisation-pass" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 1a1a99ac..1b0676e4 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.7-develop +# Rock v0.1.7-optimisation-pass -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=optimisation_pass)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. @@ -37,10 +37,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.7-develop](https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock) (Tested on arch, btw) +[Rock v0.1.7-optimisation-pass](https://github.com/Champii/Rock/releases/download/v0.1.7-optimisation-pass/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.7-optimisation-pass/rock chmod +x rock ./rock -V ``` diff --git a/src/bin/main.rs b/src/bin/main.rs index 62beac51..969cd587 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -109,6 +109,12 @@ fn main() { .takes_value(false) .help("Show hir"), ) + .arg( + Arg::with_name("no-optimize") + .short("N") + .takes_value(false) + .help("Disable LLVM optimization passes"), + ) .arg( Arg::with_name("ir") .short("i") @@ -139,6 +145,7 @@ fn main() { show_hir: matches.is_present("hir"), show_ir: matches.is_present("ir"), show_state: matches.is_present("state"), + no_optimize: matches.is_present("no-optimize"), build_folder: PathBuf::from(matches.value_of("output-folder").unwrap()), ..Default::default() }; diff --git a/src/lib/codegen/codegen_context.rs b/src/lib/codegen/codegen_context.rs index e358c9c0..10218a11 100644 --- a/src/lib/codegen/codegen_context.rs +++ b/src/lib/codegen/codegen_context.rs @@ -5,9 +5,12 @@ use inkwell::{ builder::Builder, context::Context, module::Module, + passes::{PassManager, PassManagerBuilder}, + targets::{InitializationConfig, Target}, types::{BasicType, BasicTypeEnum}, values::{AnyValue, AnyValueEnum, BasicValue, BasicValueEnum, CallableValue, FunctionValue}, AddressSpace, FloatPredicate, IntPredicate, + OptimizationLevel::Aggressive, }; use crate::{ @@ -41,6 +44,58 @@ impl<'a> CodegenContext<'a> { } } + pub fn optimize(&mut self) { + let config = InitializationConfig::default(); + + Target::initialize_native(&config).unwrap(); + + let pass_manager_builder = PassManagerBuilder::create(); + + pass_manager_builder.set_optimization_level(Aggressive); + + let pass_manager = PassManager::create(()); + + pass_manager.add_demote_memory_to_register_pass(); + pass_manager.add_promote_memory_to_register_pass(); + pass_manager.add_argument_promotion_pass(); + pass_manager.add_always_inliner_pass(); + pass_manager.add_gvn_pass(); + pass_manager.add_new_gvn_pass(); + pass_manager.add_function_attrs_pass(); + pass_manager.add_prune_eh_pass(); + pass_manager.add_loop_vectorize_pass(); + pass_manager.add_cfg_simplification_pass(); + pass_manager.add_constant_merge_pass(); + pass_manager.add_scalarizer_pass(); + pass_manager.add_merged_load_store_motion_pass(); + pass_manager.add_ind_var_simplify_pass(); + pass_manager.add_instruction_combining_pass(); + pass_manager.add_licm_pass(); + pass_manager.add_loop_deletion_pass(); + pass_manager.add_loop_unswitch_pass(); + pass_manager.add_memcpy_optimize_pass(); + pass_manager.add_partially_inline_lib_calls_pass(); + pass_manager.add_lower_switch_pass(); + pass_manager.add_reassociate_pass(); + pass_manager.add_simplify_lib_calls_pass(); + pass_manager.add_tail_call_elimination_pass(); + pass_manager.add_aggressive_inst_combiner_pass(); + pass_manager.add_instruction_simplify_pass(); + pass_manager.add_function_inlining_pass(); + pass_manager.add_global_optimizer_pass(); + pass_manager.add_dead_arg_elimination_pass(); + pass_manager.add_strip_symbol_pass(); + pass_manager.add_strip_dead_prototypes_pass(); + pass_manager.add_internalize_pass(true); + pass_manager.add_aggressive_dce_pass(); + pass_manager.add_sccp_pass(); + pass_manager.add_verifier_pass(); + + pass_manager.run_on(&self.module); + + pass_manager_builder.populate_module_pass_manager(&pass_manager); + } + pub fn lower_type(&mut self, t: &Type, builder: &'a Builder) -> Result, ()> { Ok(match t { Type::Primitive(PrimitiveType::Int8) => self.context.i8_type().into(), diff --git a/src/lib/codegen/mod.rs b/src/lib/codegen/mod.rs index 09d6ef01..ad26d1c8 100644 --- a/src/lib/codegen/mod.rs +++ b/src/lib/codegen/mod.rs @@ -18,10 +18,6 @@ pub fn generate( codegen_ctx.parsing_ctx.return_if_error()?; } - if config.show_ir { - codegen_ctx.module.print_to_stderr(); - } - match codegen_ctx.module.verify() { Ok(_) => (), Err(e) => { @@ -31,6 +27,14 @@ pub fn generate( } } + if !config.no_optimize { + codegen_ctx.optimize(); + } + + if config.show_ir { + codegen_ctx.module.print_to_stderr(); + } + if !codegen_ctx .module .write_bitcode_to_path(&config.build_folder.join("out.bc")) diff --git a/src/lib/helpers/config.rs b/src/lib/helpers/config.rs index fb06e7ff..baeb7cab 100644 --- a/src/lib/helpers/config.rs +++ b/src/lib/helpers/config.rs @@ -12,22 +12,6 @@ impl Default for PackageType { } } -// TBD -// #[derive(Debug, Default, Serialize, Deserialize)] -// pub struct PackageMetaData<'a> { -// pub hir: hir::Root<'a>, -// } - -// impl<'a> PackageMetaData<'a> { -// pub fn load(path: &Path) -> bincode::Result { -// bincode::deserialize_from(BufReader::new(File::open(path).unwrap())) -// } - -// pub fn store(&self, path: &Path) -> bincode::Result<()> { -// bincode::serialize_into(BufWriter::new(File::create(path).unwrap()), self) -// } -// } - #[derive(Debug, Clone, Default)] pub struct ProjectConfig { pub name: String, @@ -47,4 +31,5 @@ pub struct Config { pub show_state: bool, pub verbose: bool, pub build_folder: PathBuf, + pub no_optimize: bool, } From 4eb6f7e9fe2d4ef168eeeafdc6a7228149633293 Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Oct 2021 17:51:34 +0000 Subject: [PATCH 15/74] Generated files for new version --- Cargo.toml | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b8e307a6..f9860a46 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.7-optimisation-pass" +version = "0.1.7-develop" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 1b0676e4..1a1a99ac 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.7-optimisation-pass +# Rock v0.1.7-develop -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=optimisation_pass)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. @@ -37,10 +37,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.7-optimisation-pass](https://github.com/Champii/Rock/releases/download/v0.1.7-optimisation-pass/rock) (Tested on arch, btw) +[Rock v0.1.7-develop](https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.7-optimisation-pass/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock chmod +x rock ./rock -V ``` From f084dd208f23d2c09bc4156715104c5b0b73767a Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 4 Oct 2021 02:23:24 -0700 Subject: [PATCH 16/74] Interpreter (#49) * Add basic interpreter and fix reassign resolve * Add some better colors for everything * Fix cargo warnings * Color fix and REPL section in README * Readme * First work on repl toplevel decl * Generated files for new version * Top level decl * Colors * Fix cargo * Generated files for new version * Cleanup Co-authored-by: Florian Greiner --- .github/templates/Cargo.toml | 2 +- .github/templates/README.md | 37 +++ Cargo.lock | 179 ++++++++++++++- Cargo.toml | 4 +- README.md | 45 +++- src/bin/main.rs | 22 +- src/lib/ast_lowering/return_placement.rs | 4 +- src/lib/codegen/codegen_context.rs | 21 +- src/lib/codegen/interpreter.rs | 212 ++++++++++++++++++ src/lib/codegen/mod.rs | 50 ++++- src/lib/diagnostics/diagnostic.rs | 60 +++-- src/lib/helpers/config.rs | 1 + src/lib/hir/has_hir_id.rs | 8 +- src/lib/hir/hir_printer.rs | 2 +- src/lib/hir/tree.rs | 17 +- src/lib/infer/constraint.rs | 2 +- src/lib/infer/state.rs | 46 +++- src/lib/parser/parser_impl.rs | 8 +- src/lib/parser/parsing_context.rs | 54 ++++- src/lib/parser/source_file.rs | 38 +++- src/lib/parser/token.rs | 10 + src/lib/resolver/resolve_ctx.rs | 24 +- src/lib/rock.rs | 38 +++- src/lib/testcases/basic/reassign_self/main.rk | 4 + .../testcases/basic/reassign_self/main.rk.out | 1 + .../basic/reassign_self/main.rk.stdout | 0 src/lib/tests.rs | 4 + 27 files changed, 783 insertions(+), 110 deletions(-) create mode 100644 src/lib/codegen/interpreter.rs create mode 100644 src/lib/testcases/basic/reassign_self/main.rk create mode 100644 src/lib/testcases/basic/reassign_self/main.rk.out create mode 100644 src/lib/testcases/basic/reassign_self/main.rk.stdout diff --git a/.github/templates/Cargo.toml b/.github/templates/Cargo.toml index 73b2e981..554ec945 100644 --- a/.github/templates/Cargo.toml +++ b/.github/templates/Cargo.toml @@ -11,7 +11,6 @@ regex = "1" env_logger = "0.5.12" log = "0.4" bitflags = "1.2.1" -concat-idents = "1.1.2" # inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm11-0"] } inkwell = { version = "0.1.0-beta.3", features = ["llvm12-0"] } either = "1.5" @@ -20,6 +19,7 @@ serde_derive = '*' bincode = "*" colored = "2.0.0" paste = "1.0.5" +rustyline = "9.0.0" [lib] name = "rock" diff --git a/.github/templates/README.md b/.github/templates/README.md index 75d01b71..15cfa52f 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -13,6 +13,8 @@ It's highly inspired from Livescript, and will borrow (pun intended) some featur - [With cargo from Git]( #with-cargo-from-git ) - [From sources]( #from-sources ) - [Quickstart]( #quickstart ) + - [Basic setup]( #basic-setup ) + - [REPL]( #repl ) - [Showcases]( #showcases ) - [Development notes]( #development-notes ) @@ -24,6 +26,7 @@ It's highly inspired from Livescript, and will borrow (pun intended) some featur - Typeclass (Traits) - Parametric Polymorphism by default - Compile to LLVM IR +- REPL (ALPHA) ## Install @@ -66,6 +69,8 @@ cargo run -- -V ## Quickstart +### Basic setup + Lets create a new project folder to compute some factorials ``` sh @@ -103,6 +108,38 @@ Should output 24 ``` +Take a look at `rock --help` for a quick tour of its flags and arguments + +### REPL + +You can start a REPL session with + +``` sh +rock -r +# OR +rock --repl +``` + +``` sh +Rock: {version} +---- + +Type ':?' for help + +> add a b = a + b +> let x = 30 +30 +> let y = 12 +12 +> add x, y +42 +> :t add +add: (Int64 -> Int64 -> Int64) +> _ +``` + +Only supports basic expressions for now. + ## Showcases ### Polymophic function diff --git a/Cargo.lock b/Cargo.lock index 6f883ecd..989048b9 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -31,6 +31,12 @@ dependencies = [ "winapi", ] +[[package]] +name = "autocfg" +version = "1.0.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cdb031dd78e28731d87d56cc8ffef4a8f36ca26c38fe2de700543e627f8a464a" + [[package]] name = "bincode" version = "1.3.3" @@ -73,6 +79,17 @@ dependencies = [ "vec_map", ] +[[package]] +name = "clipboard-win" +version = "4.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4e4ea1881992efc993e4dc50a324cdbd03216e41bdc8385720ff47efc9bd2ca8" +dependencies = [ + "error-code", + "str-buf", + "winapi", +] + [[package]] name = "colored" version = "2.0.0" @@ -85,13 +102,24 @@ dependencies = [ ] [[package]] -name = "concat-idents" -version = "1.1.3" +name = "dirs-next" +version = "2.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4b6f90860248d75014b7b103db8fee4f291c07bfb41306cdf77a0a5ab7a10d2f" +checksum = "b98cf8ebf19c3d1b223e151f99a4f9f0690dca41414773390fc824184ac833e1" dependencies = [ - "quote", - "syn", + "cfg-if", + "dirs-sys-next", +] + +[[package]] +name = "dirs-sys-next" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ebda144c4fe02d1f7ea1a7d9641b6fc6b580adcfa024ae48797ecdeb6825b4d" +dependencies = [ + "libc", + "redox_users", + "winapi", ] [[package]] @@ -100,6 +128,12 @@ version = "1.6.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "e78d4f1cc4ae33bbfc157ed5d5a5ef3bc29227303d595861deb238fcec4e9457" +[[package]] +name = "endian-type" +version = "0.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c34f04666d835ff5d62e058c3995147c06f42fe86ff053337632bca83e42702d" + [[package]] name = "env_logger" version = "0.5.13" @@ -113,6 +147,38 @@ dependencies = [ "termcolor", ] +[[package]] +name = "error-code" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b5115567ac25674e0043e472be13d14e537f37ea8aa4bdc4aef0c89add1db1ff" +dependencies = [ + "libc", + "str-buf", +] + +[[package]] +name = "fd-lock" +version = "3.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b8806dd91a06a7a403a8e596f9bfbfb34e469efbc363fc9c9713e79e26472e36" +dependencies = [ + "cfg-if", + "libc", + "winapi", +] + +[[package]] +name = "getrandom" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7fcd999463524c52659517fe2cea98493cfe485d10565e7b0fb07dbba7ad2753" +dependencies = [ + "cfg-if", + "libc", + "wasi", +] + [[package]] name = "hermit-abi" version = "0.1.19" @@ -215,6 +281,37 @@ version = "2.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "308cc39be01b73d0d18f82a0e7b2a3df85245f84af96fdddc5d202d27e47b86a" +[[package]] +name = "memoffset" +version = "0.6.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "59accc507f1338036a0477ef61afdae33cde60840f4dfe481319ce3ad116ddf9" +dependencies = [ + "autocfg", +] + +[[package]] +name = "nibble_vec" +version = "0.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "77a5d83df9f36fe23f0c3648c6bbb8b0298bb5f1939c8f2704431371f4b84d43" +dependencies = [ + "smallvec", +] + +[[package]] +name = "nix" +version = "0.22.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "cf1e25ee6b412c2a1e3fcb6a4499a5c1bfe7f43e014bdce9a6b6666e5aa2d187" +dependencies = [ + "bitflags", + "cc", + "cfg-if", + "libc", + "memoffset", +] + [[package]] name = "once_cell" version = "1.8.0" @@ -285,6 +382,16 @@ dependencies = [ "proc-macro2", ] +[[package]] +name = "radix_trie" +version = "0.2.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c069c179fcdc6a2fe24d8d18305cf085fdbd4f922c041943e203685d6a1c58fd" +dependencies = [ + "endian-type", + "nibble_vec", +] + [[package]] name = "redox_syscall" version = "0.2.10" @@ -294,6 +401,16 @@ dependencies = [ "bitflags", ] +[[package]] +name = "redox_users" +version = "0.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "528532f3d801c87aec9def2add9ca802fe569e44a544afe633765267840abe64" +dependencies = [ + "getrandom", + "redox_syscall", +] + [[package]] name = "regex" version = "1.5.4" @@ -313,13 +430,12 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rock" -version = "0.1.7-develop" +version = "0.1.7-interpreter" dependencies = [ "bincode", "bitflags", "clap", "colored", - "concat-idents", "either", "env_logger", "inkwell", @@ -327,10 +443,35 @@ dependencies = [ "log", "paste", "regex", + "rustyline", "serde", "serde_derive", ] +[[package]] +name = "rustyline" +version = "9.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "790487c3881a63489ae77126f57048b42d62d3b2bafbf37453ea19eedb6340d6" +dependencies = [ + "bitflags", + "cfg-if", + "clipboard-win", + "dirs-next", + "fd-lock", + "libc", + "log", + "memchr", + "nix", + "radix_trie", + "scopeguard", + "smallvec", + "unicode-segmentation", + "unicode-width", + "utf8parse", + "winapi", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -378,6 +519,12 @@ version = "1.7.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "1ecab6c735a6bb4139c0caafd0cc3635748bbb3acf4550e8138122099251f309" +[[package]] +name = "str-buf" +version = "1.0.5" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "d44a3643b4ff9caf57abcee9c2c621d6c03d9135e0d8b589bd9afb5992cb176a" + [[package]] name = "strsim" version = "0.8.0" @@ -419,6 +566,12 @@ version = "0.1.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "56dee185309b50d1f11bfedef0fe6d036842e3fb77413abef29f8f8d1c5d4c1c" +[[package]] +name = "unicode-segmentation" +version = "1.8.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8895849a949e7845e06bd6dc1aa51731a103c42707010a5b591c0038fb73385b" + [[package]] name = "unicode-width" version = "0.1.9" @@ -431,12 +584,24 @@ version = "0.2.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "8ccb82d61f80a663efe1f787a51b16b5a51e3314d6ac365b08639f52387b33f3" +[[package]] +name = "utf8parse" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "936e4b492acfd135421d8dca4b1aa80a7bfc26e702ef3af710e0752684df5372" + [[package]] name = "vec_map" version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "wasi" +version = "0.10.2+wasi-snapshot-preview1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "fd6fbd9a79829dd1ad0cc20627bf1ed606756a7f77edff7b66b7064f9cb327c6" + [[package]] name = "winapi" version = "0.3.9" diff --git a/Cargo.toml b/Cargo.toml index f9860a46..31d2b310 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.7-develop" +version = "0.1.7-interpreter" authors = ["champii "] edition = "2018" @@ -11,7 +11,6 @@ regex = "1" env_logger = "0.5.12" log = "0.4" bitflags = "1.2.1" -concat-idents = "1.1.2" # inkwell = { git = "https://github.com/TheDan64/inkwell", branch = "master", features = ["llvm11-0"] } inkwell = { version = "0.1.0-beta.3", features = ["llvm12-0"] } either = "1.5" @@ -20,6 +19,7 @@ serde_derive = '*' bincode = "*" colored = "2.0.0" paste = "1.0.5" +rustyline = "9.0.0" [lib] name = "rock" diff --git a/README.md b/README.md index 1a1a99ac..5c7462b2 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.7-develop +# Rock v0.1.7-interpreter -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=interpreter)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. @@ -13,6 +13,8 @@ It's highly inspired from Livescript, and will borrow (pun intended) some featur - [With cargo from Git]( #with-cargo-from-git ) - [From sources]( #from-sources ) - [Quickstart]( #quickstart ) + - [Basic setup]( #basic-setup ) + - [REPL]( #repl ) - [Showcases]( #showcases ) - [Development notes]( #development-notes ) @@ -24,6 +26,7 @@ It's highly inspired from Livescript, and will borrow (pun intended) some featur - Typeclass (Traits) - Parametric Polymorphism by default - Compile to LLVM IR +- REPL (ALPHA) ## Install @@ -37,10 +40,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.7-develop](https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock) (Tested on arch, btw) +[Rock v0.1.7-interpreter](https://github.com/Champii/Rock/releases/download/v0.1.7-interpreter/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.7-interpreter/rock chmod +x rock ./rock -V ``` @@ -66,6 +69,8 @@ cargo run -- -V ## Quickstart +### Basic setup + Lets create a new project folder to compute some factorials ``` sh @@ -103,6 +108,38 @@ Should output 24 ``` +Take a look at `rock --help` for a quick tour of its flags and arguments + +### REPL + +You can start a REPL session with + +``` sh +rock -r +# OR +rock --repl +``` + +``` sh +Rock: v0.1.7-interpreter +---- + +Type ':?' for help + +> add a b = a + b +> let x = 30 +30 +> let y = 12 +12 +> add x, y +42 +> :t add +add: (Int64 -> Int64 -> Int64) +> _ +``` + +Only supports basic expressions for now. + ## Showcases ### Polymophic function diff --git a/src/bin/main.rs b/src/bin/main.rs index 969cd587..b6d5b808 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -19,7 +19,7 @@ fn build(config: &Config) -> bool { fs::create_dir_all(config.build_folder.clone()).unwrap(); - if let Err(diagnostic) = rock::parse_file(entry_file.to_string(), config) { + if let Err(diagnostic) = rock::compile_file(entry_file.to_string(), config) { if let DiagnosticKind::NoError = diagnostic.get_kind() { } else { println!("Error: {}", diagnostic.get_kind()); @@ -89,47 +89,62 @@ fn main() { Arg::with_name("verbose") .takes_value(false) .short("v") + .long("verbose") .help("Verbose level"), ) .arg( Arg::with_name("tokens") .short("t") + .long("tokens") .takes_value(false) .help("Show tokens"), ) .arg( Arg::with_name("ast") .short("a") + .long("ast") .takes_value(false) .help("Show ast"), ) .arg( Arg::with_name("hir") .short("h") + .long("hir") .takes_value(false) .help("Show hir"), ) .arg( Arg::with_name("no-optimize") .short("N") + .long("no-optimize") .takes_value(false) .help("Disable LLVM optimization passes"), ) + .arg( + Arg::with_name("repl") + .short("r") + .long("repl") + .takes_value(false) + .help("Run a REPL interpreter (ALPHA)"), + ) .arg( Arg::with_name("ir") .short("i") + .long("ir") .takes_value(false) .help("Show the generated IR"), ) .arg( Arg::with_name("state") .short("s") + .long("state") .takes_value(false) - .help("Show the InferContext state before solve"), + .help("Show the InferContext state before solve (DEPRECATED)"), ) .arg( Arg::with_name("output-folder") .short("o") + .long("output-folder") .takes_value(true) .default_value("./build") .help("Choose a different output folder"), @@ -145,6 +160,7 @@ fn main() { show_hir: matches.is_present("hir"), show_ir: matches.is_present("ir"), show_state: matches.is_present("state"), + repl: matches.is_present("repl"), no_optimize: matches.is_present("no-optimize"), build_folder: PathBuf::from(matches.value_of("output-folder").unwrap()), ..Default::default() @@ -156,6 +172,8 @@ fn main() { build(&config); } else if let Some(_matches) = matches.subcommand_matches("run") { run(config); + } else if config.repl { + run(config) } else { println!("{}", matches.usage()); } diff --git a/src/lib/ast_lowering/return_placement.rs b/src/lib/ast_lowering/return_placement.rs index 63f8ce45..20507d26 100644 --- a/src/lib/ast_lowering/return_placement.rs +++ b/src/lib/ast_lowering/return_placement.rs @@ -27,8 +27,8 @@ impl<'a> ReturnInserter<'a> { StatementKind::If(ref mut i) => { self.visit_if(i); } - StatementKind::Assign(ref mut _a) => { - unimplemented!("Assign as return value"); + StatementKind::Assign(ref mut a) => { + a.value.kind = ExpressionKind::Return(Box::new(a.value.clone())); } } } diff --git a/src/lib/codegen/codegen_context.rs b/src/lib/codegen/codegen_context.rs index 10218a11..b8a10ad1 100644 --- a/src/lib/codegen/codegen_context.rs +++ b/src/lib/codegen/codegen_context.rs @@ -14,10 +14,8 @@ use inkwell::{ }; use crate::{ - diagnostics::Diagnostic, helpers::scopes::Scopes, hir::*, - parser::ParsingCtx, ty::{PrimitiveType, Type}, }; @@ -27,11 +25,10 @@ pub struct CodegenContext<'a> { pub module: Module<'a>, pub scopes: Scopes>, pub cur_func: Option>, - pub parsing_ctx: ParsingCtx, } impl<'a> CodegenContext<'a> { - pub fn new(context: &'a Context, parsing_ctx: ParsingCtx, hir: &'a Root) -> Self { + pub fn new(context: &'a Context, hir: &'a Root) -> Self { let module = context.create_module("mod"); Self { @@ -40,7 +37,6 @@ impl<'a> CodegenContext<'a> { hir, scopes: Scopes::new(), cur_func: None, - parsing_ctx, } } @@ -683,21 +679,6 @@ impl<'a> CodegenContext<'a> { let val = match self.scopes.get(reso) { None => { - let span = self - .hir - .hir_map - .get_node_id(&id.hir_id) - .map(|node_id| self.hir.spans.get(&node_id).unwrap().clone()) - .unwrap(); - - self.parsing_ctx - .diagnostics - .push_error(Diagnostic::new_codegen_error( - span, - id.hir_id.clone(), - "Cannot resolve identifier", - )); - return Err(()); } Some(val) => val, diff --git a/src/lib/codegen/interpreter.rs b/src/lib/codegen/interpreter.rs new file mode 100644 index 00000000..2a34ca38 --- /dev/null +++ b/src/lib/codegen/interpreter.rs @@ -0,0 +1,212 @@ +use colored::*; +use rustyline::{error::ReadlineError, Editor}; + +use inkwell::{ + builder::Builder, + context::Context, + targets::{InitializationConfig, Target}, + OptimizationLevel, +}; + +use crate::{ + parser::{ParsingCtx, SourceFile}, + ty::Type, + Config, +}; + +use super::codegen_context::CodegenContext; + +pub fn interpret<'a, 'ctx>( + _codegen_ctx: &'a mut CodegenContext<'ctx>, + _builder: &'ctx Builder, + rock_config: &Config, +) { + println!( + "{}{} {}{}\n{}\n\n{}\n", + "Rock".green(), + ":".bright_black(), + "v".bright_cyan(), + env!("CARGO_PKG_VERSION").cyan(), + "----".bright_black(), + "Type ':?' for help".bright_black() + ); + + let config = InitializationConfig::default(); + + Target::initialize_native(&config).unwrap(); + + let mut commands = vec![]; + let mut toplevels = vec![]; + + let mut rl = Editor::<()>::new(); + + if rl.load_history("history.txt").is_err() {} + + loop { + let readline = rl.readline(&"> ".yellow().to_string()); + + match readline { + Ok(line) => { + rl.add_history_entry(line.as_str()); + + if line == "exit" || line == "quit" { + break; + } + + process_line(line, &mut commands, &mut toplevels, rock_config); + } + Err(ReadlineError::Interrupted) => { + break; + } + Err(ReadlineError::Eof) => { + break; + } + Err(err) => { + println!("Error: {:?}", err); + break; + } + } + } + + rl.save_history("history.txt").unwrap(); +} + +fn process_line( + mut line: String, + commands: &mut Vec, + top_levels: &mut Vec, + config: &Config, +) { + if line.is_empty() { + return; + } + + let mut get_type = false; + + if line.starts_with(":?") { + print_help(); + + return; + } + + if line.starts_with(":t ") { + get_type = true; + + line.replace_range(0..3, ""); + } + + if line.starts_with("print ") { + line.replace_range(0..6, ""); + } + + let mut is_top_level = false; + + // FIXME: dirty hack to know if this is a function + let line_parts = line.split("=").collect::>(); + if line_parts.len() > 1 + && !line_parts[0].starts_with("let ") + && line_parts[0].split(" ").count() > 1 + { + is_top_level = true; + } else { + if line.starts_with("use ") || line.starts_with("mod ") { + is_top_level = true; + } + } + + if is_top_level { + top_levels.push(line.clone()); + } else { + if !get_type { + commands.push(" ".to_owned() + &line); + } + } + + let mut parsing_ctx = ParsingCtx::new(&config); + + let src = + SourceFile::from_expr(top_levels.join("\n"), commands.join("\n"), !is_top_level).unwrap(); + + parsing_ctx.add_file(&src); + + let hir = match crate::parse_str(&mut parsing_ctx, config) { + Ok(hir) => hir, + Err(_e) => { + if is_top_level { + top_levels.pop(); + } else { + if !get_type { + commands.pop(); + } + } + + return; + } + }; + + if get_type { + if is_top_level { + top_levels.pop(); + } else { + // commands.pop(); + } + } + + if get_type { + let t = hir + .get_function_by_name(line.split(" ").nth(0).unwrap()) + .map(|f| format!("{:?}", Type::from(f.signature.clone()))) + .or_else(|| Some("UNKNOWN".red().to_string())) + .unwrap(); + + println!("{}: {}", line, t); + + return; + } + + let context = Context::create(); + let builder = context.create_builder(); + + let mut codegen_ctx = CodegenContext::new(&context, &hir); + + if codegen_ctx.lower_hir(&hir, &builder).is_err() {} + + match codegen_ctx.module.verify() { + Ok(_) => (), + Err(e) => { + codegen_ctx.module.print_to_stderr(); + + println!("Error: Bug in the generated IR:\n\n{}", e.to_string()); + + return; + } + } + + if !config.no_optimize { + codegen_ctx.optimize(); + } + + if config.show_ir { + codegen_ctx.module.print_to_stderr(); + } + + let engine = codegen_ctx + .module + .create_jit_execution_engine(OptimizationLevel::None) + .unwrap(); + + unsafe { + engine.run_function_as_main(engine.get_function_value("main").unwrap(), &[]); + } +} + +pub fn print_help() { + println!( + "\n{}\n\n {} : {}\n {} : {}\n", + "Help:".bright_green(), + ":t".bright_yellow(), + "Print the type of an expression".bright_black(), + ":?".bright_yellow(), + "Print This help".bright_black(), + ); +} diff --git a/src/lib/codegen/mod.rs b/src/lib/codegen/mod.rs index ad26d1c8..360d2674 100644 --- a/src/lib/codegen/mod.rs +++ b/src/lib/codegen/mod.rs @@ -1,26 +1,27 @@ mod codegen_context; +mod interpreter; use codegen_context::*; use inkwell::context::Context; -use crate::{diagnostics::Diagnostic, hir::Root, parser::ParsingCtx, Config}; +use crate::{diagnostics::Diagnostic, hir::Root, Config}; -pub fn generate( - config: &Config, - parsing_ctx: ParsingCtx, - hir: Root, -) -> Result { +pub fn generate(config: &Config, hir: Root) -> Result<(), Diagnostic> { let context = Context::create(); let builder = context.create_builder(); - let mut codegen_ctx = CodegenContext::new(&context, parsing_ctx, &hir); + let mut codegen_ctx = CodegenContext::new(&context, &hir); + if codegen_ctx.lower_hir(&hir, &builder).is_err() { - codegen_ctx.parsing_ctx.return_if_error()?; + // FIXME: have a movable `Diagnostics` + // codegen_ctx.parsing_ctx.return_if_error()?; } match codegen_ctx.module.verify() { Ok(_) => (), Err(e) => { + codegen_ctx.module.print_to_stderr(); + println!("Error: Bug in the generated IR:\n\n{}", e.to_string()); return Err(Diagnostic::new_empty()); @@ -42,5 +43,36 @@ pub fn generate( panic!("CANNOT IR WRITE TO PATH"); } - Ok(codegen_ctx.parsing_ctx) + Ok(()) +} + +pub fn interpret(hir: Root, config: &Config) -> Result<(), Diagnostic> { + let context = Context::create(); + let builder = context.create_builder(); + + let mut codegen_ctx = CodegenContext::new(&context, &hir); + + if codegen_ctx.lower_hir(&hir, &builder).is_err() { + // FIXME: have a movable `Diagnostics` + // codegen_ctx.parsing_ctx.return_if_error()?; + } + + match codegen_ctx.module.verify() { + Ok(_) => (), + Err(e) => { + codegen_ctx.module.print_to_stderr(); + + println!("Error: Bug in the generated IR:\n\n{}", e.to_string()); + + return Err(Diagnostic::new_empty()); + } + } + + interpreter::interpret(&mut codegen_ctx, &builder, config); + + // if config.show_ir { + // codegen_ctx.module.print_to_stderr(); + // } + + Ok(()) } diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index 2d33952c..3bcb97e6 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -46,8 +46,8 @@ impl Diagnostic { Self::new(span, DiagnosticKind::UnusedFunction) } - pub fn new_module_not_found(span: Span) -> Self { - Self::new(span, DiagnosticKind::ModuleNotFound) + pub fn new_module_not_found(span: Span, path: String) -> Self { + Self::new(span, DiagnosticKind::ModuleNotFound(path)) } pub fn new_unresolved_type(span: Span, t: Type) -> Self { @@ -85,6 +85,7 @@ impl Diagnostic { pub fn new_no_main() -> Self { Self::new(Span::new_placeholder(), DiagnosticKind::NoMain) } + pub fn new_type_conflict(span: Span, t1: Type, t2: Type, in1: Type, in2: Type) -> Self { Self::new(span, DiagnosticKind::TypeConflict(t1, t2, in1, in2)) } @@ -143,19 +144,50 @@ impl Diagnostic { DiagnosticType::Warning => x.yellow(), }; - println!( - "[{}]: {}\n{}\n{:>4} {}\n{:>4} {} {}\n{:>4} {} {}", + let color_bright = |x: String| match diag_type { + DiagnosticType::Error => x.bright_red(), + DiagnosticType::Warning => x.bright_yellow(), + }; + + let diag_type_str = format!( + "{}{}{} {}{}", + "[".bright_black(), diag_type_str, + "]".bright_black(), color(self.kind.to_string()).bold(), - line_ind.bright_blue(), + ":".bright_black(), + ); + + let line_span_start = line_start; + let mut line_span_stop = line_start + (self.span.end - self.span.start) + 1; + + let line_colored = lines[line - 1].iter().cloned().collect::(); + if line_span_stop > line_colored.len() { + line_span_stop = line_colored.len() - 1; + } + + let first_part = &line_colored[..line_span_start]; + let colored_part = color(line_colored[line_span_start..=line_span_stop].to_string()); + let last_part = if line_span_stop + 1 >= line_colored.len() { + String::new() + } else { + line_colored[line_span_stop + 1..].to_owned() + }; + + let line_colored = format!("{}{}{}", first_part, colored_part, last_part,); + + println!( + "{}\n{}\n{:>4} {}\n{:>4} {} {}\n{:>4} {} {}", + diag_type_str, + line_ind.bright_black(), "", - "|".cyan(), - color(line.to_string()), - "|".cyan(), - lines[line - 1].iter().cloned().collect::(), + "|".bright_black(), + color_bright(line.to_string()), + "|".bright_black(), + line_colored, "", - "|".cyan(), - color(arrow), + "|".bright_black(), + color_bright(arrow), ); } @@ -170,7 +202,7 @@ pub enum DiagnosticKind { UnexpectedToken, SyntaxError(String), UnknownIdentifier, - ModuleNotFound, + ModuleNotFound(String), NotAFunction, UnusedParameter, UnresolvedTraitCall { @@ -194,7 +226,7 @@ impl Display for DiagnosticKind { Self::UnexpectedToken => "UnexpectedToken".to_string(), Self::SyntaxError(msg) => format!("SyntaxError: {}", msg), Self::UnknownIdentifier => "UnknownIdentifier".to_string(), - Self::ModuleNotFound => "ModuleNotFound".to_string(), + Self::ModuleNotFound(path) => format!("Module not found: {}", path), Self::DuplicatedOperator => "DuplicatedOperator".to_string(), Self::TypeConflict(t1, t2, _in1, _in2) => { format!("Type conflict: Expected {:?} but got {:?} ", t1, t2) @@ -215,7 +247,7 @@ impl Display for DiagnosticKind { given_sig, existing_impls .iter() - .map(|sig| format!("Found impl: {:?}", sig)) + .map(|sig| format!(" Found impl: {:?}", sig)) .collect::>() .join("\n") ) diff --git a/src/lib/helpers/config.rs b/src/lib/helpers/config.rs index baeb7cab..86f3ef6b 100644 --- a/src/lib/helpers/config.rs +++ b/src/lib/helpers/config.rs @@ -32,4 +32,5 @@ pub struct Config { pub verbose: bool, pub build_folder: PathBuf, pub no_optimize: bool, + pub repl: bool, } diff --git a/src/lib/hir/has_hir_id.rs b/src/lib/hir/has_hir_id.rs index d8774cec..023fc3d6 100644 --- a/src/lib/hir/has_hir_id.rs +++ b/src/lib/hir/has_hir_id.rs @@ -51,14 +51,20 @@ macro_rules! impl_indirect_get_hir_id_trait { impl_indirect_get_hir_id_trait!( TopLevel + Statement Assign AssignLeftSide ArgumentDecl IdentifierPath FnBody Body - Statement Expression Array Else ); + +impl HasHirId for Vec { + fn get_hir_id(&self) -> HirId { + self.last().unwrap().get_hir_id() + } +} diff --git a/src/lib/hir/hir_printer.rs b/src/lib/hir/hir_printer.rs index 2395b5a0..2ae6abce 100644 --- a/src/lib/hir/hir_printer.rs +++ b/src/lib/hir/hir_printer.rs @@ -47,7 +47,7 @@ impl<'a> HirPrinter<'a> { .map_or_else(|| String::from("None"), |t| format!("{:?}", t)); println!( - "{:>13}{:-<60} {}", + "{:<10}{:-<60} {}", t.get_hir_id(), self.make_indent_str(t.class_name_self().magenta()), ty diff --git a/src/lib/hir/tree.rs b/src/lib/hir/tree.rs index 7ad6117f..38cadbfb 100644 --- a/src/lib/hir/tree.rs +++ b/src/lib/hir/tree.rs @@ -10,7 +10,7 @@ use crate::{ ty::{FuncType, StructType, Type}, }; -use super::{arena::Arena, HasHirId}; +use super::{arena::Arena, hir_printer, HasHirId}; #[derive(Debug, Default)] pub struct Root { @@ -126,6 +126,10 @@ impl Root { .filter_map(|(node_id, span)| Some((self.hir_map.get_hir_id(*node_id)?, span.clone()))) .collect() } + + pub fn print(&self) { + hir_printer::print(self); + } } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -427,6 +431,11 @@ impl Expression { kind: Box::new(ExpressionKind::Dot(dot)), } } + pub fn new_return(ret: Expression) -> Self { + Self { + kind: Box::new(ExpressionKind::Return(ret)), + } + } pub fn get_terminal_hir_id(&self) -> HirId { match &*self.kind { @@ -528,6 +537,12 @@ impl Literal { panic!("Not a number"); } } + pub fn new_int64(i: i64) -> Self { + Self { + hir_id: HirId(0), + kind: LiteralKind::Number(i), + } + } } #[derive(Debug, Clone, Serialize, Deserialize)] diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index e2fc21e4..286e3db8 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -405,8 +405,8 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { } fn visit_assign(&mut self, assign: &'a Assign) { - self.visit_assign_left_side(&assign.name); self.visit_expression(&assign.value); + self.visit_assign_left_side(&assign.name); self.envs .set_type_eq(&assign.name.get_hir_id(), &assign.value.get_hir_id()); diff --git a/src/lib/infer/state.rs b/src/lib/infer/state.rs index d25e3647..f7ad34e4 100644 --- a/src/lib/infer/state.rs +++ b/src/lib/infer/state.rs @@ -62,27 +62,30 @@ impl Envs { self.current_fn.clone() } - pub fn set_type(&mut self, dest: &HirId, src: &Type) { + fn set_type_alone(&mut self, dest: &HirId, src: &Type) -> Option { if let Type::ForAll(_) = src { warn!("set_type requires `src: &Type` to be solved"); - return; + return None; } - let previous = self - .get_current_env_mut() + self.get_current_env_mut() .unwrap() - .insert(dest.clone(), src.clone()); + .insert(dest.clone(), src.clone()) + } + + pub fn set_type(&mut self, dest: &HirId, src: &Type) { + let previous = self.set_type_alone(dest, src); match (src, previous.clone()) { (Type::Func(src_f), Some(Type::Func(prev_f))) if !src_f.eq(&prev_f) => { if prev_f.is_solved() && src_f.is_solved() { self.diagnostics.push_error(Diagnostic::new_type_conflict( self.spans.get(dest).unwrap().clone(), - src.clone(), previous.clone().unwrap(), src.clone(), previous.unwrap(), + src.clone(), )); } } @@ -90,10 +93,10 @@ impl Envs { if previous.is_solved() && src.is_solved() { self.diagnostics.push_error(Diagnostic::new_type_conflict( self.spans.get(dest).unwrap().clone(), - src.clone(), previous.clone(), src.clone(), previous, + src.clone(), )); } } @@ -102,7 +105,34 @@ impl Envs { } pub fn set_type_eq(&mut self, dest: &HirId, src: &HirId) { - self.set_type(dest, &self.get_type(src).unwrap().clone()) + let src_t = self.get_type(src).unwrap().clone(); + let previous = self.set_type_alone(dest, &src_t); + + match (src_t.clone(), previous.clone()) { + (Type::Func(src_f), Some(Type::Func(prev_f))) if !src_f.eq(&prev_f) => { + if prev_f.is_solved() && src_f.is_solved() { + self.diagnostics.push_error(Diagnostic::new_type_conflict( + self.spans.get(src).unwrap().clone(), + previous.clone().unwrap(), + src_t.clone(), + previous.unwrap(), + src_t.clone(), + )); + } + } + (src_t, Some(previous)) if !src_t.eq(&previous) => { + if previous.is_solved() && src_t.is_solved() { + self.diagnostics.push_error(Diagnostic::new_type_conflict( + self.spans.get(src).unwrap().clone(), + previous.clone(), + src_t.clone(), + previous, + src_t.clone(), + )); + } + } + _ => (), + } } pub fn get_type(&self, hir_id: &HirId) -> Option<&Type> { diff --git a/src/lib/parser/parser_impl.rs b/src/lib/parser/parser_impl.rs index 94ea955e..945c3ae2 100644 --- a/src/lib/parser/parser_impl.rs +++ b/src/lib/parser/parser_impl.rs @@ -131,7 +131,7 @@ impl<'a> Parser<'a> { pub fn cur_tok(&self) -> Token { match self.tokens.get(self.cur_tok_id as usize) { Some(a) => a.clone(), - _ => unreachable!(), + _ => Token::eof(), } } @@ -164,11 +164,7 @@ impl<'a> Parser<'a> { pub fn seek(&self, distance: usize) -> Token { match self.tokens.get(self.cur_tok_id as usize + distance) { Some(a) => a.clone(), - _ => Token { - t: TokenType::Eof, - span: Span::new_placeholder(), - txt: "".to_string(), - }, + _ => Token::eof(), } } diff --git a/src/lib/parser/parsing_context.rs b/src/lib/parser/parsing_context.rs index 90c103b5..9f04d0a5 100644 --- a/src/lib/parser/parsing_context.rs +++ b/src/lib/parser/parsing_context.rs @@ -51,15 +51,35 @@ impl ParsingCtx { self.print_diagnostics(); if !self.diagnostics.list.is_empty() { + let diag_type_str = format!( + "{}{}{}", + "[".bright_black(), + "Success".green(), + "]".bright_black(), + ); + println!( - "[{}] Compilation {} with {} {}", - "Warning".yellow(), - "successful".green(), + "{} {} {} {} {} {}", + diag_type_str, + "Compilation".bright_black(), + "successful".bright_green(), + "with".bright_black(), self.diagnostics.list.len().to_string().yellow(), - "warnings".yellow(), + "warnings".bright_yellow(), ); } else if self.config.verbose { - println!("[{}] Compilation successful", "Success".green(),); + let diag_type_str = format!( + "{}{}{}", + "[".bright_black(), + "Success".green(), + "]".bright_black(), + ); + + println!( + "{} {}", + diag_type_str, + "Compilation successful".bright_black(), + ); } } @@ -79,14 +99,24 @@ impl ParsingCtx { ) }); - println!( - "[{}] Compilation {} with {} {} and {} {}", + let diag_type_str = format!( + "{}{}{}", + "[".bright_black(), "Error".red(), - "stopped".red(), + "]".bright_black(), + ); + + println!( + "{} {} {} {} {} {} {} {} {}", + diag_type_str, + "Compilation".bright_black(), + "stopped".bright_red(), + "with".bright_black(), errors.len().to_string().red(), - "errors".red(), + "errors".bright_red(), + "and".bright_black(), warnings.len().to_string().yellow(), - "warnings".yellow(), + "warnings".bright_yellow(), ); return Err(Diagnostic::new_empty()); @@ -102,9 +132,9 @@ impl ParsingCtx { pub fn resolve_and_add_file(&mut self, name: String) -> Result { let current_file = self.get_current_file(); - let new_file = current_file.resolve_new(name).map_err(|_| { + let new_file = current_file.resolve_new(name.clone()).map_err(|m| { // Placeholder span, to be overriden by calling mod (TopLevel::parse()) - Diagnostic::new_module_not_found(Span::new(current_file.file_path.clone(), 0, 0)) + Diagnostic::new_module_not_found(Span::new(current_file.file_path.clone(), 0, 0), m) })?; if self.config.verbose { diff --git a/src/lib/parser/source_file.rs b/src/lib/parser/source_file.rs index 04c105b7..bd2a649a 100644 --- a/src/lib/parser/source_file.rs +++ b/src/lib/parser/source_file.rs @@ -31,7 +31,41 @@ impl SourceFile { }) } - pub fn resolve_new(&self, name: String) -> Result { + pub fn from_expr( + top_levels: String, + mut expr: String, + do_print: bool, + ) -> Result { + let print_str = if do_print { "print " } else { "" }; + + if expr.is_empty() { + expr = " 0".to_string(); + } + + let top_levels = r##"mod lib +use lib::prelude::* +"## + .to_owned() + + &top_levels + + &r##" + +main = + "## + &print_str.to_string() + + &r##"custom() + 0 +custom = +"## + .to_owned() + + &expr; + + Ok(SourceFile { + file_path: PathBuf::from("./src/main.rk"), + mod_path: PathBuf::from("root"), + content: top_levels, + }) + } + + pub fn resolve_new(&self, name: String) -> Result { let mut file_path = self.file_path.parent().unwrap().join(Path::new(&name)); file_path.set_extension("rk"); @@ -40,7 +74,7 @@ impl SourceFile { let content = match fs::read_to_string(file_path.to_str().unwrap().to_string()) { Ok(content) => content, - Err(_) => return Err(()), + Err(_) => return Err(mod_path.as_path().to_str().unwrap().to_string()), }; Ok(Self { diff --git a/src/lib/parser/token.rs b/src/lib/parser/token.rs index c7804ba4..d8529281 100644 --- a/src/lib/parser/token.rs +++ b/src/lib/parser/token.rs @@ -73,3 +73,13 @@ pub struct Token { } pub type TokenId = usize; + +impl Token { + pub fn eof() -> Self { + Token { + t: TokenType::Eof, + span: Span::new_placeholder(), + txt: "".to_string(), + } + } +} diff --git a/src/lib/resolver/resolve_ctx.rs b/src/lib/resolver/resolve_ctx.rs index c65f6bbf..77059c0a 100644 --- a/src/lib/resolver/resolve_ctx.rs +++ b/src/lib/resolver/resolve_ctx.rs @@ -91,13 +91,15 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { } fn visit_assign(&mut self, assign: &'a Assign) { + self.visit_expression(&assign.value); + match &assign.name { AssignLeftSide::Identifier(id) => { if !assign.is_let { - let previous_assign_node_id = self.get(id.name.clone()).unwrap(); - - self.resolutions - .insert(id.identity.node_id, previous_assign_node_id.node_id); + if let Some(previous_assign_node_id) = self.get(id.name.clone()) { + self.resolutions + .insert(id.identity.node_id, previous_assign_node_id.node_id); + } self.visit_identifier(id) } @@ -107,8 +109,6 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { AssignLeftSide::Indice(expr) => self.visit_expression(expr), AssignLeftSide::Dot(expr) => self.visit_expression(expr), } - - self.visit_expression(&assign.value); } fn visit_top_level(&mut self, top: &'a TopLevel) { @@ -200,6 +200,12 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { .diagnostics .push_error(Diagnostic::new_module_not_found( ident.identity.span.clone(), + mod_path + .path + .iter() + .map(|p| p.name.clone()) + .collect::>() + .join("/"), )), }; } @@ -241,6 +247,12 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { .diagnostics .push_error(Diagnostic::new_module_not_found( ident.identity.span.clone(), + mod_path + .path + .iter() + .map(|p| p.name.clone()) + .collect::>() + .join("/"), )), }; } diff --git a/src/lib/rock.rs b/src/lib/rock.rs index ac0950f1..68d2cdee 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -28,30 +28,45 @@ mod resolver; mod tests; mod ty; +use codegen::interpret; use diagnostics::Diagnostic; pub use helpers::config::Config; use parser::{ParsingCtx, SourceFile}; -pub fn parse_file(in_name: String, config: &Config) -> Result<(), Diagnostic> { +pub fn compile_file(in_name: String, config: &Config) -> Result<(), Diagnostic> { let mut source_file = SourceFile::from_file(in_name)?; source_file.mod_path = PathBuf::from("root"); - parse_str(&source_file, config) + compile_str(&source_file, config) } -pub fn parse_str(input: &SourceFile, config: &Config) -> Result<(), Diagnostic> { +pub fn compile_str(input: &SourceFile, config: &Config) -> Result<(), Diagnostic> { let mut parsing_ctx = ParsingCtx::new(config); parsing_ctx.add_file(input); + let hir = parse_str(&mut parsing_ctx, config)?; + + if config.repl { + interpret(hir, config) + } else { + generate_ir(hir, config)?; + + parsing_ctx.print_success_diagnostics(); + + Ok(()) + } +} + +pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { // Text to Ast debug!(" -> Parsing"); - let mut ast = parser::parse_root(&mut parsing_ctx)?; + let mut ast = parser::parse_root(parsing_ctx)?; // Name resolving debug!(" -> Resolving"); - resolver::resolve(&mut ast, &mut parsing_ctx)?; + resolver::resolve(&mut ast, parsing_ctx)?; // Lowering to HIR debug!(" -> Lowering to HIR"); @@ -59,17 +74,18 @@ pub fn parse_str(input: &SourceFile, config: &Config) -> Result<(), Diagnostic> // Infer Hir debug!(" -> Infer HIR"); - let new_hir = infer::infer(&mut hir, &mut parsing_ctx, config)?; + let new_hir = infer::infer(&mut hir, parsing_ctx, config)?; + + Ok(new_hir) +} +pub fn generate_ir(hir: hir::Root, config: &Config) -> Result<(), Diagnostic> { // Generate code debug!(" -> Lower to LLVM IR"); - let parsing_ctx = codegen::generate(config, parsing_ctx, new_hir)?; - - parsing_ctx.print_success_diagnostics(); + codegen::generate(config, hir)?; Ok(()) } - mod test { use super::*; use crate::{parser::SourceFile, Config}; @@ -86,7 +102,7 @@ mod test { content: input, }; - if let Err(_e) = parse_str(&file, &config) { + if let Err(_e) = compile_str(&file, &config) { return false; } diff --git a/src/lib/testcases/basic/reassign_self/main.rk b/src/lib/testcases/basic/reassign_self/main.rk new file mode 100644 index 00000000..25fb1dbf --- /dev/null +++ b/src/lib/testcases/basic/reassign_self/main.rk @@ -0,0 +1,4 @@ +main = + let a = 21 + a = ~IAdd a a + a diff --git a/src/lib/testcases/basic/reassign_self/main.rk.out b/src/lib/testcases/basic/reassign_self/main.rk.out new file mode 100644 index 00000000..f70d7bba --- /dev/null +++ b/src/lib/testcases/basic/reassign_self/main.rk.out @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/lib/testcases/basic/reassign_self/main.rk.stdout b/src/lib/testcases/basic/reassign_self/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/tests.rs b/src/lib/tests.rs index c679ba61..31e211a8 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -82,6 +82,10 @@ fn testcases_basic_monomorph_in_trait_main() { run("testcases/basic/monomorph_in_trait/main.rk", include_str!("testcases/basic/monomorph_in_trait/main.rk"), include_str!("testcases/basic/monomorph_in_trait/main.rk.out"), include_str!("testcases/basic/monomorph_in_trait/main.rk.stdout")); } #[test] +fn testcases_basic_reassign_self_main() { + run("testcases/basic/reassign_self/main.rk", include_str!("testcases/basic/reassign_self/main.rk"), include_str!("testcases/basic/reassign_self/main.rk.out"), include_str!("testcases/basic/reassign_self/main.rk.stdout")); +} +#[test] fn testcases_basic_trait_use_before_decl_main() { run("testcases/basic/trait_use_before_decl/main.rk", include_str!("testcases/basic/trait_use_before_decl/main.rk"), include_str!("testcases/basic/trait_use_before_decl/main.rk.out"), include_str!("testcases/basic/trait_use_before_decl/main.rk.stdout")); } From 63d7e1d81d527f7f2101fa8fb57aa8f6a3d8862c Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 4 Oct 2021 09:23:43 +0000 Subject: [PATCH 17/74] Generated files for new version --- Cargo.toml | 2 +- README.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 31d2b310..c505a426 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.7-interpreter" +version = "0.1.7-develop" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 5c7462b2..a3ff6c8c 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.7-interpreter +# Rock v0.1.7-develop -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=interpreter)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. @@ -40,10 +40,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.7-interpreter](https://github.com/Champii/Rock/releases/download/v0.1.7-interpreter/rock) (Tested on arch, btw) +[Rock v0.1.7-develop](https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.7-interpreter/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.7-develop/rock chmod +x rock ./rock -V ``` @@ -121,7 +121,7 @@ rock --repl ``` ``` sh -Rock: v0.1.7-interpreter +Rock: v0.1.7-develop ---- Type ':?' for help From f117e42d8e64a1fc1fa4cff71abb31ac51feabda Mon Sep 17 00:00:00 2001 From: Florian Greiner Date: Mon, 4 Oct 2021 12:08:14 +0200 Subject: [PATCH 18/74] Restored dead store elim pass, simplify test --- src/lib/codegen/codegen_context.rs | 1 + src/lib/testcases/basic/nested_array/main.rk | 3 +-- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/lib/codegen/codegen_context.rs b/src/lib/codegen/codegen_context.rs index b8a10ad1..3079e710 100644 --- a/src/lib/codegen/codegen_context.rs +++ b/src/lib/codegen/codegen_context.rs @@ -85,6 +85,7 @@ impl<'a> CodegenContext<'a> { pass_manager.add_internalize_pass(true); pass_manager.add_aggressive_dce_pass(); pass_manager.add_sccp_pass(); + pass_manager.add_dead_store_elimination_pass(); pass_manager.add_verifier_pass(); pass_manager.run_on(&self.module); diff --git a/src/lib/testcases/basic/nested_array/main.rk b/src/lib/testcases/basic/nested_array/main.rk index 1b184563..e5ac41a4 100644 --- a/src/lib/testcases/basic/nested_array/main.rk +++ b/src/lib/testcases/basic/nested_array/main.rk @@ -1,2 +1 @@ -lol = [[12, 24], [42, 0]] -main = lol()[1][0] +main = [[12, 24], [42, 0]][1][0] From 2d0dd08b6100b2b9643003c68e3d00d98653a6ae Mon Sep 17 00:00:00 2001 From: Florian Greiner Date: Mon, 4 Oct 2021 23:29:59 +0200 Subject: [PATCH 19/74] Tmp fix return placement for assign --- .github/templates/README.md | 13 ++++-- src/bin/main.rs | 2 +- src/lib/ast/mod.rs | 1 + .../{ast_lowering => ast}/return_placement.rs | 28 ++++++++++++- src/lib/ast/tree.rs | 16 ++++++++ src/lib/ast_lowering/ast_lowering_context.rs | 4 +- src/lib/ast_lowering/mod.rs | 1 - src/lib/codegen/codegen_context.rs | 26 ++++++++---- src/lib/codegen/interpreter.rs | 40 +++++++++++++++---- src/lib/diagnostics/diagnostic.rs | 5 ++- src/lib/infer/constraint.rs | 2 +- src/lib/parser/parser_impl.rs | 1 - src/lib/parser/source_file.rs | 1 + src/lib/testcases/mods/struct_new/lib.rk | 8 ++++ src/lib/testcases/mods/struct_new/main.rk | 7 ++++ src/lib/testcases/mods/struct_new/main.rk.out | 1 + .../testcases/mods/struct_new/main.rk.stdout | 0 src/lib/tests.rs | 4 ++ std/src/fs.rk | 35 ++++++++++++++++ std/src/lib.rk | 1 + std/src/num.rk | 12 ++++++ std/src/prelude.rk | 1 - 22 files changed, 180 insertions(+), 29 deletions(-) rename src/lib/{ast_lowering => ast}/return_placement.rs (56%) create mode 100644 src/lib/testcases/mods/struct_new/lib.rk create mode 100644 src/lib/testcases/mods/struct_new/main.rk create mode 100644 src/lib/testcases/mods/struct_new/main.rk.out create mode 100644 src/lib/testcases/mods/struct_new/main.rk.stdout create mode 100644 std/src/fs.rk diff --git a/.github/templates/README.md b/.github/templates/README.md index 15cfa52f..f0bfbd08 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -2,10 +2,13 @@ [![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch={branch})](https://github.com/Champii/Rock/actions/workflows/rust.yml) -Little toy language made with Rust and LLVM. +Little language made with Rust and LLVM. + Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. It's highly inspired from Livescript, and will borrow (pun intended) some features and syntaxes from Crystal, from functional languages like Haskell, or even from Rust itself. +No to be taken seriously (yet) + # VTable - [Features]( #features ) - [Install]( #install ) @@ -140,6 +143,9 @@ add: (Int64 -> Int64 -> Int64) Only supports basic expressions for now. +Be warned that for a given session, the whole code is re-executed at each entry. +This includes I/O of all sorts (Looking at you, open/read/write in loops) + ## Showcases ### Polymophic function @@ -258,5 +264,6 @@ Prints `MyName` ## Development notes This project, its syntax and its APIs are subject to change at any moment. -This is a personal project, so please bear with me -(Differently put: this is a big red hot pile of experimental garbage right now) +This is a personal project, so please bear with me + +Differently put: this is a big red hot pile of experimental garbage right now diff --git a/src/bin/main.rs b/src/bin/main.rs index b6d5b808..31a6c659 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -66,7 +66,7 @@ fn run(config: Config) { .output() .expect("failed to execute binary"); - print!("{}", String::from_utf8(cmd.stdout).unwrap()); + print!("{}", unsafe { String::from_utf8_unchecked(cmd.stdout) }); match cmd.status.code() { Some(code) => { diff --git a/src/lib/ast/mod.rs b/src/lib/ast/mod.rs index 5a533149..5fc23a83 100644 --- a/src/lib/ast/mod.rs +++ b/src/lib/ast/mod.rs @@ -2,6 +2,7 @@ pub mod ast_print; mod identity; +pub mod return_placement; pub mod span_collector; mod tree; pub mod visit; diff --git a/src/lib/ast_lowering/return_placement.rs b/src/lib/ast/return_placement.rs similarity index 56% rename from src/lib/ast_lowering/return_placement.rs rename to src/lib/ast/return_placement.rs index 20507d26..5c1db390 100644 --- a/src/lib/ast_lowering/return_placement.rs +++ b/src/lib/ast/return_placement.rs @@ -14,12 +14,28 @@ impl<'a> ReturnInserter<'a> { } fn visit_body(&mut self, body: &mut Body) { + // let mut is_assign = None; + if let Some(stmt) = body.stmts.iter_mut().last() { - self.visit_statement(stmt) + // if let StatementKind::Assign(ref mut a) = *stmt.kind.clone() { + // is_assign = Some(a.clone()); + // } + + self.visit_statement(stmt); } + + // if let Some(a) = is_assign { + // body.stmts.push(Statement { + // kind: Box::new(StatementKind::Expression(Box::new(Expression { + // kind: ExpressionKind::Return(Box::new(a.name.as_expression())), + // }))), + // }); + // } } fn visit_statement(&mut self, stmt: &mut Statement) { + let mut is_assign = None; + match *stmt.kind { StatementKind::Expression(ref mut e) => { e.kind = ExpressionKind::Return(e.clone()); @@ -28,9 +44,17 @@ impl<'a> ReturnInserter<'a> { self.visit_if(i); } StatementKind::Assign(ref mut a) => { - a.value.kind = ExpressionKind::Return(Box::new(a.value.clone())); + is_assign = Some(a.value.clone()); } } + + // FIXME: do this only if a.name is Identifier + // or else return the ident + if let Some(value) = is_assign { + stmt.kind = Box::new(StatementKind::Expression(Box::new(Expression { + kind: ExpressionKind::Return(Box::new(value.clone())), + }))); + } } fn visit_if(&mut self, r#if: &mut If) { diff --git a/src/lib/ast/tree.rs b/src/lib/ast/tree.rs index 466c80f4..8ed0dd0b 100644 --- a/src/lib/ast/tree.rs +++ b/src/lib/ast/tree.rs @@ -249,6 +249,22 @@ pub enum AssignLeftSide { Indice(Expression), Dot(Expression), } + +impl AssignLeftSide { + pub fn as_expression(&self) -> Expression { + match self { + AssignLeftSide::Identifier(i) => Expression { + kind: ExpressionKind::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { + op: Operand::from_identifier(i), + identity: i.identity.clone(), + secondaries: None, + })), + }, + AssignLeftSide::Indice(i) => i.clone(), + AssignLeftSide::Dot(d) => d.clone(), + } + } +} // impl AssignLeftSide { // pub fn get_node_id(&self) -> NodeId { // use AssignLeftSide::*; diff --git a/src/lib/ast_lowering/ast_lowering_context.rs b/src/lib/ast_lowering/ast_lowering_context.rs index a29216fb..c73d2780 100644 --- a/src/lib/ast_lowering/ast_lowering_context.rs +++ b/src/lib/ast_lowering/ast_lowering_context.rs @@ -1,13 +1,13 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ - ast::*, + ast::{return_placement::ReturnInserter, *}, hir::{self, Arena, FnBodyId, HirId}, infer::Envs, ty::*, }; -use super::{hir_map::HirMap, return_placement::ReturnInserter, InfixDesugar}; +use super::{hir_map::HirMap, InfixDesugar}; pub struct AstLoweringContext { hir_map: HirMap, diff --git a/src/lib/ast_lowering/mod.rs b/src/lib/ast_lowering/mod.rs index db0ee4ea..a54e80b7 100644 --- a/src/lib/ast_lowering/mod.rs +++ b/src/lib/ast_lowering/mod.rs @@ -3,7 +3,6 @@ use crate::{ast::Root, hir}; mod ast_lowering_context; mod hir_map; mod infix_desugar; -mod return_placement; use ast_lowering_context::AstLoweringContext; pub use hir_map::*; diff --git a/src/lib/codegen/codegen_context.rs b/src/lib/codegen/codegen_context.rs index 3079e710..0a3c2f74 100644 --- a/src/lib/codegen/codegen_context.rs +++ b/src/lib/codegen/codegen_context.rs @@ -51,7 +51,6 @@ impl<'a> CodegenContext<'a> { let pass_manager = PassManager::create(()); - pass_manager.add_demote_memory_to_register_pass(); pass_manager.add_promote_memory_to_register_pass(); pass_manager.add_argument_promotion_pass(); pass_manager.add_always_inliner_pass(); @@ -83,9 +82,11 @@ impl<'a> CodegenContext<'a> { pass_manager.add_strip_symbol_pass(); pass_manager.add_strip_dead_prototypes_pass(); pass_manager.add_internalize_pass(true); - pass_manager.add_aggressive_dce_pass(); pass_manager.add_sccp_pass(); - pass_manager.add_dead_store_elimination_pass(); + // FIXME: Struct init fail with this pass + // pass_manager.add_dead_store_elimination_pass(); + pass_manager.add_aggressive_dce_pass(); + pass_manager.add_global_dce_pass(); pass_manager.add_verifier_pass(); pass_manager.run_on(&self.module); @@ -341,26 +342,35 @@ impl<'a> CodegenContext<'a> { assign: &'a Assign, builder: &'a Builder, ) -> Result, ()> { - let value = self.lower_expression(&assign.value, builder)?; - - match &assign.name { + Ok(match &assign.name { AssignLeftSide::Identifier(id) => { + let value = self.lower_expression(&assign.value, builder)?; + self.scopes .add(id.get_hir_id(), value.as_basic_value_enum()); + + value } AssignLeftSide::Indice(indice) => { let ptr = self.lower_indice_ptr(indice, builder)?.into_pointer_value(); + let value = self.lower_expression(&assign.value, builder)?; + builder.build_store(ptr, value); + + value } AssignLeftSide::Dot(dot) => { let ptr = self.lower_dot_ptr(dot, builder)?.into_pointer_value(); + let value = self.lower_expression(&assign.value, builder)?; + builder.build_store(ptr, value); + + value } } - - Ok(value.as_any_value_enum()) + .as_any_value_enum()) } pub fn lower_if( diff --git a/src/lib/codegen/interpreter.rs b/src/lib/codegen/interpreter.rs index 2a34ca38..6132baf9 100644 --- a/src/lib/codegen/interpreter.rs +++ b/src/lib/codegen/interpreter.rs @@ -82,6 +82,8 @@ fn process_line( } let mut get_type = false; + let mut print_ir = false; + let mut print_hir = false; if line.starts_with(":?") { print_help(); @@ -89,6 +91,14 @@ fn process_line( return; } + if line.starts_with(":i") { + print_ir = true; + } + + if line.starts_with(":h") { + print_hir = true; + } + if line.starts_with(":t ") { get_type = true; @@ -105,7 +115,7 @@ fn process_line( let line_parts = line.split("=").collect::>(); if line_parts.len() > 1 && !line_parts[0].starts_with("let ") - && line_parts[0].split(" ").count() > 1 + && line_parts[0].split(" ").filter(|x| !x.is_empty()).count() > 1 { is_top_level = true; } else { @@ -117,7 +127,7 @@ fn process_line( if is_top_level { top_levels.push(line.clone()); } else { - if !get_type { + if !get_type && !print_ir && !print_hir { commands.push(" ".to_owned() + &line); } } @@ -132,10 +142,10 @@ fn process_line( let hir = match crate::parse_str(&mut parsing_ctx, config) { Ok(hir) => hir, Err(_e) => { - if is_top_level { + if is_top_level || print_ir || print_hir { top_levels.pop(); } else { - if !get_type { + if !get_type && !print_ir && !print_hir { commands.pop(); } } @@ -144,8 +154,14 @@ fn process_line( } }; + if print_hir { + hir.print(); + + return; + } + if get_type { - if is_top_level { + if is_top_level || print_ir { top_levels.pop(); } else { // commands.pop(); @@ -186,10 +202,14 @@ fn process_line( codegen_ctx.optimize(); } - if config.show_ir { + if config.show_ir || print_ir { codegen_ctx.module.print_to_stderr(); } + if print_ir { + return; + } + let engine = codegen_ctx .module .create_jit_execution_engine(OptimizationLevel::None) @@ -202,11 +222,15 @@ fn process_line( pub fn print_help() { println!( - "\n{}\n\n {} : {}\n {} : {}\n", + "\n{}\n\n {} : {}\n {} : {}\n {} : {}\n {} : {}\n", "Help:".bright_green(), + ":h".bright_yellow(), + "Print the HIR".bright_black(), + ":i".bright_yellow(), + "Print the IR".bright_black(), ":t".bright_yellow(), "Print the type of an expression".bright_black(), ":?".bright_yellow(), - "Print This help".bright_black(), + "Print this help".bright_black(), ); } diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index 3bcb97e6..9b9e1417 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -229,7 +229,10 @@ impl Display for DiagnosticKind { Self::ModuleNotFound(path) => format!("Module not found: {}", path), Self::DuplicatedOperator => "DuplicatedOperator".to_string(), Self::TypeConflict(t1, t2, _in1, _in2) => { - format!("Type conflict: Expected {:?} but got {:?} ", t1, t2) + format!( + "Type conflict:\n{:<8}Expected {:?}\n{:<8}But got {:?}", + "", t1, "", t2 + ) } Self::UnresolvedType(t) => { format!( diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index 286e3db8..de3e67e9 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -610,7 +610,7 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { fn visit_identifier(&mut self, id: &Identifier) { // We set the type to resolution if any - if let Some(reso) = self.resolve_rec(&id.hir_id) { + if let Some(reso) = self.resolve(&id.hir_id) { if self.envs.get_type(&reso).is_some() { self.envs.set_type_eq(&id.get_hir_id(), &reso); } diff --git a/src/lib/parser/parser_impl.rs b/src/lib/parser/parser_impl.rs index 945c3ae2..24ed0d54 100644 --- a/src/lib/parser/parser_impl.rs +++ b/src/lib/parser/parser_impl.rs @@ -1,7 +1,6 @@ use std::{collections::HashMap, convert::TryInto}; use crate::{ast::*, diagnostics::Diagnostic, parser::*, resolver::ResolutionMap, ty::*}; - type Error = Diagnostic; macro_rules! expect { diff --git a/src/lib/parser/source_file.rs b/src/lib/parser/source_file.rs index bd2a649a..0d7416bb 100644 --- a/src/lib/parser/source_file.rs +++ b/src/lib/parser/source_file.rs @@ -58,6 +58,7 @@ custom = .to_owned() + &expr; + // println!("{}", top_levels); Ok(SourceFile { file_path: PathBuf::from("./src/main.rk"), mod_path: PathBuf::from("root"), diff --git a/src/lib/testcases/mods/struct_new/lib.rk b/src/lib/testcases/mods/struct_new/lib.rk new file mode 100644 index 00000000..f8adda6e --- /dev/null +++ b/src/lib/testcases/mods/struct_new/lib.rk @@ -0,0 +1,8 @@ +struct Foo + i :: Int64 + s :: String + +new_foo str = + Foo + i: 42 + s: str diff --git a/src/lib/testcases/mods/struct_new/main.rk b/src/lib/testcases/mods/struct_new/main.rk new file mode 100644 index 00000000..7535ca64 --- /dev/null +++ b/src/lib/testcases/mods/struct_new/main.rk @@ -0,0 +1,7 @@ +mod lib + +use lib::* + +main = + let foo = new_foo "bar" + foo.i diff --git a/src/lib/testcases/mods/struct_new/main.rk.out b/src/lib/testcases/mods/struct_new/main.rk.out new file mode 100644 index 00000000..f70d7bba --- /dev/null +++ b/src/lib/testcases/mods/struct_new/main.rk.out @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/lib/testcases/mods/struct_new/main.rk.stdout b/src/lib/testcases/mods/struct_new/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/tests.rs b/src/lib/tests.rs index 31e211a8..93fede8f 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -58,6 +58,10 @@ fn testcases_mods_func_arg_resolution_main() { run("testcases/mods/func_arg_resolution/main.rk", include_str!("testcases/mods/func_arg_resolution/main.rk"), include_str!("testcases/mods/func_arg_resolution/main.rk.out"), include_str!("testcases/mods/func_arg_resolution/main.rk.stdout")); } #[test] +fn testcases_mods_struct_new_main() { + run("testcases/mods/struct_new/main.rk", include_str!("testcases/mods/struct_new/main.rk"), include_str!("testcases/mods/struct_new/main.rk.out"), include_str!("testcases/mods/struct_new/main.rk.stdout")); +} +#[test] fn testcases_mods_basic_mod_main() { run("testcases/mods/basic_mod/main.rk", include_str!("testcases/mods/basic_mod/main.rk"), include_str!("testcases/mods/basic_mod/main.rk.out"), include_str!("testcases/mods/basic_mod/main.rk.stdout")); } diff --git a/std/src/fs.rk b/std/src/fs.rk new file mode 100644 index 00000000..c10a49f6 --- /dev/null +++ b/std/src/fs.rk @@ -0,0 +1,35 @@ +extern open :: String -> Int64 -> Int64 -> Int64 +extern close :: Int64 -> Int64 +extern strtol :: String -> Int64 -> Int64 -> Int64 +extern read :: Int64 -> String -> Int64 -> Int64 +extern malloc :: Int64 -> String + +use super::print::print +use super::show::show +use super::num::* +use super::eq::* + +struct File + fd :: Int64 + path :: String + +impl Show File + show f = + "File { fd: " + show f.fd + ", path: " + f.path + " }" + +oct_to_dec oct = strtol oct, 0, 8 + +new_file p = + let f = open p, 0, oct_to_dec "0777" + File + fd: f + path: p + +read_file f = + let s = malloc 100 + let len = read f.fd, s, 100 + s + + +close_file f = + close f.fd diff --git a/std/src/lib.rk b/std/src/lib.rk index 301f9c36..7aceaede 100644 --- a/std/src/lib.rk +++ b/std/src/lib.rk @@ -2,6 +2,7 @@ mod num mod eq mod show mod print +mod fs # mod helpers mod prelude diff --git a/std/src/num.rk b/std/src/num.rk index 56e3a12c..f531f599 100644 --- a/std/src/num.rk +++ b/std/src/num.rk @@ -20,3 +20,15 @@ impl Num Float64 - c d = ~FSub c d * c d = ~FMul c d / c d = ~FDiv c d + +extern malloc :: Int64 -> String +extern strlen :: String -> Int64 +extern strcat :: String -> String -> String +extern strcpy :: String -> String -> String + +impl Num String + + a b = + let s = malloc (strlen a + strlen b) + strcpy s, a + strcat s, b + s diff --git a/std/src/prelude.rk b/std/src/prelude.rk index e773bd1e..08b8abc5 100644 --- a/std/src/prelude.rk +++ b/std/src/prelude.rk @@ -2,4 +2,3 @@ use super::show::show use super::print::print use super::num::* use super::eq::* -# use super::helpers::* From 6b55310bc7df8f3b2e6369f2b77108fb7c272a20 Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 4 Oct 2021 15:49:31 -0700 Subject: [PATCH 20/74] Tmp fix return placement for assign (#57) * Tmp fix return placement for assign Co-authored-by: Florian Greiner --- .github/templates/README.md | 13 ++++-- Cargo.toml | 2 +- README.md | 23 +++++++---- src/bin/main.rs | 2 +- src/lib/ast/mod.rs | 1 + .../{ast_lowering => ast}/return_placement.rs | 28 ++++++++++++- src/lib/ast/tree.rs | 16 ++++++++ src/lib/ast_lowering/ast_lowering_context.rs | 4 +- src/lib/ast_lowering/mod.rs | 1 - src/lib/codegen/codegen_context.rs | 26 ++++++++---- src/lib/codegen/interpreter.rs | 40 +++++++++++++++---- src/lib/diagnostics/diagnostic.rs | 5 ++- src/lib/infer/constraint.rs | 2 +- src/lib/parser/parser_impl.rs | 1 - src/lib/parser/source_file.rs | 1 + src/lib/testcases/mods/struct_new/lib.rk | 8 ++++ src/lib/testcases/mods/struct_new/main.rk | 7 ++++ src/lib/testcases/mods/struct_new/main.rk.out | 1 + .../testcases/mods/struct_new/main.rk.stdout | 0 src/lib/tests.rs | 4 ++ std/src/fs.rk | 35 ++++++++++++++++ std/src/lib.rk | 1 + std/src/num.rk | 12 ++++++ std/src/prelude.rk | 1 - 24 files changed, 196 insertions(+), 38 deletions(-) rename src/lib/{ast_lowering => ast}/return_placement.rs (56%) create mode 100644 src/lib/testcases/mods/struct_new/lib.rk create mode 100644 src/lib/testcases/mods/struct_new/main.rk create mode 100644 src/lib/testcases/mods/struct_new/main.rk.out create mode 100644 src/lib/testcases/mods/struct_new/main.rk.stdout create mode 100644 std/src/fs.rk diff --git a/.github/templates/README.md b/.github/templates/README.md index 15cfa52f..f0bfbd08 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -2,10 +2,13 @@ [![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch={branch})](https://github.com/Champii/Rock/actions/workflows/rust.yml) -Little toy language made with Rust and LLVM. +Little language made with Rust and LLVM. + Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. It's highly inspired from Livescript, and will borrow (pun intended) some features and syntaxes from Crystal, from functional languages like Haskell, or even from Rust itself. +No to be taken seriously (yet) + # VTable - [Features]( #features ) - [Install]( #install ) @@ -140,6 +143,9 @@ add: (Int64 -> Int64 -> Int64) Only supports basic expressions for now. +Be warned that for a given session, the whole code is re-executed at each entry. +This includes I/O of all sorts (Looking at you, open/read/write in loops) + ## Showcases ### Polymophic function @@ -258,5 +264,6 @@ Prints `MyName` ## Development notes This project, its syntax and its APIs are subject to change at any moment. -This is a personal project, so please bear with me -(Differently put: this is a big red hot pile of experimental garbage right now) +This is a personal project, so please bear with me + +Differently put: this is a big red hot pile of experimental garbage right now diff --git a/Cargo.toml b/Cargo.toml index 66eebfa9..b81f6199 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.8-develop" +version = "0.1.8-fixes" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 4bf8455b..08b66299 100644 --- a/README.md +++ b/README.md @@ -1,11 +1,14 @@ -# Rock v0.1.8-develop +# Rock v0.1.8-fixes -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=fixes)](https://github.com/Champii/Rock/actions/workflows/rust.yml) + +Little language made with Rust and LLVM. -Little toy language made with Rust and LLVM. Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. It's highly inspired from Livescript, and will borrow (pun intended) some features and syntaxes from Crystal, from functional languages like Haskell, or even from Rust itself. +No to be taken seriously (yet) + # VTable - [Features]( #features ) - [Install]( #install ) @@ -40,10 +43,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.8-develop](https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock) (Tested on arch, btw) +[Rock v0.1.8-fixes](https://github.com/Champii/Rock/releases/download/v0.1.8-fixes/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.8-fixes/rock chmod +x rock ./rock -V ``` @@ -121,7 +124,7 @@ rock --repl ``` ``` sh -Rock: v0.1.8-develop +Rock: v0.1.8-fixes ---- Type ':?' for help @@ -140,6 +143,9 @@ add: (Int64 -> Int64 -> Int64) Only supports basic expressions for now. +Be warned that for a given session, the whole code is re-executed at each entry. +This includes I/O of all sorts (Looking at you, open/read/write in loops) + ## Showcases ### Polymophic function @@ -258,5 +264,6 @@ Prints `MyName` ## Development notes This project, its syntax and its APIs are subject to change at any moment. -This is a personal project, so please bear with me -(Differently put: this is a big red hot pile of experimental garbage right now) +This is a personal project, so please bear with me + +Differently put: this is a big red hot pile of experimental garbage right now diff --git a/src/bin/main.rs b/src/bin/main.rs index b6d5b808..31a6c659 100644 --- a/src/bin/main.rs +++ b/src/bin/main.rs @@ -66,7 +66,7 @@ fn run(config: Config) { .output() .expect("failed to execute binary"); - print!("{}", String::from_utf8(cmd.stdout).unwrap()); + print!("{}", unsafe { String::from_utf8_unchecked(cmd.stdout) }); match cmd.status.code() { Some(code) => { diff --git a/src/lib/ast/mod.rs b/src/lib/ast/mod.rs index 5a533149..5fc23a83 100644 --- a/src/lib/ast/mod.rs +++ b/src/lib/ast/mod.rs @@ -2,6 +2,7 @@ pub mod ast_print; mod identity; +pub mod return_placement; pub mod span_collector; mod tree; pub mod visit; diff --git a/src/lib/ast_lowering/return_placement.rs b/src/lib/ast/return_placement.rs similarity index 56% rename from src/lib/ast_lowering/return_placement.rs rename to src/lib/ast/return_placement.rs index 20507d26..5c1db390 100644 --- a/src/lib/ast_lowering/return_placement.rs +++ b/src/lib/ast/return_placement.rs @@ -14,12 +14,28 @@ impl<'a> ReturnInserter<'a> { } fn visit_body(&mut self, body: &mut Body) { + // let mut is_assign = None; + if let Some(stmt) = body.stmts.iter_mut().last() { - self.visit_statement(stmt) + // if let StatementKind::Assign(ref mut a) = *stmt.kind.clone() { + // is_assign = Some(a.clone()); + // } + + self.visit_statement(stmt); } + + // if let Some(a) = is_assign { + // body.stmts.push(Statement { + // kind: Box::new(StatementKind::Expression(Box::new(Expression { + // kind: ExpressionKind::Return(Box::new(a.name.as_expression())), + // }))), + // }); + // } } fn visit_statement(&mut self, stmt: &mut Statement) { + let mut is_assign = None; + match *stmt.kind { StatementKind::Expression(ref mut e) => { e.kind = ExpressionKind::Return(e.clone()); @@ -28,9 +44,17 @@ impl<'a> ReturnInserter<'a> { self.visit_if(i); } StatementKind::Assign(ref mut a) => { - a.value.kind = ExpressionKind::Return(Box::new(a.value.clone())); + is_assign = Some(a.value.clone()); } } + + // FIXME: do this only if a.name is Identifier + // or else return the ident + if let Some(value) = is_assign { + stmt.kind = Box::new(StatementKind::Expression(Box::new(Expression { + kind: ExpressionKind::Return(Box::new(value.clone())), + }))); + } } fn visit_if(&mut self, r#if: &mut If) { diff --git a/src/lib/ast/tree.rs b/src/lib/ast/tree.rs index 466c80f4..8ed0dd0b 100644 --- a/src/lib/ast/tree.rs +++ b/src/lib/ast/tree.rs @@ -249,6 +249,22 @@ pub enum AssignLeftSide { Indice(Expression), Dot(Expression), } + +impl AssignLeftSide { + pub fn as_expression(&self) -> Expression { + match self { + AssignLeftSide::Identifier(i) => Expression { + kind: ExpressionKind::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { + op: Operand::from_identifier(i), + identity: i.identity.clone(), + secondaries: None, + })), + }, + AssignLeftSide::Indice(i) => i.clone(), + AssignLeftSide::Dot(d) => d.clone(), + } + } +} // impl AssignLeftSide { // pub fn get_node_id(&self) -> NodeId { // use AssignLeftSide::*; diff --git a/src/lib/ast_lowering/ast_lowering_context.rs b/src/lib/ast_lowering/ast_lowering_context.rs index a29216fb..c73d2780 100644 --- a/src/lib/ast_lowering/ast_lowering_context.rs +++ b/src/lib/ast_lowering/ast_lowering_context.rs @@ -1,13 +1,13 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ - ast::*, + ast::{return_placement::ReturnInserter, *}, hir::{self, Arena, FnBodyId, HirId}, infer::Envs, ty::*, }; -use super::{hir_map::HirMap, return_placement::ReturnInserter, InfixDesugar}; +use super::{hir_map::HirMap, InfixDesugar}; pub struct AstLoweringContext { hir_map: HirMap, diff --git a/src/lib/ast_lowering/mod.rs b/src/lib/ast_lowering/mod.rs index db0ee4ea..a54e80b7 100644 --- a/src/lib/ast_lowering/mod.rs +++ b/src/lib/ast_lowering/mod.rs @@ -3,7 +3,6 @@ use crate::{ast::Root, hir}; mod ast_lowering_context; mod hir_map; mod infix_desugar; -mod return_placement; use ast_lowering_context::AstLoweringContext; pub use hir_map::*; diff --git a/src/lib/codegen/codegen_context.rs b/src/lib/codegen/codegen_context.rs index 3079e710..0a3c2f74 100644 --- a/src/lib/codegen/codegen_context.rs +++ b/src/lib/codegen/codegen_context.rs @@ -51,7 +51,6 @@ impl<'a> CodegenContext<'a> { let pass_manager = PassManager::create(()); - pass_manager.add_demote_memory_to_register_pass(); pass_manager.add_promote_memory_to_register_pass(); pass_manager.add_argument_promotion_pass(); pass_manager.add_always_inliner_pass(); @@ -83,9 +82,11 @@ impl<'a> CodegenContext<'a> { pass_manager.add_strip_symbol_pass(); pass_manager.add_strip_dead_prototypes_pass(); pass_manager.add_internalize_pass(true); - pass_manager.add_aggressive_dce_pass(); pass_manager.add_sccp_pass(); - pass_manager.add_dead_store_elimination_pass(); + // FIXME: Struct init fail with this pass + // pass_manager.add_dead_store_elimination_pass(); + pass_manager.add_aggressive_dce_pass(); + pass_manager.add_global_dce_pass(); pass_manager.add_verifier_pass(); pass_manager.run_on(&self.module); @@ -341,26 +342,35 @@ impl<'a> CodegenContext<'a> { assign: &'a Assign, builder: &'a Builder, ) -> Result, ()> { - let value = self.lower_expression(&assign.value, builder)?; - - match &assign.name { + Ok(match &assign.name { AssignLeftSide::Identifier(id) => { + let value = self.lower_expression(&assign.value, builder)?; + self.scopes .add(id.get_hir_id(), value.as_basic_value_enum()); + + value } AssignLeftSide::Indice(indice) => { let ptr = self.lower_indice_ptr(indice, builder)?.into_pointer_value(); + let value = self.lower_expression(&assign.value, builder)?; + builder.build_store(ptr, value); + + value } AssignLeftSide::Dot(dot) => { let ptr = self.lower_dot_ptr(dot, builder)?.into_pointer_value(); + let value = self.lower_expression(&assign.value, builder)?; + builder.build_store(ptr, value); + + value } } - - Ok(value.as_any_value_enum()) + .as_any_value_enum()) } pub fn lower_if( diff --git a/src/lib/codegen/interpreter.rs b/src/lib/codegen/interpreter.rs index 2a34ca38..6132baf9 100644 --- a/src/lib/codegen/interpreter.rs +++ b/src/lib/codegen/interpreter.rs @@ -82,6 +82,8 @@ fn process_line( } let mut get_type = false; + let mut print_ir = false; + let mut print_hir = false; if line.starts_with(":?") { print_help(); @@ -89,6 +91,14 @@ fn process_line( return; } + if line.starts_with(":i") { + print_ir = true; + } + + if line.starts_with(":h") { + print_hir = true; + } + if line.starts_with(":t ") { get_type = true; @@ -105,7 +115,7 @@ fn process_line( let line_parts = line.split("=").collect::>(); if line_parts.len() > 1 && !line_parts[0].starts_with("let ") - && line_parts[0].split(" ").count() > 1 + && line_parts[0].split(" ").filter(|x| !x.is_empty()).count() > 1 { is_top_level = true; } else { @@ -117,7 +127,7 @@ fn process_line( if is_top_level { top_levels.push(line.clone()); } else { - if !get_type { + if !get_type && !print_ir && !print_hir { commands.push(" ".to_owned() + &line); } } @@ -132,10 +142,10 @@ fn process_line( let hir = match crate::parse_str(&mut parsing_ctx, config) { Ok(hir) => hir, Err(_e) => { - if is_top_level { + if is_top_level || print_ir || print_hir { top_levels.pop(); } else { - if !get_type { + if !get_type && !print_ir && !print_hir { commands.pop(); } } @@ -144,8 +154,14 @@ fn process_line( } }; + if print_hir { + hir.print(); + + return; + } + if get_type { - if is_top_level { + if is_top_level || print_ir { top_levels.pop(); } else { // commands.pop(); @@ -186,10 +202,14 @@ fn process_line( codegen_ctx.optimize(); } - if config.show_ir { + if config.show_ir || print_ir { codegen_ctx.module.print_to_stderr(); } + if print_ir { + return; + } + let engine = codegen_ctx .module .create_jit_execution_engine(OptimizationLevel::None) @@ -202,11 +222,15 @@ fn process_line( pub fn print_help() { println!( - "\n{}\n\n {} : {}\n {} : {}\n", + "\n{}\n\n {} : {}\n {} : {}\n {} : {}\n {} : {}\n", "Help:".bright_green(), + ":h".bright_yellow(), + "Print the HIR".bright_black(), + ":i".bright_yellow(), + "Print the IR".bright_black(), ":t".bright_yellow(), "Print the type of an expression".bright_black(), ":?".bright_yellow(), - "Print This help".bright_black(), + "Print this help".bright_black(), ); } diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index 3bcb97e6..9b9e1417 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -229,7 +229,10 @@ impl Display for DiagnosticKind { Self::ModuleNotFound(path) => format!("Module not found: {}", path), Self::DuplicatedOperator => "DuplicatedOperator".to_string(), Self::TypeConflict(t1, t2, _in1, _in2) => { - format!("Type conflict: Expected {:?} but got {:?} ", t1, t2) + format!( + "Type conflict:\n{:<8}Expected {:?}\n{:<8}But got {:?}", + "", t1, "", t2 + ) } Self::UnresolvedType(t) => { format!( diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index 286e3db8..de3e67e9 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -610,7 +610,7 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { fn visit_identifier(&mut self, id: &Identifier) { // We set the type to resolution if any - if let Some(reso) = self.resolve_rec(&id.hir_id) { + if let Some(reso) = self.resolve(&id.hir_id) { if self.envs.get_type(&reso).is_some() { self.envs.set_type_eq(&id.get_hir_id(), &reso); } diff --git a/src/lib/parser/parser_impl.rs b/src/lib/parser/parser_impl.rs index 945c3ae2..24ed0d54 100644 --- a/src/lib/parser/parser_impl.rs +++ b/src/lib/parser/parser_impl.rs @@ -1,7 +1,6 @@ use std::{collections::HashMap, convert::TryInto}; use crate::{ast::*, diagnostics::Diagnostic, parser::*, resolver::ResolutionMap, ty::*}; - type Error = Diagnostic; macro_rules! expect { diff --git a/src/lib/parser/source_file.rs b/src/lib/parser/source_file.rs index bd2a649a..0d7416bb 100644 --- a/src/lib/parser/source_file.rs +++ b/src/lib/parser/source_file.rs @@ -58,6 +58,7 @@ custom = .to_owned() + &expr; + // println!("{}", top_levels); Ok(SourceFile { file_path: PathBuf::from("./src/main.rk"), mod_path: PathBuf::from("root"), diff --git a/src/lib/testcases/mods/struct_new/lib.rk b/src/lib/testcases/mods/struct_new/lib.rk new file mode 100644 index 00000000..f8adda6e --- /dev/null +++ b/src/lib/testcases/mods/struct_new/lib.rk @@ -0,0 +1,8 @@ +struct Foo + i :: Int64 + s :: String + +new_foo str = + Foo + i: 42 + s: str diff --git a/src/lib/testcases/mods/struct_new/main.rk b/src/lib/testcases/mods/struct_new/main.rk new file mode 100644 index 00000000..7535ca64 --- /dev/null +++ b/src/lib/testcases/mods/struct_new/main.rk @@ -0,0 +1,7 @@ +mod lib + +use lib::* + +main = + let foo = new_foo "bar" + foo.i diff --git a/src/lib/testcases/mods/struct_new/main.rk.out b/src/lib/testcases/mods/struct_new/main.rk.out new file mode 100644 index 00000000..f70d7bba --- /dev/null +++ b/src/lib/testcases/mods/struct_new/main.rk.out @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/lib/testcases/mods/struct_new/main.rk.stdout b/src/lib/testcases/mods/struct_new/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/tests.rs b/src/lib/tests.rs index 31e211a8..93fede8f 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -58,6 +58,10 @@ fn testcases_mods_func_arg_resolution_main() { run("testcases/mods/func_arg_resolution/main.rk", include_str!("testcases/mods/func_arg_resolution/main.rk"), include_str!("testcases/mods/func_arg_resolution/main.rk.out"), include_str!("testcases/mods/func_arg_resolution/main.rk.stdout")); } #[test] +fn testcases_mods_struct_new_main() { + run("testcases/mods/struct_new/main.rk", include_str!("testcases/mods/struct_new/main.rk"), include_str!("testcases/mods/struct_new/main.rk.out"), include_str!("testcases/mods/struct_new/main.rk.stdout")); +} +#[test] fn testcases_mods_basic_mod_main() { run("testcases/mods/basic_mod/main.rk", include_str!("testcases/mods/basic_mod/main.rk"), include_str!("testcases/mods/basic_mod/main.rk.out"), include_str!("testcases/mods/basic_mod/main.rk.stdout")); } diff --git a/std/src/fs.rk b/std/src/fs.rk new file mode 100644 index 00000000..c10a49f6 --- /dev/null +++ b/std/src/fs.rk @@ -0,0 +1,35 @@ +extern open :: String -> Int64 -> Int64 -> Int64 +extern close :: Int64 -> Int64 +extern strtol :: String -> Int64 -> Int64 -> Int64 +extern read :: Int64 -> String -> Int64 -> Int64 +extern malloc :: Int64 -> String + +use super::print::print +use super::show::show +use super::num::* +use super::eq::* + +struct File + fd :: Int64 + path :: String + +impl Show File + show f = + "File { fd: " + show f.fd + ", path: " + f.path + " }" + +oct_to_dec oct = strtol oct, 0, 8 + +new_file p = + let f = open p, 0, oct_to_dec "0777" + File + fd: f + path: p + +read_file f = + let s = malloc 100 + let len = read f.fd, s, 100 + s + + +close_file f = + close f.fd diff --git a/std/src/lib.rk b/std/src/lib.rk index 301f9c36..7aceaede 100644 --- a/std/src/lib.rk +++ b/std/src/lib.rk @@ -2,6 +2,7 @@ mod num mod eq mod show mod print +mod fs # mod helpers mod prelude diff --git a/std/src/num.rk b/std/src/num.rk index 56e3a12c..f531f599 100644 --- a/std/src/num.rk +++ b/std/src/num.rk @@ -20,3 +20,15 @@ impl Num Float64 - c d = ~FSub c d * c d = ~FMul c d / c d = ~FDiv c d + +extern malloc :: Int64 -> String +extern strlen :: String -> Int64 +extern strcat :: String -> String -> String +extern strcpy :: String -> String -> String + +impl Num String + + a b = + let s = malloc (strlen a + strlen b) + strcpy s, a + strcat s, b + s diff --git a/std/src/prelude.rk b/std/src/prelude.rk index e773bd1e..08b8abc5 100644 --- a/std/src/prelude.rk +++ b/std/src/prelude.rk @@ -2,4 +2,3 @@ use super::show::show use super::print::print use super::num::* use super::eq::* -# use super::helpers::* From 941899a6e59a448cc6cb3b082aea3fa990e886c8 Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 4 Oct 2021 22:49:45 +0000 Subject: [PATCH 21/74] Generated files for new version --- Cargo.toml | 2 +- README.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b81f6199..66eebfa9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.8-fixes" +version = "0.1.8-develop" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 08b66299..41d14497 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.8-fixes +# Rock v0.1.8-develop -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=fixes)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little language made with Rust and LLVM. @@ -43,10 +43,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.8-fixes](https://github.com/Champii/Rock/releases/download/v0.1.8-fixes/rock) (Tested on arch, btw) +[Rock v0.1.8-develop](https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.8-fixes/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock chmod +x rock ./rock -V ``` @@ -124,7 +124,7 @@ rock --repl ``` ``` sh -Rock: v0.1.8-fixes +Rock: v0.1.8-develop ---- Type ':?' for help From 7c0f4e2a95c57fcd99d43811b577fc76bc153ccb Mon Sep 17 00:00:00 2001 From: Champii Date: Thu, 7 Oct 2021 06:07:41 -0700 Subject: [PATCH 22/74] Basic Loops support (#61) * Tmp fix return placement for assign * Basic While, not working cause of constants not beeing on the stack * All assign are now on the stack with automatic store/load for primitives * Fix for_while body * Basic loops * Add ~Len operator for arrays and fonctors in lib * Add stdlib externs * Add not working vec to std * Generated files for new version * Fix warnings * Fix Clippy warnings Co-authored-by: Florian Greiner --- Cargo.lock | 2 +- Cargo.toml | 2 +- README.md | 10 +- src/lib/ast/ast_print.rs | 3 + src/lib/ast/return_placement.rs | 5 +- src/lib/ast/tree.rs | 21 +++ src/lib/ast/visit.rs | 22 +++ src/lib/ast_lowering/ast_lowering_context.rs | 24 +++ src/lib/ast_lowering/loop_desugar.rs | 63 +++++++ src/lib/codegen/codegen_context.rs | 175 ++++++++++++++++-- src/lib/codegen/interpreter.rs | 14 +- src/lib/codegen/mod.rs | 1 + src/lib/helpers/scopes.rs | 29 +++ src/lib/hir/has_hir_id.rs | 3 + src/lib/hir/tree.rs | 43 +++++ src/lib/hir/visit.rs | 22 +++ src/lib/hir/visit_mut.rs | 22 +++ src/lib/infer/constraint.rs | 36 +++- src/lib/infer/state.rs | 2 +- src/lib/parser/lexer.rs | 6 + src/lib/parser/parser_impl.rs | 59 +++++- src/lib/parser/parsing_context.rs | 2 +- src/lib/parser/source_file.rs | 2 +- src/lib/parser/token.rs | 3 +- src/lib/resolver/resolve_ctx.rs | 13 ++ .../testcases/basic/reassign_return/main.rk | 7 + .../basic/reassign_return/main.rk.out | 1 + .../basic/reassign_return/main.rk.stdout | 0 src/lib/testcases/basic/while/main.rk | 12 ++ src/lib/testcases/basic/while/main.rk.out | 1 + src/lib/testcases/basic/while/main.rk.stdout | 0 src/lib/tests.rs | 8 + src/lib/ty/func_type.rs | 4 +- src/lib/ty/primitive_type.rs | 8 + std/src/clone.rk | 21 +++ std/src/externs.rk | 37 ++++ std/src/fs.rk | 22 +-- std/src/functor.rk | 22 +++ std/src/lib.rk | 6 + std/src/num.rk | 10 + std/src/prelude.rk | 2 + std/src/print.rk | 9 +- std/src/show.rk | 54 +++++- std/src/vec.rk | 48 +++++ 44 files changed, 786 insertions(+), 70 deletions(-) create mode 100644 src/lib/ast_lowering/loop_desugar.rs create mode 100644 src/lib/testcases/basic/reassign_return/main.rk create mode 100644 src/lib/testcases/basic/reassign_return/main.rk.out create mode 100644 src/lib/testcases/basic/reassign_return/main.rk.stdout create mode 100644 src/lib/testcases/basic/while/main.rk create mode 100644 src/lib/testcases/basic/while/main.rk.out create mode 100644 src/lib/testcases/basic/while/main.rk.stdout create mode 100644 std/src/clone.rk create mode 100644 std/src/externs.rk create mode 100644 std/src/functor.rk create mode 100644 std/src/vec.rk diff --git a/Cargo.lock b/Cargo.lock index 1b1b6028..24859bd0 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -430,7 +430,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rock" -version = "0.1.8-develop" +version = "0.1.8-loops" dependencies = [ "bincode", "bitflags", diff --git a/Cargo.toml b/Cargo.toml index 66eebfa9..b2486c27 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.8-develop" +version = "0.1.8-loops" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 41d14497..55703ef8 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.8-develop +# Rock v0.1.8-loops -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=loops)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little language made with Rust and LLVM. @@ -43,10 +43,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.8-develop](https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock) (Tested on arch, btw) +[Rock v0.1.8-loops](https://github.com/Champii/Rock/releases/download/v0.1.8-loops/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.8-loops/rock chmod +x rock ./rock -V ``` @@ -124,7 +124,7 @@ rock --repl ``` ``` sh -Rock: v0.1.8-develop +Rock: v0.1.8-loops ---- Type ':?' for help diff --git a/src/lib/ast/ast_print.rs b/src/lib/ast/ast_print.rs index adc8fae3..f9b7d1b1 100644 --- a/src/lib/ast/ast_print.rs +++ b/src/lib/ast/ast_print.rs @@ -95,6 +95,9 @@ impl_visitor_trait!( ArgumentDecl Body Statement + For + While + ForIn Expression If Else diff --git a/src/lib/ast/return_placement.rs b/src/lib/ast/return_placement.rs index 5c1db390..0e58d49b 100644 --- a/src/lib/ast/return_placement.rs +++ b/src/lib/ast/return_placement.rs @@ -46,13 +46,16 @@ impl<'a> ReturnInserter<'a> { StatementKind::Assign(ref mut a) => { is_assign = Some(a.value.clone()); } + StatementKind::For(ref mut _fa) => { + unimplemented!("Cannot have loop in return position"); + } } // FIXME: do this only if a.name is Identifier // or else return the ident if let Some(value) = is_assign { stmt.kind = Box::new(StatementKind::Expression(Box::new(Expression { - kind: ExpressionKind::Return(Box::new(value.clone())), + kind: ExpressionKind::Return(Box::new(value)), }))); } } diff --git a/src/lib/ast/tree.rs b/src/lib/ast/tree.rs index 8ed0dd0b..34fba438 100644 --- a/src/lib/ast/tree.rs +++ b/src/lib/ast/tree.rs @@ -241,6 +241,26 @@ pub enum StatementKind { Expression(Box), Assign(Box), If(Box), + For(For), +} + +#[derive(Debug, Clone)] +pub enum For { + In(ForIn), + While(While), +} + +#[derive(Debug, Clone)] +pub struct While { + pub predicat: Expression, + pub body: Body, +} + +#[derive(Debug, Clone)] +pub struct ForIn { + pub value: Identifier, + pub expr: Expression, + pub body: Body, } #[derive(Debug, Clone)] @@ -537,4 +557,5 @@ pub enum NativeOperatorKind { Flt, Fle, BEq, + Len, } diff --git a/src/lib/ast/visit.rs b/src/lib/ast/visit.rs index 502a91e2..26c86a88 100644 --- a/src/lib/ast/visit.rs +++ b/src/lib/ast/visit.rs @@ -43,6 +43,9 @@ generate_visitor_trait!( ArgumentDecl Body Statement + For + ForIn + While Expression If Else @@ -148,9 +151,28 @@ pub fn walk_statement<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Statem StatementKind::Expression(expr) => visitor.visit_expression(expr), StatementKind::Assign(assign) => visitor.visit_assign(assign), StatementKind::If(expr) => visitor.visit_if(expr), + StatementKind::For(for_loop) => visitor.visit_for(for_loop), } } +pub fn walk_for<'a, V: Visitor<'a>>(visitor: &mut V, for_loop: &'a For) { + match for_loop { + For::In(for_in) => visitor.visit_for_in(for_in), + For::While(while_loop) => visitor.visit_while(while_loop), + } +} + +pub fn walk_for_in<'a, V: Visitor<'a>>(visitor: &mut V, for_in: &'a ForIn) { + visitor.visit_identifier(&for_in.value); + visitor.visit_expression(&for_in.expr); + visitor.visit_body(&for_in.body); +} + +pub fn walk_while<'a, V: Visitor<'a>>(visitor: &mut V, while_loop: &'a While) { + visitor.visit_expression(&while_loop.predicat); + visitor.visit_body(&while_loop.body); +} + pub fn walk_assign_left_side<'a, V: Visitor<'a>>(visitor: &mut V, assign_left: &'a AssignLeftSide) { match assign_left { AssignLeftSide::Identifier(id) => visitor.visit_identifier(id), diff --git a/src/lib/ast_lowering/ast_lowering_context.rs b/src/lib/ast_lowering/ast_lowering_context.rs index c73d2780..7f9907ce 100644 --- a/src/lib/ast_lowering/ast_lowering_context.rs +++ b/src/lib/ast_lowering/ast_lowering_context.rs @@ -244,10 +244,33 @@ impl AstLoweringContext { StatementKind::Assign(a) => { Box::new(hir::StatementKind::Assign(self.lower_assign(a))) } + StatementKind::For(f) => Box::new(hir::StatementKind::For(self.lower_for(f))), }, } } + pub fn lower_for(&mut self, for_loop: &For) -> hir::For { + match for_loop { + For::In(i) => hir::For::In(self.lower_for_in(i)), + For::While(w) => hir::For::While(self.lower_while(w)), + } + } + + pub fn lower_for_in(&mut self, for_in: &ForIn) -> hir::ForIn { + hir::ForIn { + value: self.lower_identifier(&for_in.value), + expr: self.lower_expression(&for_in.expr), + body: self.lower_body(&for_in.body), + } + } + + pub fn lower_while(&mut self, while_loop: &While) -> hir::While { + hir::While { + predicat: self.lower_expression(&while_loop.predicat), + body: self.lower_body(&while_loop.body), + } + } + pub fn lower_assign_left_side(&mut self, assign_left: &AssignLeftSide) -> hir::AssignLeftSide { match assign_left { AssignLeftSide::Identifier(id) => { @@ -466,6 +489,7 @@ impl AstLoweringContext { NativeOperatorKind::Flt => hir::NativeOperatorKind::Flt, NativeOperatorKind::Fle => hir::NativeOperatorKind::Fle, NativeOperatorKind::BEq => hir::NativeOperatorKind::BEq, + NativeOperatorKind::Len => hir::NativeOperatorKind::Len, }; hir::NativeOperator { hir_id, kind } diff --git a/src/lib/ast_lowering/loop_desugar.rs b/src/lib/ast_lowering/loop_desugar.rs new file mode 100644 index 00000000..f0c7ba8f --- /dev/null +++ b/src/lib/ast_lowering/loop_desugar.rs @@ -0,0 +1,63 @@ +use std::collections::HashMap; + +use crate::ast::{Expression, ExpressionKind, Identifier, Operand, Statement, UnaryExpr}; + +pub struct Loop { + pre_loop: Vec, + predicat: Expression, + pre_body: Vec, + body: Body, + post_body: Vec, +} + +#[derive(Debug)] +pub struct LoopDesugar {} + +impl LoopDesugar { + pub fn new() -> Self { + LoopDesugar {} + } + + pub fn desugar(&mut self, for_loop: &For) -> Loop { + match for_loop { + For::In(for_in) => self.desugar_for_in(&for_in), + For::While(while_loop) => self.desugar_while(&while_loop), + } + } + + // for item in arr + // do item + // + // --- becomes + // + // let i = 0 + // let arr_len = ~Len arr + // for i < arr_len + // let item = arr[i] // pre_body + // do item + // i = i + 1 // post_body + + + + fn desugar_for_in(&mut self, for_in: &ForIn) -> Loop { + let i_var = Statement::new_assign() + + Loop { + pre_loop: vec![], + predicat: (), + pre_body: vec![], + body: for_in.body.clone(), + post_body: vec![], + } + } + + fn desugar_while(&mut self, while_loop: &While) -> Loop { + Loop { + pre_loop: vec![], + predicat: while_loop.predicat.clone(), + pre_body: vec![], + body: while_loop.body.clone(), + post_body: vec![], + } + } +} diff --git a/src/lib/codegen/codegen_context.rs b/src/lib/codegen/codegen_context.rs index 0a3c2f74..62b7ed0a 100644 --- a/src/lib/codegen/codegen_context.rs +++ b/src/lib/codegen/codegen_context.rs @@ -52,28 +52,22 @@ impl<'a> CodegenContext<'a> { let pass_manager = PassManager::create(()); pass_manager.add_promote_memory_to_register_pass(); + // pass_manager.add_demote_memory_to_register_pass(); pass_manager.add_argument_promotion_pass(); pass_manager.add_always_inliner_pass(); pass_manager.add_gvn_pass(); pass_manager.add_new_gvn_pass(); pass_manager.add_function_attrs_pass(); pass_manager.add_prune_eh_pass(); - pass_manager.add_loop_vectorize_pass(); - pass_manager.add_cfg_simplification_pass(); pass_manager.add_constant_merge_pass(); pass_manager.add_scalarizer_pass(); pass_manager.add_merged_load_store_motion_pass(); - pass_manager.add_ind_var_simplify_pass(); pass_manager.add_instruction_combining_pass(); - pass_manager.add_licm_pass(); - pass_manager.add_loop_deletion_pass(); - pass_manager.add_loop_unswitch_pass(); pass_manager.add_memcpy_optimize_pass(); pass_manager.add_partially_inline_lib_calls_pass(); pass_manager.add_lower_switch_pass(); pass_manager.add_reassociate_pass(); pass_manager.add_simplify_lib_calls_pass(); - pass_manager.add_tail_call_elimination_pass(); pass_manager.add_aggressive_inst_combiner_pass(); pass_manager.add_instruction_simplify_pass(); pass_manager.add_function_inlining_pass(); @@ -83,10 +77,21 @@ impl<'a> CodegenContext<'a> { pass_manager.add_strip_dead_prototypes_pass(); pass_manager.add_internalize_pass(true); pass_manager.add_sccp_pass(); - // FIXME: Struct init fail with this pass - // pass_manager.add_dead_store_elimination_pass(); pass_manager.add_aggressive_dce_pass(); pass_manager.add_global_dce_pass(); + pass_manager.add_tail_call_elimination_pass(); + pass_manager.add_basic_alias_analysis_pass(); + pass_manager.add_licm_pass(); + pass_manager.add_ind_var_simplify_pass(); + pass_manager.add_loop_vectorize_pass(); + pass_manager.add_loop_unswitch_pass(); + pass_manager.add_loop_idiom_pass(); + pass_manager.add_loop_rotate_pass(); + pass_manager.add_loop_unroll_and_jam_pass(); + pass_manager.add_loop_unroll_pass(); + pass_manager.add_loop_deletion_pass(); + pass_manager.add_cfg_simplification_pass(); + pass_manager.add_verifier_pass(); pass_manager.run_on(&self.module); @@ -309,6 +314,8 @@ impl<'a> CodegenContext<'a> { name: &str, builder: &'a Builder, ) -> Result<(AnyValueEnum<'a>, BasicBlock<'a>), ()> { + // self.scopes.push(); + let basic_block = self .context .append_basic_block(self.cur_func.unwrap(), name); @@ -322,6 +329,8 @@ impl<'a> CodegenContext<'a> { .last() .unwrap()?; + // self.scopes.pop(); + Ok((stmt, basic_block)) } @@ -334,9 +343,71 @@ impl<'a> CodegenContext<'a> { StatementKind::Expression(e) => self.lower_expression(e, builder)?.as_any_value_enum(), StatementKind::If(e) => self.lower_if(e, builder)?.0, StatementKind::Assign(a) => self.lower_assign(a, builder)?, + StatementKind::For(f) => self.lower_for(f, builder)?, }) } + pub fn lower_for( + &mut self, + for_loop: &'a For, + builder: &'a Builder, + ) -> Result, ()> { + match &for_loop { + For::In(i) => self.lower_for_in(i, builder), + For::While(w) => self.lower_while(w, builder), + } + } + + pub fn lower_for_in( + &mut self, + for_in: &'a ForIn, + builder: &'a Builder, + ) -> Result, ()> { + let block = builder.get_insert_block().unwrap(); + let cur_f = block.get_parent().unwrap(); + + let (value, while_body) = self.lower_body(&for_in.body, "for_in_body", builder)?; + + let predicat = self.lower_expression(&for_in.expr, builder)?; + + let exit_block = self.context.append_basic_block(cur_f, "for_in_exit"); + + builder.position_at_end(while_body); + builder.build_conditional_branch(predicat.into_int_value(), while_body, exit_block); + + builder.position_at_end(block); + builder.build_unconditional_branch(while_body); + + builder.position_at_end(exit_block); + + Ok(value) + } + + pub fn lower_while( + &mut self, + while_loop: &'a While, + builder: &'a Builder, + ) -> Result, ()> { + let block = builder.get_insert_block().unwrap(); + let cur_f = block.get_parent().unwrap(); + + let (value, while_body) = self.lower_body(&while_loop.body, "while_body", builder)?; + + let predicat = self.lower_expression(&while_loop.predicat, builder)?; + + let exit_block = self.context.append_basic_block(cur_f, "while_exit"); + + builder.position_at_end(while_body); + builder.build_conditional_branch(predicat.into_int_value(), while_body, exit_block); + + builder.position_at_end(block); + builder.build_unconditional_branch(while_body); + + builder.position_at_end(exit_block); + + Ok(value) + } + pub fn lower_assign( &mut self, assign: &'a Assign, @@ -346,10 +417,38 @@ impl<'a> CodegenContext<'a> { AssignLeftSide::Identifier(id) => { let value = self.lower_expression(&assign.value, builder)?; - self.scopes - .add(id.get_hir_id(), value.as_basic_value_enum()); + // FIXME: This is twisted + let val = self + .hir + .resolutions + .get(&id.get_hir_id()) + .and_then(|reso| self.scopes.get(reso)) + .map(|ptr| ptr.into_pointer_value()) + .or_else(|| { + self.hir.node_types.get(&assign.get_hir_id()).and_then(|t| { + (t.is_primitive() && !t.is_array() && !t.is_string()).then(|| { + let ptr = + builder.build_alloca(value.get_type(), &id.name.to_string()); + + self.scopes.add(id.get_hir_id(), ptr.as_basic_value_enum()); + + ptr + }) + }) + }) + .map(|ptr| { + builder.build_store(ptr, value); + ptr.as_basic_value_enum() + }) + .or({ + // self.scopes.add(id.get_hir_id(), value.clone()); + Some(value) + }) + .unwrap(); + + self.scopes.add(id.get_hir_id(), val); - value + val.as_any_value_enum() } AssignLeftSide::Indice(indice) => { let ptr = self.lower_indice_ptr(indice, builder)?.into_pointer_value(); @@ -358,7 +457,7 @@ impl<'a> CodegenContext<'a> { builder.build_store(ptr, value); - value + ptr.as_any_value_enum() } AssignLeftSide::Dot(dot) => { let ptr = self.lower_dot_ptr(dot, builder)?.into_pointer_value(); @@ -367,10 +466,9 @@ impl<'a> CodegenContext<'a> { builder.build_store(ptr, value); - value + ptr.as_any_value_enum() } - } - .as_any_value_enum()) + }) } pub fn lower_if( @@ -398,6 +496,8 @@ impl<'a> CodegenContext<'a> { }; // FIXME: Need a last block if the 'if' is not the last statement in the fn body + // Investigate PHI values + // // let rest_block = self // .context // .append_basic_block(self.module.get_last_function().unwrap(), "rest"); @@ -453,7 +553,15 @@ impl<'a> CodegenContext<'a> { self.lower_native_operation(op, left, right, builder)? } ExpressionKind::Return(expr) => { + // println!("RETURN {:#?}", expr); let val = self.lower_expression(expr, builder)?; + // println!("RETURN2 {:#?}", val); + + // let val = val + // .is_pointer_value() + // .then(|| builder.build_load(val.into_pointer_value(), "test")) + // .or(Some(val)) + // .unwrap(); builder.build_return(Some(&val.as_basic_value_enum())); @@ -684,16 +792,27 @@ impl<'a> CodegenContext<'a> { pub fn lower_identifier( &mut self, id: &Identifier, - _builder: &'a Builder, + builder: &'a Builder, ) -> Result, ()> { let reso = self.hir.resolutions.get(&id.hir_id).unwrap(); - let val = match self.scopes.get(reso) { + let val = match self.scopes.get(reso.clone()) { None => { + self.module.print_to_stderr(); + println!("GEN : NO REO {:#?} {:#?}", id, reso); return Err(()); } Some(val) => val, }; + let t = self.hir.node_types.get(&id.get_hir_id()).unwrap(); + + // Dereference primitives only + // FIXME: get Array and String out of PrimitveType + let val = if val.is_pointer_value() && t.is_primitive() && !t.is_array() && !t.is_string() { + builder.build_load(val.into_pointer_value(), &id.name.to_string()) + } else { + val + }; Ok(val) } @@ -860,6 +979,26 @@ impl<'a> CodegenContext<'a> { .build_int_compare(IntPredicate::EQ, left, right, "beq") .as_basic_value_enum() } + + // arrays + NativeOperatorKind::Len => { + let arr_size = self + .hir + .node_types + .get(&left.get_hir_id()) + .and_then(|arr_t| arr_t.try_as_primitive_type()) + .and_then(|prim_t| prim_t.try_as_array()) + .map(|(_inner_t, size)| size) + .unwrap(); + + // FIXME: ignored right argument for now + // let right = self.lower_identifier(right, builder)?.into_int_value(); + + self.context + .i64_type() + .const_int(arr_size as u64, false) + .as_basic_value_enum() + } }) } } diff --git a/src/lib/codegen/interpreter.rs b/src/lib/codegen/interpreter.rs index 6132baf9..797f1018 100644 --- a/src/lib/codegen/interpreter.rs +++ b/src/lib/codegen/interpreter.rs @@ -112,16 +112,14 @@ fn process_line( let mut is_top_level = false; // FIXME: dirty hack to know if this is a function - let line_parts = line.split("=").collect::>(); + let line_parts = line.split('=').collect::>(); if line_parts.len() > 1 && !line_parts[0].starts_with("let ") && line_parts[0].split(" ").filter(|x| !x.is_empty()).count() > 1 { is_top_level = true; - } else { - if line.starts_with("use ") || line.starts_with("mod ") { - is_top_level = true; - } + } else if line.starts_with("use ") || line.starts_with("mod ") { + is_top_level = true; } if is_top_level { @@ -132,7 +130,7 @@ fn process_line( } } - let mut parsing_ctx = ParsingCtx::new(&config); + let mut parsing_ctx = ParsingCtx::new(config); let src = SourceFile::from_expr(top_levels.join("\n"), commands.join("\n"), !is_top_level).unwrap(); @@ -170,8 +168,8 @@ fn process_line( if get_type { let t = hir - .get_function_by_name(line.split(" ").nth(0).unwrap()) - .map(|f| format!("{:?}", Type::from(f.signature.clone()))) + .get_function_by_name(line.split(' ').next().unwrap()) + .map(|f| format!("{:?}", Type::from(f.signature))) .or_else(|| Some("UNKNOWN".red().to_string())) .unwrap(); diff --git a/src/lib/codegen/mod.rs b/src/lib/codegen/mod.rs index 360d2674..9aba0b50 100644 --- a/src/lib/codegen/mod.rs +++ b/src/lib/codegen/mod.rs @@ -15,6 +15,7 @@ pub fn generate(config: &Config, hir: Root) -> Result<(), Diagnostic> { if codegen_ctx.lower_hir(&hir, &builder).is_err() { // FIXME: have a movable `Diagnostics` // codegen_ctx.parsing_ctx.return_if_error()?; + panic!("GEN ERROR"); } match codegen_ctx.module.verify() { diff --git a/src/lib/helpers/scopes.rs b/src/lib/helpers/scopes.rs index dc06320d..b7fbd119 100644 --- a/src/lib/helpers/scopes.rs +++ b/src/lib/helpers/scopes.rs @@ -98,3 +98,32 @@ where self.ordering.push(s); } } + +#[cfg(test)] +mod tests { + use super::*; + + #[test] + fn basic_scope() { + let mut scopes = Scopes::default(); + + scopes.add("a", 1); + scopes.add("b", 2); + + assert_eq!(scopes.get("a").unwrap(), 1); + assert_eq!(scopes.get("b").unwrap(), 2); + + scopes.push(); + + scopes.add("a", 3); + scopes.add("b", 4); + + assert_eq!(scopes.get("a").unwrap(), 3); + assert_eq!(scopes.get("b").unwrap(), 4); + + scopes.pop(); + + assert_eq!(scopes.get("a").unwrap(), 1); + assert_eq!(scopes.get("b").unwrap(), 2); + } +} diff --git a/src/lib/hir/has_hir_id.rs b/src/lib/hir/has_hir_id.rs index 023fc3d6..e0d3c01d 100644 --- a/src/lib/hir/has_hir_id.rs +++ b/src/lib/hir/has_hir_id.rs @@ -57,6 +57,9 @@ impl_indirect_get_hir_id_trait!( ArgumentDecl IdentifierPath FnBody + For + ForIn + While Body Expression Array diff --git a/src/lib/hir/tree.rs b/src/lib/hir/tree.rs index 38cadbfb..d6f0d270 100644 --- a/src/lib/hir/tree.rs +++ b/src/lib/hir/tree.rs @@ -326,6 +326,7 @@ impl Statement { StatementKind::Expression(e) => e.get_hir_id(), StatementKind::Assign(a) => a.get_hir_id(), StatementKind::If(e) => e.get_hir_id(), + StatementKind::For(f) => f.get_hir_id(), } } } @@ -335,6 +336,47 @@ pub enum StatementKind { Expression(Expression), Assign(Assign), If(If), + For(For), +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub enum For { + In(ForIn), + While(While), +} + +impl For { + pub fn get_terminal_hir_id(&self) -> HirId { + match self { + For::In(i) => i.get_hir_id(), + For::While(w) => w.get_hir_id(), + } + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct While { + pub predicat: Expression, + pub body: Body, +} + +impl While { + pub fn get_terminal_hir_id(&self) -> HirId { + self.body.get_hir_id() + } +} + +#[derive(Debug, Clone, Serialize, Deserialize)] +pub struct ForIn { + pub value: Identifier, + pub expr: Expression, + pub body: Body, +} + +impl ForIn { + pub fn get_terminal_hir_id(&self) -> HirId { + self.body.get_hir_id() + } } #[derive(Debug, Clone, Serialize, Deserialize)] @@ -592,6 +634,7 @@ pub enum NativeOperatorKind { Fge, Flt, BEq, + Len, } impl std::fmt::Display for NativeOperatorKind { diff --git a/src/lib/hir/visit.rs b/src/lib/hir/visit.rs index 06e7ccab..5a1a4443 100644 --- a/src/lib/hir/visit.rs +++ b/src/lib/hir/visit.rs @@ -39,6 +39,9 @@ generate_visitor_trait!( FnBody Body Statement + For + ForIn + While Expression If Else @@ -151,9 +154,28 @@ pub fn walk_statement<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Statem StatementKind::Expression(expr) => visitor.visit_expression(expr), StatementKind::Assign(assign) => visitor.visit_assign(assign), StatementKind::If(expr) => visitor.visit_if(expr), + StatementKind::For(for_loop) => visitor.visit_for(for_loop), } } +pub fn walk_for<'a, V: Visitor<'a>>(visitor: &mut V, for_loop: &'a For) { + match for_loop { + For::In(for_in) => visitor.visit_for_in(for_in), + For::While(while_loop) => visitor.visit_while(while_loop), + } +} + +pub fn walk_for_in<'a, V: Visitor<'a>>(visitor: &mut V, for_in: &'a ForIn) { + visitor.visit_identifier(&for_in.value); + visitor.visit_expression(&for_in.expr); + visitor.visit_body(&for_in.body); +} + +pub fn walk_while<'a, V: Visitor<'a>>(visitor: &mut V, while_loop: &'a While) { + visitor.visit_expression(&while_loop.predicat); + visitor.visit_body(&while_loop.body); +} + pub fn walk_expression<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a Expression) { match &*expr.kind { ExpressionKind::Lit(lit) => visitor.visit_literal(lit), diff --git a/src/lib/hir/visit_mut.rs b/src/lib/hir/visit_mut.rs index ae4c7dd1..b11dc589 100644 --- a/src/lib/hir/visit_mut.rs +++ b/src/lib/hir/visit_mut.rs @@ -39,6 +39,9 @@ generate_visitor_mut_trait!( FnBody Body Statement + For + ForIn + While Expression If Else @@ -151,9 +154,28 @@ pub fn walk_statement<'a, V: VisitorMut<'a>>(visitor: &mut V, statement: &'a mut StatementKind::Expression(expr) => visitor.visit_expression(expr), StatementKind::Assign(assign) => visitor.visit_assign(assign), StatementKind::If(expr) => visitor.visit_if(expr), + StatementKind::For(for_loop) => visitor.visit_for(for_loop), } } +pub fn walk_for<'a, V: VisitorMut<'a>>(visitor: &mut V, for_loop: &'a mut For) { + match for_loop { + For::In(for_in) => visitor.visit_for_in(for_in), + For::While(while_loop) => visitor.visit_while(while_loop), + } +} + +pub fn walk_for_in<'a, V: VisitorMut<'a>>(visitor: &mut V, for_in: &'a mut ForIn) { + visitor.visit_identifier(&mut for_in.value); + visitor.visit_expression(&mut for_in.expr); + visitor.visit_body(&mut for_in.body); +} + +pub fn walk_while<'a, V: VisitorMut<'a>>(visitor: &mut V, while_loop: &'a mut While) { + visitor.visit_expression(&mut while_loop.predicat); + visitor.visit_body(&mut while_loop.body); +} + pub fn walk_assign_left_side<'a, V: VisitorMut<'a>>( visitor: &mut V, assign_left: &'a mut AssignLeftSide, diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index de3e67e9..73c0c0e6 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -464,11 +464,14 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { | NativeOperatorKind::FDiv | NativeOperatorKind::FMul => PrimitiveType::Float64, NativeOperatorKind::BEq => PrimitiveType::Bool, + NativeOperatorKind::Len => PrimitiveType::Void, // ignored }; - self.envs - .set_type(&left.hir_id.clone(), &arg_t.clone().into()); - self.envs.set_type(&right.hir_id.clone(), &arg_t.into()); + if !matches!(arg_t, PrimitiveType::Void) { + self.envs + .set_type(&left.hir_id.clone(), &arg_t.clone().into()); + self.envs.set_type(&right.hir_id.clone(), &arg_t.into()); + } self.visit_native_operator(op); } @@ -604,6 +607,28 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { } } + fn visit_for_in(&mut self, for_in: &'a ForIn) { + self.visit_expression(&for_in.expr); + + self.envs + .get_type(&for_in.expr.get_hir_id()) + .cloned() + .and_then(|expr_t| { + expr_t + .is_array() + .then(|| expr_t.try_as_primitive_type().unwrap()) + .and_then(|p| p.try_as_array()) + .map(|(inner_t, _size)| { + self.envs.set_type(&for_in.value.get_hir_id(), &inner_t) + }) + }); + + self.visit_body(&for_in.body); + + // assert expr to arr type + // set item to inner type; + } + fn visit_identifier_path(&mut self, id: &'a IdentifierPath) { self.visit_identifier(id.path.iter().last().unwrap()); } @@ -637,9 +662,10 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { | NativeOperatorKind::IDiv | NativeOperatorKind::IMul => PrimitiveType::Int64, NativeOperatorKind::FAdd - | NativeOperatorKind::FSub | NativeOperatorKind::FDiv - | NativeOperatorKind::FMul => PrimitiveType::Float64, + | NativeOperatorKind::FMul + | NativeOperatorKind::FSub => PrimitiveType::Float64, + NativeOperatorKind::Len => PrimitiveType::Int64, }; self.envs.set_type(&op.hir_id, &t.into()); diff --git a/src/lib/infer/state.rs b/src/lib/infer/state.rs index f7ad34e4..e9ea8453 100644 --- a/src/lib/infer/state.rs +++ b/src/lib/infer/state.rs @@ -127,7 +127,7 @@ impl Envs { previous.clone(), src_t.clone(), previous, - src_t.clone(), + src_t, )); } } diff --git a/src/lib/parser/lexer.rs b/src/lib/parser/lexer.rs index 909ecc36..f33386af 100644 --- a/src/lib/parser/lexer.rs +++ b/src/lib/parser/lexer.rs @@ -73,6 +73,7 @@ impl<'a> Lexer<'a> { Self::try_else_keyword, Self::try_then_keyword, Self::try_for_keyword, + Self::try_in_keyword, Self::try_struct_keyword, Self::try_infix_keyword, Self::try_use_keyword, @@ -233,6 +234,10 @@ impl<'a> Lexer<'a> { self.match_consume("for", TokenType::For, Sep::WS | Sep::EOL) } + fn try_in_keyword(&mut self) -> Option { + self.match_consume("in", TokenType::In, Sep::WS | Sep::EOL) + } + fn try_struct_keyword(&mut self) -> Option { self.match_consume("struct", TokenType::Struct, Sep::WS) } @@ -450,6 +455,7 @@ impl<'a> Lexer<'a> { let ops = vec![ "~IAdd", "~ISub", "~IMul", "~IDiv", "~FAdd", "~FSub", "~FMul", "~FDiv", "~IEq", "~Igt", "~Ige", "~Ilt", "~Ile", "~FEq", "~Fgt", "~Fge", "~Flt", "~Fle", "~BEq", + "~Len", ]; for op in ops { diff --git a/src/lib/parser/parser_impl.rs b/src/lib/parser/parser_impl.rs index 24ed0d54..6a6960cd 100644 --- a/src/lib/parser/parser_impl.rs +++ b/src/lib/parser/parser_impl.rs @@ -592,6 +592,8 @@ impl Parse for Statement { } } else if let Ok(assign) = Assign::parse(ctx) { StatementKind::Assign(Box::new(assign)) + } else if let Ok(for_loop) = For::parse(ctx) { + StatementKind::For(for_loop) } else { match Expression::parse(ctx) { Ok(expr) => StatementKind::Expression(Box::new(expr)), @@ -605,6 +607,60 @@ impl Parse for Statement { } } +impl Parse for For { + fn parse(ctx: &mut Parser) -> Result { + expect!(TokenType::For, ctx); + + ctx.save(); + + let res = if let Ok(forin) = ForIn::parse(ctx) { + For::In(forin) + } else if let Ok(while_) = While::parse(ctx) { + For::While(while_) + } else { + ctx.restore(); + + error!("Bad for".to_string(), ctx); + }; + + ctx.save_pop(); + + Ok(res) + } +} + +impl Parse for ForIn { + fn parse(ctx: &mut Parser) -> Result { + ctx.save(); + + let value = try_or_restore!(Identifier::parse(ctx), ctx); + + expect_or_restore!(TokenType::In, ctx); + + let expr = try_or_restore!(Expression::parse(ctx), ctx); + + let body = try_or_restore!(Body::parse(ctx), ctx); + + ctx.save_pop(); + + Ok(ForIn { value, expr, body }) + } +} + +impl Parse for While { + fn parse(ctx: &mut Parser) -> Result { + ctx.save(); + + let predicat = try_or_restore!(Expression::parse(ctx), ctx); + + let body = try_or_restore!(Body::parse(ctx), ctx); + + ctx.save_pop(); + + Ok(While { predicat, body }) + } +} + impl Parse for AssignLeftSide { fn parse(ctx: &mut Parser) -> Result { if ctx.seek(1).t == TokenType::OpenArray { @@ -1176,6 +1232,7 @@ impl Parse for NativeOperator { "~Flt" => NativeOperatorKind::Flt, "~Fle" => NativeOperatorKind::Fle, "~BEq" => NativeOperatorKind::BEq, + "~Len" => NativeOperatorKind::Len, _ => error!("Unknown native operator".to_string(), ctx), }; @@ -1213,7 +1270,7 @@ impl Parse for Type { let inner_t = Type::parse(ctx)?; // FIXME: FIXED ARRAY SIZE OF 1KB ! - let t = Type::Primitive(PrimitiveType::Array(Box::new(inner_t), 1024)); + let t = Type::Primitive(PrimitiveType::Array(Box::new(inner_t), 2)); expect!(TokenType::CloseArray, ctx); diff --git a/src/lib/parser/parsing_context.rs b/src/lib/parser/parsing_context.rs index 9f04d0a5..961e6e10 100644 --- a/src/lib/parser/parsing_context.rs +++ b/src/lib/parser/parsing_context.rs @@ -132,7 +132,7 @@ impl ParsingCtx { pub fn resolve_and_add_file(&mut self, name: String) -> Result { let current_file = self.get_current_file(); - let new_file = current_file.resolve_new(name.clone()).map_err(|m| { + let new_file = current_file.resolve_new(name).map_err(|m| { // Placeholder span, to be overriden by calling mod (TopLevel::parse()) Diagnostic::new_module_not_found(Span::new(current_file.file_path.clone(), 0, 0), m) })?; diff --git a/src/lib/parser/source_file.rs b/src/lib/parser/source_file.rs index 0d7416bb..ee3fe9d7 100644 --- a/src/lib/parser/source_file.rs +++ b/src/lib/parser/source_file.rs @@ -47,7 +47,7 @@ use lib::prelude::* "## .to_owned() + &top_levels - + &r##" + + r##" main = "## + &print_str.to_string() diff --git a/src/lib/parser/token.rs b/src/lib/parser/token.rs index d8529281..1c79f51c 100644 --- a/src/lib/parser/token.rs +++ b/src/lib/parser/token.rs @@ -16,7 +16,8 @@ pub enum TokenType { Then, Else, For, - // In, + In, + While, Struct, Infix, Trait, diff --git a/src/lib/resolver/resolve_ctx.rs b/src/lib/resolver/resolve_ctx.rs index 77059c0a..d3bfff42 100644 --- a/src/lib/resolver/resolve_ctx.rs +++ b/src/lib/resolver/resolve_ctx.rs @@ -90,6 +90,19 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { walk_list!(self, visit_top_level, &m.top_levels); } + // fn visit_for(&mut self, for_loop: &'a For) { + // self.visit_expression(&for_loop.expr); + // self.visit_body(&for_loop.body); + // } + + fn visit_for_in(&mut self, for_in: &'a ForIn) { + self.visit_expression(&for_in.expr); + + self.add_to_current_scope(for_in.value.name.clone(), for_in.value.identity.clone()); + + self.visit_body(&for_in.body); + } + fn visit_assign(&mut self, assign: &'a Assign) { self.visit_expression(&assign.value); diff --git a/src/lib/testcases/basic/reassign_return/main.rk b/src/lib/testcases/basic/reassign_return/main.rk new file mode 100644 index 00000000..139401ae --- /dev/null +++ b/src/lib/testcases/basic/reassign_return/main.rk @@ -0,0 +1,7 @@ +infix + 4 ++ a b = ~IAdd a b + +main = + let i = 21 + i = i + 21 + i diff --git a/src/lib/testcases/basic/reassign_return/main.rk.out b/src/lib/testcases/basic/reassign_return/main.rk.out new file mode 100644 index 00000000..f70d7bba --- /dev/null +++ b/src/lib/testcases/basic/reassign_return/main.rk.out @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/lib/testcases/basic/reassign_return/main.rk.stdout b/src/lib/testcases/basic/reassign_return/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/testcases/basic/while/main.rk b/src/lib/testcases/basic/while/main.rk new file mode 100644 index 00000000..36c6f397 --- /dev/null +++ b/src/lib/testcases/basic/while/main.rk @@ -0,0 +1,12 @@ +infix + 4 ++ a b = ~IAdd a b + +infix < 3 +< a b = ~Ilt a b + +main = + let i = 0 + let x = 42 + for i < x + i = i + 1 + i diff --git a/src/lib/testcases/basic/while/main.rk.out b/src/lib/testcases/basic/while/main.rk.out new file mode 100644 index 00000000..f70d7bba --- /dev/null +++ b/src/lib/testcases/basic/while/main.rk.out @@ -0,0 +1 @@ +42 \ No newline at end of file diff --git a/src/lib/testcases/basic/while/main.rk.stdout b/src/lib/testcases/basic/while/main.rk.stdout new file mode 100644 index 00000000..e69de29b diff --git a/src/lib/tests.rs b/src/lib/tests.rs index 93fede8f..a49d22e7 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -98,6 +98,10 @@ fn testcases_basic_nested_struct_dect_multiline_main() { run("testcases/basic/nested_struct_dect_multiline/main.rk", include_str!("testcases/basic/nested_struct_dect_multiline/main.rk"), include_str!("testcases/basic/nested_struct_dect_multiline/main.rk.out"), include_str!("testcases/basic/nested_struct_dect_multiline/main.rk.stdout")); } #[test] +fn testcases_basic_reassign_return_main() { + run("testcases/basic/reassign_return/main.rk", include_str!("testcases/basic/reassign_return/main.rk"), include_str!("testcases/basic/reassign_return/main.rk.out"), include_str!("testcases/basic/reassign_return/main.rk.stdout")); +} +#[test] fn testcases_basic_array_main() { run("testcases/basic/array/main.rk", include_str!("testcases/basic/array/main.rk"), include_str!("testcases/basic/array/main.rk.out"), include_str!("testcases/basic/array/main.rk.stdout")); } @@ -146,6 +150,10 @@ fn testcases_basic_main_main() { run("testcases/basic/main/main.rk", include_str!("testcases/basic/main/main.rk"), include_str!("testcases/basic/main/main.rk.out"), include_str!("testcases/basic/main/main.rk.stdout")); } #[test] +fn testcases_basic_while_main() { + run("testcases/basic/while/main.rk", include_str!("testcases/basic/while/main.rk"), include_str!("testcases/basic/while/main.rk.out"), include_str!("testcases/basic/while/main.rk.stdout")); +} +#[test] fn testcases_basic_fn_arg_main() { run("testcases/basic/fn_arg/main.rk", include_str!("testcases/basic/fn_arg/main.rk"), include_str!("testcases/basic/fn_arg/main.rk.out"), include_str!("testcases/basic/fn_arg/main.rk.stdout")); } diff --git a/src/lib/ty/func_type.rs b/src/lib/ty/func_type.rs index d4261178..6484eeca 100644 --- a/src/lib/ty/func_type.rs +++ b/src/lib/ty/func_type.rs @@ -290,7 +290,7 @@ mod tests { fn apply_forall_types() { let sig = FuncType::from_args_nb(2); - let res = sig.apply_forall_types(&vec![Type::forall("b")], &vec![Type::int64()]); + let res = sig.apply_forall_types(&[Type::forall("b")], &[Type::int64()]); assert_eq!(res.arguments[0], Type::forall("a")); assert_eq!(res.arguments[1], Type::int64()); @@ -312,7 +312,7 @@ mod tests { fn apply_partial_types() { let sig = FuncType::from_args_nb(2); - let res = sig.apply_partial_types(&vec![None, Some(Type::int64())], Some(Type::int64())); + let res = sig.apply_partial_types(&[None, Some(Type::int64())], Some(Type::int64())); assert_eq!(res.arguments[0], Type::forall("a")); assert_eq!(res.arguments[1], Type::int64()); diff --git a/src/lib/ty/primitive_type.rs b/src/lib/ty/primitive_type.rs index 9ee7fd51..c09bef96 100644 --- a/src/lib/ty/primitive_type.rs +++ b/src/lib/ty/primitive_type.rs @@ -81,4 +81,12 @@ impl PrimitiveType { pub fn is_array(&self) -> bool { matches!(self, PrimitiveType::Array(_, _)) } + + pub fn try_as_array(&self) -> Option<(Type, usize)> { + if let PrimitiveType::Array(t, s) = self { + Some((*t.clone(), *s)) + } else { + None + } + } } diff --git a/std/src/clone.rk b/std/src/clone.rk new file mode 100644 index 00000000..26f82b8b --- /dev/null +++ b/std/src/clone.rk @@ -0,0 +1,21 @@ +use super::externs::* + +trait Clone a + clone :: a -> a + +impl Clone Int64 + clone a = a + +impl Clone Float64 + clone a = a + +impl Clone String + clone a = + let s = c_malloc strlen a + c_strcpy s, a + s + +use super::functor::* + +impl Clone [Int64] + clone a = map clone, a diff --git a/std/src/externs.rk b/std/src/externs.rk new file mode 100644 index 00000000..08832bbe --- /dev/null +++ b/std/src/externs.rk @@ -0,0 +1,37 @@ +extern malloc :: Int64 -> String +c_malloc i = malloc i + +extern strlen :: String -> Int64 +c_strlen s = strlen s + +extern strcat :: String -> String -> String +c_strcat dest src = strcat dest, src + +extern strcpy :: String -> String -> String +c_strcpy dest src = strcpy dest, src + +extern sprintf :: String -> String -> Int64 -> Int64 +c_sprintf dest format i = sprintf dest, format, i + +extern gcvt :: Float64 -> Int64 -> String -> String -> String +c_gcvt float digits unused1 unused2 = gcvt float, digits, unused1, unused2 + +extern puts :: String -> Int64 +c_puts s = puts s + +extern memcpy :: String -> String -> Int64 -> String +c_memcpy dest src size = memcpy dest, src, size + +# FS + +extern open :: String -> Int64 -> Int64 -> Int64 +c_open path flags mode = open path, flags, mode + +extern close :: Int64 -> Int64 +c_close fd = close fd + +extern strtol :: String -> Int64 -> Int64 -> Int64 +c_strtol octal_str unused base = strtol octal_str, unused, base + +extern read :: Int64 -> String -> Int64 -> Int64 +c_read fd buf len = read fd, buf, len diff --git a/std/src/fs.rk b/std/src/fs.rk index c10a49f6..6b6a1605 100644 --- a/std/src/fs.rk +++ b/std/src/fs.rk @@ -1,8 +1,4 @@ -extern open :: String -> Int64 -> Int64 -> Int64 -extern close :: Int64 -> Int64 -extern strtol :: String -> Int64 -> Int64 -> Int64 -extern read :: Int64 -> String -> Int64 -> Int64 -extern malloc :: Int64 -> String +use super::externs::* use super::print::print use super::show::show @@ -17,19 +13,23 @@ impl Show File show f = "File { fd: " + show f.fd + ", path: " + f.path + " }" -oct_to_dec oct = strtol oct, 0, 8 +oct_to_dec oct = c_strtol oct, 0, 8 new_file p = - let f = open p, 0, oct_to_dec "0777" + let f = c_open p, 0, oct_to_dec "0777" File fd: f path: p read_file f = - let s = malloc 100 - let len = read f.fd, s, 100 + let s = c_malloc 100 + let len = c_read f.fd, s, 100 s - close_file f = - close f.fd + c_close f.fd + +_shut_up_warnings = + read_file new_file "" + close_file 0 + _shut_up_warnings() diff --git a/std/src/functor.rk b/std/src/functor.rk new file mode 100644 index 00000000..40106f5a --- /dev/null +++ b/std/src/functor.rk @@ -0,0 +1,22 @@ +use super::num::* +use super::eq::* + +map f arr = + let i = 0 + let arr2 = arr + for i < (~Len arr arr) + arr2[i] = f arr[i] + i = i + 1 + arr2 + +foreach f arr = + let i = 0 + for i < (~Len arr arr) + f arr[i] + i = i + 1 + arr + +_shut_up_warnings = + map 0, 0 + foreach 0, 0 + _shut_up_warnings() diff --git a/std/src/lib.rk b/std/src/lib.rk index 7aceaede..38acebaf 100644 --- a/std/src/lib.rk +++ b/std/src/lib.rk @@ -1,8 +1,14 @@ +mod externs +use externs::* + mod num mod eq mod show mod print mod fs +mod functor +mod clone +mod vec # mod helpers mod prelude diff --git a/std/src/num.rk b/std/src/num.rk index f531f599..dcc59fd7 100644 --- a/std/src/num.rk +++ b/std/src/num.rk @@ -21,6 +21,15 @@ impl Num Float64 * c d = ~FMul c d / c d = ~FDiv c d +<<<<<<< HEAD +use super::externs::* + +impl Num String + + a b = + let s = c_malloc (c_strlen a + c_strlen b) + c_strcpy s, a + c_strcat s, b +======= extern malloc :: Int64 -> String extern strlen :: String -> Int64 extern strcat :: String -> String -> String @@ -31,4 +40,5 @@ impl Num String let s = malloc (strlen a + strlen b) strcpy s, a strcat s, b +>>>>>>> 941899a6e59a448cc6cb3b082aea3fa990e886c8 s diff --git a/std/src/prelude.rk b/std/src/prelude.rk index 08b8abc5..0159ee59 100644 --- a/std/src/prelude.rk +++ b/std/src/prelude.rk @@ -2,3 +2,5 @@ use super::show::show use super::print::print use super::num::* use super::eq::* +use super::functor::* +use super::clone::* diff --git a/std/src/print.rk b/std/src/print.rk index 149d5b55..db34cd91 100644 --- a/std/src/print.rk +++ b/std/src/print.rk @@ -1,5 +1,8 @@ -extern puts :: String -> Int64 - +use super::externs::* use super::show::show -print a = puts show a +print a = c_puts show a + +_shut_up_warnings = + print 0 + _shut_up_warnings() diff --git a/std/src/show.rk b/std/src/show.rk index 3e3425d8..5b573f98 100644 --- a/std/src/show.rk +++ b/std/src/show.rk @@ -1,16 +1,16 @@ -extern malloc :: Int64 -> String -extern strlen :: String -> Int64 -extern strcpy :: String -> String -> Int64 -extern sprintf :: String -> String -> Int64 -> Int64 -extern gcvt :: Float64 -> Int64 -> String -> String -> String +use super::externs::* +use super::num::* +use super::eq::* itoa a = - let s = malloc 10 - sprintf s, "%d", a + let s = c_malloc 10 + + c_sprintf s, "%d", a + s ftoa c = - gcvt c, 10, (malloc 4), (malloc 4) + c_gcvt c, 10, (c_malloc 4), (c_malloc 4) trait Show a show :: a -> String @@ -29,6 +29,40 @@ impl Show Bool impl Show String show c = - let s = malloc strlen c - strcpy s, c + let s = c_malloc c_strlen c + + c_strcpy s, c + s + + +show_arr a = + let s = c_malloc 100 + + c_strcpy s, "[" + + let i = 0 + + let len = ~Len a a + + for i < len + c_strcat s, show a[i] + c_strcat s, ", " + + i = i + 1 + + c_strcat s, "]" + + s + +impl Show [Int64] + show a = show_arr a + +impl Show [Float64] + show a = show_arr a + +impl Show [String] + show a = show_arr a + +impl Show [Bool] + show a = show_arr a diff --git a/std/src/vec.rk b/std/src/vec.rk new file mode 100644 index 00000000..1486141d --- /dev/null +++ b/std/src/vec.rk @@ -0,0 +1,48 @@ +struct Vec + data :: String + cap :: Int64 + len :: Int64 + +use super::show::show +use super::externs::* + +impl Show Vec + show v = show v.len + +new_vec = + Vec + data: c_malloc 4 + cap: 1 + len: 0 + + +use super::num::* +use super::eq::* + +realloc_vec v = + let orig_data = v.data + + v.cap = v.cap * 2 + + v.data = c_malloc (v.cap * 4) + + c_memcpy v.data, orig_data + + 0 + +push_vec v item = + let d = v.data + d[v.len] = item + + v.len = v.len + 1 + + if v.len == v.cap + then realloc_vec v + else 0 + 0 + +_shut_up_warnings = + new_vec() + push_vec 0, 0 + realloc_vec 0 + _shut_up_warnings() From 16ce7a298e097a6ae135f345d8f1500f5d739733 Mon Sep 17 00:00:00 2001 From: Champii Date: Thu, 7 Oct 2021 13:08:06 +0000 Subject: [PATCH 23/74] Generated files for new version --- Cargo.toml | 2 +- README.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b2486c27..66eebfa9 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.8-loops" +version = "0.1.8-develop" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 55703ef8..41d14497 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.8-loops +# Rock v0.1.8-develop -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=loops)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little language made with Rust and LLVM. @@ -43,10 +43,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.8-loops](https://github.com/Champii/Rock/releases/download/v0.1.8-loops/rock) (Tested on arch, btw) +[Rock v0.1.8-develop](https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.8-loops/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock chmod +x rock ./rock -V ``` @@ -124,7 +124,7 @@ rock --repl ``` ``` sh -Rock: v0.1.8-loops +Rock: v0.1.8-develop ---- Type ':?' for help From a0ec4b201060c0b88a1078ff728c75c4f8d9e3f2 Mon Sep 17 00:00:00 2001 From: Florian Greiner Date: Fri, 17 Dec 2021 12:45:19 +0100 Subject: [PATCH 24/74] wip --- Cargo.lock | 42 ++++++++++++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ src/lib/ast/mod.rs | 2 ++ src/lib/parser/mod.rs | 1 + src/lib/rock.rs | 18 ++++++++++++++++++ 5 files changed, 65 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 1b1b6028..fa38bde1 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -52,6 +52,12 @@ version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "bef38d45163c2f1dde094a7dfd33ccf595c92905c8f8f4fdc18d06fb1037718a" +[[package]] +name = "bytecount" +version = "0.6.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "72feb31ffc86498dacdbd0fcebb56138e7177a8cc5cea4516031d15ae85a742e" + [[package]] name = "cc" version = "1.0.70" @@ -290,6 +296,12 @@ dependencies = [ "autocfg", ] +[[package]] +name = "minimal-lexical" +version = "0.1.4" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9c64630dcdd71f1a64c435f54885086a0de5d6a12d104d69b165fb7d5286d677" + [[package]] name = "nibble_vec" version = "0.1.0" @@ -312,6 +324,28 @@ dependencies = [ "memoffset", ] +[[package]] +name = "nom" +version = "7.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" +dependencies = [ + "memchr", + "minimal-lexical", + "version_check", +] + +[[package]] +name = "nom_locate" +version = "4.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "37794436ca3029a3089e0b95d42da1f0b565ad271e4d3bb4bad0c7bb70b10605" +dependencies = [ + "bytecount", + "memchr", + "nom", +] + [[package]] name = "once_cell" version = "1.8.0" @@ -441,6 +475,8 @@ dependencies = [ "inkwell", "lazy_static", "log", + "nom", + "nom_locate", "paste", "regex", "rustyline", @@ -596,6 +632,12 @@ version = "0.8.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "f1bddf1187be692e79c5ffeab891132dfb0f236ed36a43c7ed39f1165ee20191" +[[package]] +name = "version_check" +version = "0.9.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 66eebfa9..0436f5ba 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,8 @@ bincode = "*" colored = "2.0.0" paste = "1.0.5" rustyline = "9.0.0" +nom = "7.0.0" +nom_locate = "4.0.0" [lib] name = "rock" diff --git a/src/lib/ast/mod.rs b/src/lib/ast/mod.rs index 5fc23a83..7609dabb 100644 --- a/src/lib/ast/mod.rs +++ b/src/lib/ast/mod.rs @@ -2,9 +2,11 @@ pub mod ast_print; mod identity; +pub mod identity2; pub mod return_placement; pub mod span_collector; mod tree; +pub mod tree2; pub mod visit; pub use identity::*; diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index 792035fd..def03a57 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -5,6 +5,7 @@ mod parser_impl; mod parsing_context; mod source_file; mod span; +pub mod span2; mod token; pub use lexer::*; diff --git a/src/lib/rock.rs b/src/lib/rock.rs index 68d2cdee..ae09757e 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -9,6 +9,9 @@ extern crate bitflags; #[macro_use] extern crate log; +#[macro_use] +extern crate nom_locate; + use std::path::PathBuf; #[macro_use] @@ -24,6 +27,7 @@ mod codegen; pub mod diagnostics; mod hir; mod parser; +mod parser2; mod resolver; mod tests; mod ty; @@ -31,8 +35,12 @@ mod ty; use codegen::interpret; use diagnostics::Diagnostic; pub use helpers::config::Config; +use nom::Finish; +use nom_locate::LocatedSpan; use parser::{ParsingCtx, SourceFile}; +use crate::parser2::ParserCtx; + pub fn compile_file(in_name: String, config: &Config) -> Result<(), Diagnostic> { let mut source_file = SourceFile::from_file(in_name)?; @@ -60,6 +68,16 @@ pub fn compile_str(input: &SourceFile, config: &Config) -> Result<(), Diagnostic } pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { + let content = parsing_ctx.get_current_file().content.clone(); + let parser = LocatedSpan::new_extra( + content.as_str(), + ParserCtx::new(parsing_ctx.get_current_file().file_path.clone()), + ); + + let ast_test = parser2::parse_root(parser).finish(); + + println!("TEST {:#?}", ast_test); + // Text to Ast debug!(" -> Parsing"); let mut ast = parser::parse_root(parsing_ctx)?; From 82c7537867bae13f05571999832ee391074f3e50 Mon Sep 17 00:00:00 2001 From: Champii Date: Fri, 17 Dec 2021 11:45:42 +0000 Subject: [PATCH 25/74] Generated files for new version --- Cargo.toml | 4 +--- README.md | 10 +++++----- 2 files changed, 6 insertions(+), 8 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 0436f5ba..c0f0820d 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.8-develop" +version = "0.1.8-new-parser" authors = ["champii "] edition = "2018" @@ -20,8 +20,6 @@ bincode = "*" colored = "2.0.0" paste = "1.0.5" rustyline = "9.0.0" -nom = "7.0.0" -nom_locate = "4.0.0" [lib] name = "rock" diff --git a/README.md b/README.md index 41d14497..86d88aa6 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.8-develop +# Rock v0.1.8-new-parser -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=new_parser)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little language made with Rust and LLVM. @@ -43,10 +43,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.8-develop](https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock) (Tested on arch, btw) +[Rock v0.1.8-new-parser](https://github.com/Champii/Rock/releases/download/v0.1.8-new-parser/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.8-new-parser/rock chmod +x rock ./rock -V ``` @@ -124,7 +124,7 @@ rock --repl ``` ``` sh -Rock: v0.1.8-develop +Rock: v0.1.8-new-parser ---- Type ':?' for help From 6f1159a0e22eb475a8d853a7e203eece79934c81 Mon Sep 17 00:00:00 2001 From: Florian Greiner Date: Fri, 17 Dec 2021 12:46:28 +0100 Subject: [PATCH 26/74] wip --- src/lib/ast/identity2.rs | 15 + src/lib/ast/tree2.rs | 677 +++++++++++++++++++++++++++++++++++++++ src/lib/parser/span2.rs | 26 ++ src/lib/parser2/mod.rs | 346 ++++++++++++++++++++ src/lib/parser2/tests.rs | 116 +++++++ 5 files changed, 1180 insertions(+) create mode 100644 src/lib/ast/identity2.rs create mode 100644 src/lib/ast/tree2.rs create mode 100644 src/lib/parser/span2.rs create mode 100644 src/lib/parser2/mod.rs create mode 100644 src/lib/parser2/tests.rs diff --git a/src/lib/ast/identity2.rs b/src/lib/ast/identity2.rs new file mode 100644 index 00000000..42030b44 --- /dev/null +++ b/src/lib/ast/identity2.rs @@ -0,0 +1,15 @@ +use crate::parser::span2::Span; + +use crate::ast::NodeId; + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Identity { + pub node_id: NodeId, + pub span: Span, +} + +impl Identity { + pub fn new(node_id: NodeId, span: Span) -> Self { + Self { span, node_id } + } +} diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs new file mode 100644 index 00000000..e5d994c5 --- /dev/null +++ b/src/lib/ast/tree2.rs @@ -0,0 +1,677 @@ +use std::collections::HashMap; + +use crate::{ + ast::NodeId, + helpers::*, + parser::span2::Span, + resolver::ResolutionMap, + ty::{FuncType, Type}, +}; + +#[derive(Debug, Clone)] +pub struct Root { + pub r#mod: Mod, + pub resolutions: ResolutionMap, + pub operators_list: HashMap, + pub unused: Vec, + pub spans: HashMap, +} + +impl Root { + pub fn new(r#mod: Mod) -> Self { + Self { + r#mod, + resolutions: ResolutionMap::default(), + operators_list: HashMap::new(), + unused: vec![], + spans: HashMap::new(), + } + } +} + +#[derive(Debug, Clone)] +pub struct Mod { + pub top_levels: Vec, + // pub node_id: NodeId, // TODO: setup a ModId +} + +impl Mod { + pub fn new(top_levels: Vec) -> Self { + Self { top_levels } + } +} + +// #[derive(Debug, Clone)] +// pub struct TopLevel { +// pub kind: TopLevelKind, +// // pub node_id: NodeId, +// } + +#[derive(Debug, Clone)] +pub enum TopLevel { + Prototype(Prototype), + Function(FunctionDecl), + Trait(Trait), + Impl(Impl), + Struct(StructDecl), + Mod(Identifier, Mod), + Use(Use), + Infix(Operator, u8), +} + +impl TopLevel { + pub fn new_function(f: FunctionDecl) -> Self { + Self::Function(f) + } + + pub fn new_infix(op: Operator, pred: u8) -> Self { + Self::Infix(op, pred) + } + + pub fn new_prototype(proto: Prototype) -> Self { + Self::Prototype(proto) + } + + pub fn new_use(u: Use) -> Self { + Self::Use(u) + } +} + +#[derive(Debug, Clone)] +pub struct StructDecl { + pub node_id: NodeId, + pub name: Type, + pub defs: Vec, +} + +#[derive(Debug, Clone)] +pub struct StructCtor { + pub node_id: NodeId, + pub name: Type, + pub defs: HashMap, +} + +#[derive(Debug, Clone)] +pub struct Trait { + pub name: Type, + pub types: Vec, + pub defs: Vec, +} + +#[derive(Debug, Clone)] +pub struct Impl { + pub name: Type, + pub types: Vec, + pub defs: Vec, +} + +#[derive(Debug, Clone)] +pub struct Prototype { + pub name: Identifier, + pub signature: FuncType, + pub node_id: NodeId, +} + +impl Prototype { + pub fn mangle(&mut self, prefix: String) { + self.name.name = prefix + "_" + &self.name.name; + } +} + +#[derive(Debug, Clone)] +pub struct Use { + pub path: IdentifierPath, + pub node_id: NodeId, +} + +impl Use { + pub fn new(path: IdentifierPath) -> Self { + Self { path, node_id: 0 } + } +} + +#[derive(Debug, Clone)] +pub struct FunctionDecl { + pub name: Identifier, + // pub mangled_name: Option, + pub arguments: Vec, + pub body: Body, + // pub node_id: NodeId, + pub signature: FuncType, +} + +impl FunctionDecl { + pub fn mangle(&mut self, prefixes: &[String]) { + self.name.name = prefixes.join("_") + "_" + &self.name.name; + } +} + +generate_has_name!(FunctionDecl); + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct IdentifierPath { + pub path: Vec, +} + +impl IdentifierPath { + pub fn new(path: Vec) -> Self { + Self { path } + } + + pub fn new_root() -> Self { + Self { + path: vec![Identifier { + name: "root".to_string(), + node_id: 0, // FIXME: should have a valid node_id ? + }], + } + } + + pub fn parent(&self) -> Self { + let mut parent = self.clone(); + + if parent.path.len() > 1 { + parent.path.pop(); + } + + parent + } + + pub fn child(&self, name: Identifier) -> Self { + let mut child = self.clone(); + + child.path.push(name); + + child + } + + pub fn last_segment_ref(&self) -> &Identifier { + self.path.iter().last().unwrap() + } + + pub fn prepend_mod(&self, path: IdentifierPath) -> Self { + let mut path = path; + + path.path.extend::<_>(self.path.clone()); + + path + } + + pub fn resolve_supers(&mut self) { + let to_remove = self + .path + .iter() + .enumerate() + .filter_map( + |(i, name)| { + if name.name == *"super" { + Some(i) + } else { + None + } + }, + ) + .collect::>(); + + let mut to_remove_total = vec![]; + + for id in to_remove { + to_remove_total.extend(vec![id - 1, id]); + } + + self.path = self + .path + .iter() + .enumerate() + .filter_map(|(i, name)| { + if to_remove_total.contains(&i) { + None + } else { + Some(name.clone()) + } + }) + .collect::>(); + } +} + +#[derive(Debug, Clone, Eq)] +pub struct Identifier { + pub name: String, + pub node_id: NodeId, +} + +// impl Identifier { +// pub fn new(name: ) { + +// } +// } + +impl PartialEq for Identifier { + fn eq(&self, other: &Self) -> bool { + self.name == other.name + } +} + +impl std::hash::Hash for Identifier { + fn hash(&self, state: &mut H) { + self.name.hash(state); + } +} + +impl std::ops::Deref for Identifier { + type Target = String; + fn deref(&self) -> &Self::Target { + &self.name + } +} + +generate_has_name!(Identifier); + +pub type ArgumentsDecl = Vec; + +// #[derive(Debug, Clone)] +// pub struct ArgumentDecl { +// pub name: String, +// pub node_id: NodeId, +// } + +#[derive(Debug, Clone)] +pub struct Body { + pub stmts: Vec, +} + +impl Body { + pub fn new(stmts: Vec) -> Self { + Self { stmts } + } +} + +// #[derive(Debug, Clone)] +// pub struct Statement { +// pub kind: Box, +// } + +#[derive(Debug, Clone)] +pub enum Statement { + Expression(Box), + Assign(Box), + If(Box), + For(For), +} + +impl Statement { + pub fn new_expression(expr: Expression) -> Self { + Self::Expression(Box::new(expr)) + } +} + +#[derive(Debug, Clone)] +pub enum For { + In(ForIn), + While(While), +} + +#[derive(Debug, Clone)] +pub struct While { + pub predicat: Expression, + pub body: Body, +} + +#[derive(Debug, Clone)] +pub struct ForIn { + pub value: Identifier, + pub expr: Expression, + pub body: Body, +} + +#[derive(Debug, Clone)] +pub enum AssignLeftSide { + Identifier(Identifier), + Indice(Expression), + Dot(Expression), +} + +impl AssignLeftSide { + pub fn as_expression(&self) -> Expression { + match self { + AssignLeftSide::Identifier(i) => { + Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { + op: Operand::new_identifier(i.clone()), + node_id: i.node_id.clone(), + secondaries: None, + })) + } + + AssignLeftSide::Indice(i) => i.clone(), + AssignLeftSide::Dot(d) => d.clone(), + } + } +} +// impl AssignLeftSide { +// pub fn get_node_id(&self) -> NodeId { +// use AssignLeftSide::*; + +// match self { +// Identifier(id) => id.node_id.node_id, +// Indice(expr) => expr., +// } +// } +// } + +#[derive(Debug, Clone)] +pub struct Assign { + pub name: AssignLeftSide, + pub value: Expression, + pub is_let: bool, +} + +#[derive(Debug, Clone)] +pub struct If { + pub node_id: NodeId, + pub predicat: Expression, + pub body: Body, + pub else_: Option>, +} + +#[derive(Debug, Clone)] +pub enum Else { + If(If), + Body(Body), +} + +// #[derive(Debug, Clone)] +// pub struct Expression { +// pub kind: ExpressionKind, +// } + +impl Expression { + #[allow(dead_code)] + pub fn is_literal(&self) -> bool { + match &self { + Expression::UnaryExpr(unary) => unary.is_literal(), + _ => false, + } + } + + #[allow(dead_code)] + pub fn is_identifier(&self) -> bool { + match &self { + Expression::UnaryExpr(unary) => unary.is_identifier(), + _ => false, + } + } + + #[allow(dead_code)] + pub fn is_binop(&self) -> bool { + matches!(&self, Expression::BinopExpr(_, _, _)) + } + + #[allow(dead_code)] + pub fn is_indice(&self) -> bool { + match &self { + Expression::UnaryExpr(unary) => unary.is_indice(), + _ => false, + } + } + + #[allow(dead_code)] + pub fn new_unary(unary: UnaryExpr) -> Expression { + Expression::UnaryExpr(unary) + } + + #[allow(dead_code)] + pub fn new_binop(unary: UnaryExpr, operator: Operator, expr: Expression) -> Expression { + Expression::BinopExpr(unary, operator, Box::new(expr)) + } + + // #[allow(dead_code)] + // pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> Expression { + // Expression { + // kind: Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { + // node_id: node_id::new_placeholder(), + // op, + // secondaries: Some(vec![SecondaryExpr::Arguments(vec![ + // Argument { arg: arg1 }, + // Argument { arg: arg2 }, + // ])]), + // })), + // } + // } +} + +#[derive(Debug, Clone)] +pub enum Expression { + BinopExpr(UnaryExpr, Operator, Box), + UnaryExpr(UnaryExpr), + NativeOperation(NativeOperator, Identifier, Identifier), + StructCtor(StructCtor), + Return(Box), +} + +#[derive(Debug, Clone)] +pub enum UnaryExpr { + PrimaryExpr(PrimaryExpr), + UnaryExpr(Operator, Box), +} + +impl UnaryExpr { + pub fn is_literal(&self) -> bool { + match self { + UnaryExpr::PrimaryExpr(p) => matches!(&p.op, Operand::Literal(_)), + _ => false, + } + } + + pub fn is_identifier(&self) -> bool { + match self { + UnaryExpr::PrimaryExpr(p) => matches!(&p.op, Operand::Identifier(_)), + _ => false, + } + } + + pub fn is_indice(&self) -> bool { + match self { + UnaryExpr::UnaryExpr(_, unary) => unary.is_indice(), + UnaryExpr::PrimaryExpr(prim) => prim.is_indice(), + } + } + + // pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> UnaryExpr { + // UnaryExpr::PrimaryExpr(PrimaryExpr { + // node_id: node_id::new_placeholder(), + // op, + // secondaries: Some(vec![SecondaryExpr::Arguments(vec![ + // Argument { arg: arg1 }, + // Argument { arg: arg2 }, + // ])]), + // }) + // } + + pub fn new_primary(primary: PrimaryExpr) -> UnaryExpr { + UnaryExpr::PrimaryExpr(primary) + } +} + +#[derive(Debug, Clone)] +pub struct Operator(pub Identifier); + +#[derive(Debug, Clone)] +pub struct PrimaryExpr { + pub node_id: NodeId, + pub op: Operand, + pub secondaries: Option>, +} + +impl PrimaryExpr { + #[allow(dead_code)] + pub fn has_secondaries(&self) -> bool { + self.secondaries.is_some() + } + + pub fn is_indice(&self) -> bool { + if let Some(secondaries) = &self.secondaries { + secondaries.iter().any(|secondary| secondary.is_indice()) + } else { + false + } + } + + pub fn new(op: Operand) -> PrimaryExpr { + PrimaryExpr { + op, + node_id: 0, + secondaries: None, + } + } +} + +// #[derive(Debug, Clone)] +// pub struct Operand { +// pub kind: Operand, +// } + +#[derive(Debug, Clone)] +pub enum Operand { + Literal(Literal), + Identifier(IdentifierPath), + Expression(Box), // parenthesis +} + +impl Operand { + pub fn new_identifier_path(id: IdentifierPath) -> Self { + Self::Identifier(id) + } + + pub fn new_identifier(id: Identifier) -> Self { + Self::Identifier(IdentifierPath { + path: vec![id.clone()], + }) + } + + pub fn new_expression(expr: Expression) -> Self { + Self::Expression(Box::new(expr)) + } + + #[allow(dead_code)] + pub fn is_literal(&self) -> bool { + matches!(&self, Operand::Literal(_)) + } + + #[allow(dead_code)] + pub fn is_identifier(&self) -> bool { + matches!(&self, Operand::Identifier(_)) + } + + pub fn new_literal(lit: Literal) -> Operand { + Operand::Literal(lit) + } +} + +impl Operand { + #[allow(dead_code)] + pub fn to_identifier_path(&self) -> IdentifierPath { + if let Operand::Identifier(id) = self { + id.clone() + } else { + panic!("Not an identifier path") + } + } +} + +#[derive(Debug, Clone)] +pub enum SecondaryExpr { + Arguments(Vec), + Indice(Box), // Boxing here to keep the enum size low + Dot(Identifier), +} + +impl SecondaryExpr { + pub fn is_indice(&self) -> bool { + matches!(self, SecondaryExpr::Indice(_)) + } +} + +#[derive(Debug, Clone)] +pub struct Literal { + pub kind: LiteralKind, + pub node_id: NodeId, +} + +impl Literal { + pub fn new_bool(b: bool, node_id: NodeId) -> Self { + Self { + kind: LiteralKind::Bool(b), + node_id, + } + } + + pub fn new_number(num: i64, node_id: NodeId) -> Self { + Self { + kind: LiteralKind::Number(num), + node_id, + } + } + + pub fn new_float(num: f64, node_id: NodeId) -> Self { + Self { + kind: LiteralKind::Float(num), + node_id, + } + } + + pub fn as_i64(&self) -> i64 { + match self.kind { + LiteralKind::Number(n) => n, + _ => panic!("Not a Number"), + } + } +} + +#[derive(Debug, Clone)] +pub enum LiteralKind { + Bool(bool), + Number(i64), + Float(f64), +} + +#[derive(Debug, Clone)] +pub struct Array { + pub values: Vec, +} + +pub type Arguments = Vec; + +#[derive(Debug, Clone)] +pub struct Argument { + pub arg: UnaryExpr, +} + +#[derive(Debug, Clone)] +pub struct NativeOperator { + pub kind: NativeOperatorKind, + pub node_id: NodeId, +} + +#[derive(Debug, Clone)] +pub enum NativeOperatorKind { + IAdd, + ISub, + IMul, + IDiv, + FAdd, + FSub, + FMul, + FDiv, + IEq, + Igt, + Ige, + Ilt, + Ile, + FEq, + Fgt, + Fge, + Flt, + Fle, + BEq, + Len, +} diff --git a/src/lib/parser/span2.rs b/src/lib/parser/span2.rs new file mode 100644 index 00000000..99f3ef82 --- /dev/null +++ b/src/lib/parser/span2.rs @@ -0,0 +1,26 @@ +use std::path::PathBuf; + +use crate::parser2::Parser; + +// TODO: merge spans + +#[derive(Debug, Clone, Hash, PartialEq, Eq)] +pub struct Span { + file_path: PathBuf, + offset: usize, + line: usize, + column: usize, + txt: String, +} + +impl<'a> From> for Span { + fn from(source: Parser<'a>) -> Self { + Self { + file_path: source.extra.current_file_path().clone(), + offset: source.location_offset(), + line: source.location_line() as usize, + column: source.get_column(), + txt: source.to_string(), + } + } +} diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs new file mode 100644 index 00000000..6d299839 --- /dev/null +++ b/src/lib/parser2/mod.rs @@ -0,0 +1,346 @@ +use std::collections::HashMap; +use std::path::PathBuf; + +use nom::branch::alt; +use nom::bytes::complete::{tag, take_while}; +use nom::character::complete::{ + alphanumeric0, alphanumeric1, char, line_ending, multispace0, one_of, satisfy, space0, space1, +}; +use nom::character::is_alphanumeric; +use nom::combinator::{map, map_res, opt, recognize}; +use nom::error::{Error, ErrorKind}; +use nom::multi::{many0, many1, separated_list0, separated_list1}; +use nom::sequence::{delimited, preceded, separated_pair, terminated, tuple}; +use nom::{Err, IResult}; + +use crate::ast::identity2::Identity; +use crate::ast::tree2::*; +use crate::ast::NodeId; +use crate::parser::span2::Span; +use crate::ty::{FuncType, Type}; + +use nom_locate::{position, LocatedSpan}; +pub type Parser<'a> = LocatedSpan<&'a str, ParserCtx>; + +#[cfg(test)] +mod tests; + +#[derive(Debug, Clone)] +pub struct ParserCtx { + cur_file_path: PathBuf, + identities: Vec, + operators_list: HashMap, +} + +impl ParserCtx { + pub fn new(file_path: PathBuf) -> Self { + Self { + cur_file_path: file_path, + identities: Vec::new(), + operators_list: HashMap::new(), + } + } + + pub fn new_identity(&mut self, span: Span) -> NodeId { + let node_id = self.identities.len() as NodeId; + + self.identities.push(Identity::new(node_id, span)); + + node_id + } + + pub fn current_file_path(&self) -> &PathBuf { + &self.cur_file_path + } + + // pub fn identities(&self) -> &Vec { + // &self.identities + // } + + pub fn operators(&self) -> &HashMap { + &self.operators_list + } + + pub fn add_operator(&mut self, op: String, prec: u8) { + self.operators_list.insert(op, prec); + } +} + +pub fn parse_root(input: Parser) -> IResult { + map(parse_mod, Root::new)(input) +} + +pub fn parse_mod(input: Parser) -> IResult { + map( + many1(terminated(parse_top_level, many1(line_ending))), + Mod::new, + )(input) +} + +pub fn parse_top_level(input: Parser) -> IResult { + alt(( + preceded( + terminated(tag("extern"), space1), + map(parse_prototype, TopLevel::new_prototype), + ), + parse_infix, + map(parse_use, TopLevel::new_use), + map(parse_fn, TopLevel::new_function), + ))(input) +} + +pub fn parse_use(input: Parser) -> IResult { + preceded( + terminated(tag("use"), space1), + map(parse_identifier_path, Use::new), + )(input) +} + +pub fn parse_infix(input: Parser) -> IResult { + let (mut input, (parsed_op, pred)) = preceded( + terminated(tag("infix"), space1), + tuple(( + terminated(many1(allowed_operator_chars), space1), + parse_number, + )), + )(input)?; + + // let (input, node_id) = new_identity(input, &parsed_op); + + let op = parsed_op.join(""); + + input.extra.add_operator(op.clone(), pred.as_i64() as u8); + + let op = Operator(Identifier { + name: op, + node_id: 0, + }); + + Ok((input, TopLevel::new_infix(op, pred.as_i64() as u8))) +} + +pub fn parse_prototype(input: Parser) -> IResult { + map( + tuple(( + terminated(parse_identifier, delimited(space0, tag("::"), space0)), + parse_signature, + )), + |(name, signature)| Prototype { + node_id: name.node_id, + name, + signature, + }, + )(input) +} + +pub fn parse_fn(input: Parser) -> IResult { + map( + tuple(( + terminated( + tuple((parse_identifier, many0(preceded(space1, parse_identifier)))), + delimited(space0, char('='), space0), + ), + parse_body, + )), + |((name, arguments), body)| FunctionDecl { + name, + body, + signature: FuncType::from_args_nb(arguments.len()), + arguments, + }, + )(input) +} + +pub fn parse_body(input: Parser) -> IResult { + map(many1(parse_statement), Body::new)(input) +} + +pub fn parse_statement(input: Parser) -> IResult { + map(parse_expression, Statement::new_expression)(input) +} + +pub fn parse_expression(input: Parser) -> IResult { + alt(( + map( + tuple(( + parse_unary, + delimited(space0, parse_operator, space0), + parse_expression, + )), + |(l, op, r)| Expression::new_binop(l, op, r), + ), + map(parse_unary, Expression::new_unary), + ))(input) +} + +pub fn parse_unary(input: Parser) -> IResult { + map(parse_primary, UnaryExpr::new_primary)(input) +} + +pub fn parse_primary(input: Parser) -> IResult { + map(parse_operand, PrimaryExpr::new)(input) +} + +pub fn parse_operand(input: Parser) -> IResult { + alt(( + map(parse_literal, Operand::new_literal), + map(parse_identifier_path, Operand::new_identifier_path), + map( + delimited( + delimited(space0, tag("("), space0), + parse_expression, + delimited(space0, tag(")"), space0), + ), + Operand::new_expression, + ), + ))(input) +} + +pub fn parse_identifier_path(input: Parser) -> IResult { + map( + separated_list1(tag("::"), parse_identifier), + IdentifierPath::new, + )(input) +} + +pub fn parse_identifier(input: Parser) -> IResult { + let (input, ident_parsed) = alphanumeric1(input)?; + + let (input, node_id) = new_identity(input, &ident_parsed); + + Ok(( + input, + Identifier { + name: ident_parsed.to_string(), + node_id, + }, + )) +} + +pub fn parse_operator(input: Parser) -> IResult { + let (input, parsed_op) = one_of(LocatedSpan::new( + input + .extra + .operators() + .keys() + .cloned() + .collect::>() + .join("") + .as_str(), + ))(input)?; + + let (input, pos) = position(input)?; + + let (input, node_id) = new_identity(input, &pos); + + Ok(( + input, + Operator(Identifier { + name: parsed_op.to_string(), + node_id, + }), + )) +} + +pub fn parse_literal(input: Parser) -> IResult { + alt((parse_bool, parse_float, parse_number))(input) +} + +pub fn parse_bool(input: Parser) -> IResult { + let (input, bool_parsed) = alt((tag("true"), tag("false")))(input)?; + + let num: bool = bool_parsed + .parse() + .map_err(|_| Err::Error(Error::new(input.clone(), ErrorKind::Alpha)))?; + + let (input, node_id) = new_identity(input, &bool_parsed); + + Ok((input, Literal::new_bool(num, node_id))) +} + +pub fn parse_float(input: Parser) -> IResult { + let (input, float_parsed) = + recognize(tuple((parse_number, char('.'), opt(parse_number))))(input)?; + + let num: f64 = float_parsed + .parse() + .map_err(|_| Err::Error(Error::new(input.clone(), ErrorKind::Float)))?; + + let (input, node_id) = new_identity(input, &float_parsed); + + Ok((input, Literal::new_float(num, node_id))) +} + +pub fn parse_number(input: Parser) -> IResult { + let (input, parsed) = take_while(is_digit)(input)?; + + let num: i64 = parsed + .parse() + .map_err(|_| Err::Error(Error::new(input.clone(), ErrorKind::Digit)))?; + + let (input, node_id) = new_identity(input, &parsed); + + Ok((input, Literal::new_number(num, node_id))) +} + +// Types + +pub fn parse_signature(input: Parser) -> IResult { + let (input, parsed) = tuple(( + parse_type, + many0(preceded(delimited(space0, tag("->"), space0), parse_type)), + ))(input)?; + + let mut types = vec![parsed.0]; + + types.extend(parsed.1); + + let ret = types.pop().unwrap(); + + Ok(( + input, + FuncType::from_args_nb(types.len()).apply_types(types, ret), + )) +} + +pub fn parse_type(input: Parser) -> IResult { + let (input, parsed) = parse_capitalized_text(input)?; + + let ty = Type::from(parsed); + + Ok((input, ty)) +} + +pub fn parse_capitalized_text(input: Parser) -> IResult { + let (input, parsed) = tuple((satisfy(char::is_uppercase), alphanumeric0))(input)?; + + let txt = + format!("{}", parsed.0) + &String::from_utf8(parsed.1.bytes().collect::>()).unwrap(); + + Ok((input, txt)) +} + +// Helpers + +fn is_digit(c: char) -> bool { + c.is_numeric() +} + +fn new_identity<'a>(mut input: Parser<'a>, parsed: &Parser<'a>) -> (Parser<'a>, NodeId) { + let node_id = input.extra.new_identity(Span::from(parsed.clone())); + + (input, node_id) +} + +pub fn allowed_operator_chars(input: Parser) -> IResult { + let (input, c) = one_of(LocatedSpan::new( + crate::parser::accepted_operator_chars() + .iter() + .map(|c| c.to_string()) + .collect::>() + .join("") + .as_str(), + ))(input)?; + + Ok((input, c.to_string())) +} diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs new file mode 100644 index 00000000..d212b133 --- /dev/null +++ b/src/lib/parser2/tests.rs @@ -0,0 +1,116 @@ +use nom::Finish; + +use super::*; + +#[cfg(test)] +mod parse_literal { + use super::*; + + #[test] + fn bool() { + let input = Parser::new_extra("true", ParserCtx::new(PathBuf::new())); + + let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); + + assert!(matches!(num_parsed.kind, LiteralKind::Bool(true))); + } + + #[test] + fn number() { + let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); + + let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); + + assert!(matches!(num_parsed.kind, LiteralKind::Number(42))); + } + + #[test] + fn float() { + let input = Parser::new_extra("42.42", ParserCtx::new(PathBuf::new())); + + let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); + + assert!(matches!(num_parsed.kind, LiteralKind::Float(f) if f == 42.42)); + } +} + +#[cfg(test)] +mod parse_bool { + use super::*; + + #[test] + fn r#true() { + let input = Parser::new_extra("true", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_bool(input).finish().unwrap(); + + assert!(matches!(parsed.kind, LiteralKind::Bool(true))); + } + + #[test] + fn r#false() { + let input = Parser::new_extra("false", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_bool(input).finish().unwrap(); + + assert!(matches!(parsed.kind, LiteralKind::Bool(false))); + } + + #[test] + fn invalid() { + let input = Parser::new_extra("atrue", ParserCtx::new(PathBuf::new())); + + assert!(parse_bool(input).finish().is_err()); + } +} + +#[cfg(test)] +mod parse_float { + use super::*; + + #[test] + fn valid_with_last_part() { + let input = Parser::new_extra("42.42", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_float(input).finish().unwrap(); + + assert!(matches!(parsed.kind, LiteralKind::Float(f) if f == 42.42)); + } + + #[test] + fn valid_no_last_part() { + let input = Parser::new_extra("42.", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_float(input).finish().unwrap(); + + assert!(matches!(parsed.kind, LiteralKind::Float(f) if f == 42.0)); + } + + #[test] + fn invalid() { + let input = Parser::new_extra("a42.", ParserCtx::new(PathBuf::new())); + + assert!(parse_float(input).finish().is_err()); + } +} + +#[cfg(test)] +mod parse_number { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_number(input).finish().unwrap(); + + assert!(matches!(parsed.kind, LiteralKind::Number(42))); + } + + #[test] + fn invalid() { + let input = Parser::new_extra("a42", ParserCtx::new(PathBuf::new())); + + assert!(parse_number(input).finish().is_err()); + } +} From c55316e10507f92aa22f082640a28448884ab385 Mon Sep 17 00:00:00 2001 From: Florian Greiner Date: Fri, 17 Dec 2021 12:58:09 +0100 Subject: [PATCH 27/74] add nom to template cargo.toml --- .github/templates/Cargo.toml | 2 ++ Cargo.lock | 10 +++++----- Cargo.toml | 2 ++ 3 files changed, 9 insertions(+), 5 deletions(-) diff --git a/.github/templates/Cargo.toml b/.github/templates/Cargo.toml index 554ec945..48842bc3 100644 --- a/.github/templates/Cargo.toml +++ b/.github/templates/Cargo.toml @@ -20,6 +20,8 @@ bincode = "*" colored = "2.0.0" paste = "1.0.5" rustyline = "9.0.0" +nom = "7.0.0" +nom_locate = "4.0.0" [lib] name = "rock" diff --git a/Cargo.lock b/Cargo.lock index fa38bde1..edbcd330 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -298,9 +298,9 @@ dependencies = [ [[package]] name = "minimal-lexical" -version = "0.1.4" +version = "0.2.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c64630dcdd71f1a64c435f54885086a0de5d6a12d104d69b165fb7d5286d677" +checksum = "68354c5c6bd36d73ff3feceb05efa59b6acb7626617f4962be322a825e61f79a" [[package]] name = "nibble_vec" @@ -326,9 +326,9 @@ dependencies = [ [[package]] name = "nom" -version = "7.0.0" +version = "7.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "7ffd9d26838a953b4af82cbeb9f1592c6798916983959be223a7124e992742c1" +checksum = "1b1d11e1ef389c76fe5b81bcaf2ea32cf88b62bc494e19f493d0b30e7a930109" dependencies = [ "memchr", "minimal-lexical", @@ -464,7 +464,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rock" -version = "0.1.8-develop" +version = "0.1.8-new-parser" dependencies = [ "bincode", "bitflags", diff --git a/Cargo.toml b/Cargo.toml index c0f0820d..1ef7317e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -20,6 +20,8 @@ bincode = "*" colored = "2.0.0" paste = "1.0.5" rustyline = "9.0.0" +nom = "7.0.0" +nom_locate = "4.0.0" [lib] name = "rock" From 3288622aca55f49b5ca61ebc0ce30d98436b45f6 Mon Sep 17 00:00:00 2001 From: Champii Date: Sun, 16 Jan 2022 06:44:25 +0100 Subject: [PATCH 28/74] Add some tests for the parser --- src/lib/ast/tree2.rs | 2 +- src/lib/diagnostics/diagnostic.rs | 11 ++ src/lib/parser/span2.rs | 2 + src/lib/parser2/mod.rs | 8 + src/lib/parser2/tests.rs | 283 ++++++++++++++++++++++++++++++ src/lib/tests.rs | 172 +++++++++--------- 6 files changed, 391 insertions(+), 87 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index e5d994c5..fc166331 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -492,7 +492,7 @@ impl UnaryExpr { } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Operator(pub Identifier); #[derive(Debug, Clone)] diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index 9b9e1417..f94317a9 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -1,5 +1,6 @@ use std::fmt::Display; +use crate::parser2::Parser; use crate::{diagnostics::DiagnosticType, parser::Span}; use crate::{ hir::HirId, @@ -271,3 +272,13 @@ impl Display for DiagnosticKind { write!(f, "{}", s) } } + +/* impl<'a> From> for Diagnostic { + fn from(err: Parser<'a>) -> Self { + let span = Span::from(err); + + let msg = "Syntax error".to_string(); + + Diagnostic::new_syntax_error(span, msg) + } +} */ diff --git a/src/lib/parser/span2.rs b/src/lib/parser/span2.rs index 99f3ef82..f1a0e9e1 100644 --- a/src/lib/parser/span2.rs +++ b/src/lib/parser/span2.rs @@ -1,5 +1,7 @@ use std::path::PathBuf; +use nom_locate::LocatedSpan; + use crate::parser2::Parser; // TODO: merge spans diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 6d299839..2975ec4a 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -41,6 +41,14 @@ impl ParserCtx { } } + pub fn new_with_operators(file_path: PathBuf, operators: HashMap) -> Self { + Self { + cur_file_path: file_path, + identities: Vec::new(), + operators_list: operators, + } + } + pub fn new_identity(&mut self, span: Span) -> NodeId { let node_id = self.identities.len() as NodeId; diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index d212b133..c68e3027 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -114,3 +114,286 @@ mod parse_number { assert!(parse_number(input).finish().is_err()); } } +/* +#[cfg(test)] +mod parse_string { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("\"hello\"", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_string(input).finish().unwrap(); + + assert!(matches!(parsed.kind, LiteralKind::String(ref s) if s == "hello")); + } + + #[test] + fn invalid() { + let input = Parser::new_extra("\"hello", ParserCtx::new(PathBuf::new())); + + assert!(parse_string(input).finish().is_err()); + } +} */ + +#[cfg(test)] +mod parse_signature { + use super::*; + + #[test] + fn valid_1_arg() { + let input = Parser::new_extra("Int64", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_signature(input).finish().unwrap(); + + assert_eq!(parsed.arguments, vec![]); + assert_eq!(parsed.ret, Box::new(Type::int64())); + } + + fn valid_2_arg() { + let input = Parser::new_extra("Int64 -> Int64", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_signature(input).finish().unwrap(); + + assert_eq!(parsed.arguments, vec![Type::int64()]); + assert_eq!(parsed.ret, Box::new(Type::int64())); + } +} + +#[cfg(test)] +mod parse_type { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("Int64", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_type(input).finish().unwrap(); + + assert_eq!(parsed, Type::int64()); + } + + #[test] + fn invalid() { + let input = Parser::new_extra("int64", ParserCtx::new(PathBuf::new())); + + assert!(parse_type(input).finish().is_err()); + } +} + +#[cfg(test)] +mod parse_infix_op { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("infix + 5", ParserCtx::new(PathBuf::new())); + + let (rest, parsed) = parse_infix(input).finish().unwrap(); + + matches!(parsed, TopLevel::Infix(op, 5)); + + let operators = HashMap::from([("+".to_string(), 5)]); + assert_eq!(rest.extra.operators_list, operators); + } +} + +#[cfg(test)] +mod parse_operator { + use super::*; + + #[test] + fn valid() { + let operators = HashMap::from([("+".to_string(), 5)]); + + let input = Parser::new_extra( + "+", + ParserCtx::new_with_operators(PathBuf::new(), operators), + ); + + let (rest, parsed) = parse_operator(input).finish().unwrap(); + + assert_eq!( + parsed, + Operator(Identifier { + name: String::from("+"), + node_id: 0, + }) + ); + } +} + +#[cfg(test)] +mod parse_identifier { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("foo", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_identifier(input).finish().unwrap(); + + assert_eq!( + parsed, + Identifier { + name: String::from("foo"), + node_id: 0, + } + ); + } +} + +#[cfg(test)] +mod parse_identifier_path { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("foo::bar", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_identifier_path(input).finish().unwrap(); + + assert_eq!( + parsed, + IdentifierPath { + path: vec![ + Identifier { + name: String::from("foo"), + node_id: 0, + }, + Identifier { + name: String::from("bar"), + node_id: 0, + }, + ], + } + ); + } +} + +#[cfg(test)] +mod parse_operand { + use super::*; + + #[test] + fn valid_literal() { + let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_operand(input).finish().unwrap(); + + matches!( + parsed, + Operand::Literal(Literal { + kind: LiteralKind::Number(42), + node_id: 0, + }) + ); + } + + #[test] + fn valid_identifier_path() { + let input = Parser::new_extra("foo::bar", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_operand(input).finish().unwrap(); + + matches!(parsed, Operand::Identifier(IdentifierPath { path })); + } + + #[test] + fn valid_expression() { + let input = Parser::new_extra("(3)", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_operand(input).finish().unwrap(); + + matches!(parsed, Operand::Expression(expr)); + } +} + +#[cfg(test)] +mod parse_expression { + use super::*; + + #[test] + fn valid_unary() { + let input = Parser::new_extra("3", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_expression(input).finish().unwrap(); + + matches!(parsed, Expression::UnaryExpr(_)); + } + + #[test] + fn valid_binary() { + let input = Parser::new_extra("3 + 4", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_expression(input).finish().unwrap(); + + matches!(parsed, Expression::BinopExpr(_, _, _)); + } +} + +#[cfg(test)] +mod parse_fn_decl { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("toto a b = a + b", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_fn(input).finish().unwrap(); + + let expected = FunctionDecl { + name: Identifier { + name: String::from("toto"), + node_id: 0, + }, + arguments: vec![ + Identifier { + name: String::from("a"), + node_id: 0, + }, + Identifier { + name: String::from("b"), + node_id: 0, + }, + ], + body: Body { + stmts: vec![Statement::Expression(Box::new(Expression::BinopExpr( + UnaryExpr::PrimaryExpr(PrimaryExpr { + op: Operand::Identifier(IdentifierPath { + path: vec![Identifier { + name: String::from("a"), + node_id: 0, + }], + }), + node_id: 0, + secondaries: None, + }), + Operator(Identifier { + name: String::from("+"), + node_id: 0, + }), + Box::new(Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { + op: Operand::Identifier(IdentifierPath { + path: vec![Identifier { + name: String::from("b"), + node_id: 0, + }], + }), + node_id: 0, + secondaries: None, + }))), + )))], + }, + signature: FuncType { + ret: Box::new(Type::forall("c")), + arguments: vec![Type::forall("a"), Type::forall("b")], + }, + }; + + assert_eq!(parsed.name, expected.name); + assert_eq!(parsed.arguments, expected.arguments); + // assert_eq!(parsed.body, expected.body); + assert_eq!(parsed.signature, expected.signature); + } +} diff --git a/src/lib/tests.rs b/src/lib/tests.rs index a49d22e7..1c2c9833 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -14,28 +14,12 @@ fn run(path: &str, input: &str, expected_ret: &str, expected_output: &str) { assert_eq!(expected_output, stdout); } #[test] -fn testcases_trait_late_resolution_main() { - run("testcases/trait/late_resolution/main.rk", include_str!("testcases/trait/late_resolution/main.rk"), include_str!("testcases/trait/late_resolution/main.rk.out"), include_str!("testcases/trait/late_resolution/main.rk.stdout")); -} -#[test] -fn testcases_trait_multi_resolution_main() { - run("testcases/trait/multi_resolution/main.rk", include_str!("testcases/trait/multi_resolution/main.rk"), include_str!("testcases/trait/multi_resolution/main.rk.out"), include_str!("testcases/trait/multi_resolution/main.rk.stdout")); -} -#[test] -fn testcases_fails_basic_fn_bad_arg_nb2_main() { - run("testcases/fails/basic/fn_bad_arg_nb2/main.rk", include_str!("testcases/fails/basic/fn_bad_arg_nb2/main.rk"), include_str!("testcases/fails/basic/fn_bad_arg_nb2/main.rk.out"), include_str!("testcases/fails/basic/fn_bad_arg_nb2/main.rk.stdout")); -} -#[test] -fn testcases_fails_basic_fn_bad_arg_nb_main() { - run("testcases/fails/basic/fn_bad_arg_nb/main.rk", include_str!("testcases/fails/basic/fn_bad_arg_nb/main.rk"), include_str!("testcases/fails/basic/fn_bad_arg_nb/main.rk.out"), include_str!("testcases/fails/basic/fn_bad_arg_nb/main.rk.stdout")); -} -#[test] -fn testcases_fails_basic_struct_bad_field_type_main() { - run("testcases/fails/basic/struct_bad_field_type/main.rk", include_str!("testcases/fails/basic/struct_bad_field_type/main.rk"), include_str!("testcases/fails/basic/struct_bad_field_type/main.rk.out"), include_str!("testcases/fails/basic/struct_bad_field_type/main.rk.stdout")); +fn testcases_mods_basic_mod_main() { + run("testcases/mods/basic_mod/main.rk", include_str!("testcases/mods/basic_mod/main.rk"), include_str!("testcases/mods/basic_mod/main.rk.out"), include_str!("testcases/mods/basic_mod/main.rk.stdout")); } #[test] -fn testcases_fails_basic_fn_bad_arg_main() { - run("testcases/fails/basic/fn_bad_arg/main.rk", include_str!("testcases/fails/basic/fn_bad_arg/main.rk"), include_str!("testcases/fails/basic/fn_bad_arg/main.rk.out"), include_str!("testcases/fails/basic/fn_bad_arg/main.rk.stdout")); +fn testcases_mods_func_arg_resolution_main() { + run("testcases/mods/func_arg_resolution/main.rk", include_str!("testcases/mods/func_arg_resolution/main.rk"), include_str!("testcases/mods/func_arg_resolution/main.rk.out"), include_str!("testcases/mods/func_arg_resolution/main.rk.stdout")); } #[test] fn testcases_mods_unused_impl_fn_main() { @@ -46,150 +30,166 @@ fn testcases_mods_unused_fn_main() { run("testcases/mods/unused_fn/main.rk", include_str!("testcases/mods/unused_fn/main.rk"), include_str!("testcases/mods/unused_fn/main.rk.out"), include_str!("testcases/mods/unused_fn/main.rk.stdout")); } #[test] -fn testcases_mods_nested_trait_resolution_main() { - run("testcases/mods/nested_trait_resolution/main.rk", include_str!("testcases/mods/nested_trait_resolution/main.rk"), include_str!("testcases/mods/nested_trait_resolution/main.rk.out"), include_str!("testcases/mods/nested_trait_resolution/main.rk.stdout")); -} -#[test] fn testcases_mods_full_fact_main() { run("testcases/mods/full_fact/main.rk", include_str!("testcases/mods/full_fact/main.rk"), include_str!("testcases/mods/full_fact/main.rk.out"), include_str!("testcases/mods/full_fact/main.rk.stdout")); } #[test] -fn testcases_mods_func_arg_resolution_main() { - run("testcases/mods/func_arg_resolution/main.rk", include_str!("testcases/mods/func_arg_resolution/main.rk"), include_str!("testcases/mods/func_arg_resolution/main.rk.out"), include_str!("testcases/mods/func_arg_resolution/main.rk.stdout")); +fn testcases_mods_nested_trait_resolution_main() { + run("testcases/mods/nested_trait_resolution/main.rk", include_str!("testcases/mods/nested_trait_resolution/main.rk"), include_str!("testcases/mods/nested_trait_resolution/main.rk.out"), include_str!("testcases/mods/nested_trait_resolution/main.rk.stdout")); } #[test] fn testcases_mods_struct_new_main() { run("testcases/mods/struct_new/main.rk", include_str!("testcases/mods/struct_new/main.rk"), include_str!("testcases/mods/struct_new/main.rk.out"), include_str!("testcases/mods/struct_new/main.rk.stdout")); } #[test] -fn testcases_mods_basic_mod_main() { - run("testcases/mods/basic_mod/main.rk", include_str!("testcases/mods/basic_mod/main.rk"), include_str!("testcases/mods/basic_mod/main.rk.out"), include_str!("testcases/mods/basic_mod/main.rk.stdout")); +fn testcases_fails_basic_fn_bad_arg_nb2_main() { + run("testcases/fails/basic/fn_bad_arg_nb2/main.rk", include_str!("testcases/fails/basic/fn_bad_arg_nb2/main.rk"), include_str!("testcases/fails/basic/fn_bad_arg_nb2/main.rk.out"), include_str!("testcases/fails/basic/fn_bad_arg_nb2/main.rk.stdout")); } #[test] -fn testcases_basic_bool_true_main() { - run("testcases/basic/bool_true/main.rk", include_str!("testcases/basic/bool_true/main.rk"), include_str!("testcases/basic/bool_true/main.rk.out"), include_str!("testcases/basic/bool_true/main.rk.stdout")); +fn testcases_fails_basic_struct_bad_field_type_main() { + run("testcases/fails/basic/struct_bad_field_type/main.rk", include_str!("testcases/fails/basic/struct_bad_field_type/main.rk"), include_str!("testcases/fails/basic/struct_bad_field_type/main.rk.out"), include_str!("testcases/fails/basic/struct_bad_field_type/main.rk.stdout")); } #[test] -fn testcases_basic_op_func_main() { - run("testcases/basic/op_func/main.rk", include_str!("testcases/basic/op_func/main.rk"), include_str!("testcases/basic/op_func/main.rk.out"), include_str!("testcases/basic/op_func/main.rk.stdout")); +fn testcases_fails_basic_fn_bad_arg_nb_main() { + run("testcases/fails/basic/fn_bad_arg_nb/main.rk", include_str!("testcases/fails/basic/fn_bad_arg_nb/main.rk"), include_str!("testcases/fails/basic/fn_bad_arg_nb/main.rk.out"), include_str!("testcases/fails/basic/fn_bad_arg_nb/main.rk.stdout")); } #[test] -fn testcases_basic_multiline_struct_const_main() { - run("testcases/basic/multiline_struct_const/main.rk", include_str!("testcases/basic/multiline_struct_const/main.rk"), include_str!("testcases/basic/multiline_struct_const/main.rk.out"), include_str!("testcases/basic/multiline_struct_const/main.rk.stdout")); +fn testcases_fails_basic_fn_bad_arg_main() { + run("testcases/fails/basic/fn_bad_arg/main.rk", include_str!("testcases/fails/basic/fn_bad_arg/main.rk"), include_str!("testcases/fails/basic/fn_bad_arg/main.rk.out"), include_str!("testcases/fails/basic/fn_bad_arg/main.rk.stdout")); } #[test] -fn testcases_basic_2_arg_fn_main() { - run("testcases/basic/2_arg_fn/main.rk", include_str!("testcases/basic/2_arg_fn/main.rk"), include_str!("testcases/basic/2_arg_fn/main.rk.out"), include_str!("testcases/basic/2_arg_fn/main.rk.stdout")); +fn testcases_basic_if_else_main() { + run("testcases/basic/if_else/main.rk", include_str!("testcases/basic/if_else/main.rk"), include_str!("testcases/basic/if_else/main.rk.out"), include_str!("testcases/basic/if_else/main.rk.stdout")); } #[test] -fn testcases_basic_monomorph_in_trait_main() { - run("testcases/basic/monomorph_in_trait/main.rk", include_str!("testcases/basic/monomorph_in_trait/main.rk"), include_str!("testcases/basic/monomorph_in_trait/main.rk.out"), include_str!("testcases/basic/monomorph_in_trait/main.rk.stdout")); +fn testcases_basic_1_arg_fn_main() { + run("testcases/basic/1_arg_fn/main.rk", include_str!("testcases/basic/1_arg_fn/main.rk"), include_str!("testcases/basic/1_arg_fn/main.rk.out"), include_str!("testcases/basic/1_arg_fn/main.rk.stdout")); } #[test] -fn testcases_basic_reassign_self_main() { - run("testcases/basic/reassign_self/main.rk", include_str!("testcases/basic/reassign_self/main.rk"), include_str!("testcases/basic/reassign_self/main.rk.out"), include_str!("testcases/basic/reassign_self/main.rk.stdout")); +fn testcases_basic_indice_assign_main() { + run("testcases/basic/indice_assign/main.rk", include_str!("testcases/basic/indice_assign/main.rk"), include_str!("testcases/basic/indice_assign/main.rk.out"), include_str!("testcases/basic/indice_assign/main.rk.stdout")); } #[test] -fn testcases_basic_trait_use_before_decl_main() { - run("testcases/basic/trait_use_before_decl/main.rk", include_str!("testcases/basic/trait_use_before_decl/main.rk"), include_str!("testcases/basic/trait_use_before_decl/main.rk.out"), include_str!("testcases/basic/trait_use_before_decl/main.rk.stdout")); +fn testcases_basic_extern_main() { + run("testcases/basic/extern/main.rk", include_str!("testcases/basic/extern/main.rk"), include_str!("testcases/basic/extern/main.rk.out"), include_str!("testcases/basic/extern/main.rk.stdout")); +} +#[test] +fn testcases_basic_monomorph_in_trait_main() { + run("testcases/basic/monomorph_in_trait/main.rk", include_str!("testcases/basic/monomorph_in_trait/main.rk"), include_str!("testcases/basic/monomorph_in_trait/main.rk.out"), include_str!("testcases/basic/monomorph_in_trait/main.rk.stdout")); +} +#[test] +fn testcases_basic_multiline_struct_const_main() { + run("testcases/basic/multiline_struct_const/main.rk", include_str!("testcases/basic/multiline_struct_const/main.rk"), include_str!("testcases/basic/multiline_struct_const/main.rk.out"), include_str!("testcases/basic/multiline_struct_const/main.rk.stdout")); } #[test] fn testcases_basic_nested_struct_dect_multiline_main() { run("testcases/basic/nested_struct_dect_multiline/main.rk", include_str!("testcases/basic/nested_struct_dect_multiline/main.rk"), include_str!("testcases/basic/nested_struct_dect_multiline/main.rk.out"), include_str!("testcases/basic/nested_struct_dect_multiline/main.rk.stdout")); } #[test] -fn testcases_basic_reassign_return_main() { - run("testcases/basic/reassign_return/main.rk", include_str!("testcases/basic/reassign_return/main.rk"), include_str!("testcases/basic/reassign_return/main.rk.out"), include_str!("testcases/basic/reassign_return/main.rk.stdout")); +fn testcases_basic_let_main() { + run("testcases/basic/let/main.rk", include_str!("testcases/basic/let/main.rk"), include_str!("testcases/basic/let/main.rk.out"), include_str!("testcases/basic/let/main.rk.stdout")); } #[test] -fn testcases_basic_array_main() { - run("testcases/basic/array/main.rk", include_str!("testcases/basic/array/main.rk"), include_str!("testcases/basic/array/main.rk.out"), include_str!("testcases/basic/array/main.rk.stdout")); +fn testcases_basic_struct_array_field_main() { + run("testcases/basic/struct_array_field/main.rk", include_str!("testcases/basic/struct_array_field/main.rk"), include_str!("testcases/basic/struct_array_field/main.rk.out"), include_str!("testcases/basic/struct_array_field/main.rk.stdout")); } #[test] -fn testcases_basic_nested_struct_main() { - run("testcases/basic/nested_struct/main.rk", include_str!("testcases/basic/nested_struct/main.rk"), include_str!("testcases/basic/nested_struct/main.rk.out"), include_str!("testcases/basic/nested_struct/main.rk.stdout")); +fn testcases_basic_trait_use_before_decl_main() { + run("testcases/basic/trait_use_before_decl/main.rk", include_str!("testcases/basic/trait_use_before_decl/main.rk"), include_str!("testcases/basic/trait_use_before_decl/main.rk.out"), include_str!("testcases/basic/trait_use_before_decl/main.rk.stdout")); } #[test] -fn testcases_basic_simple_struct_main() { - run("testcases/basic/simple_struct/main.rk", include_str!("testcases/basic/simple_struct/main.rk"), include_str!("testcases/basic/simple_struct/main.rk.out"), include_str!("testcases/basic/simple_struct/main.rk.stdout")); +fn testcases_basic_while_main() { + run("testcases/basic/while/main.rk", include_str!("testcases/basic/while/main.rk"), include_str!("testcases/basic/while/main.rk.out"), include_str!("testcases/basic/while/main.rk.stdout")); } #[test] -fn testcases_basic_reassign_main() { - run("testcases/basic/reassign/main.rk", include_str!("testcases/basic/reassign/main.rk"), include_str!("testcases/basic/reassign/main.rk.out"), include_str!("testcases/basic/reassign/main.rk.stdout")); +fn testcases_basic_simple_struct_main() { + run("testcases/basic/simple_struct/main.rk", include_str!("testcases/basic/simple_struct/main.rk"), include_str!("testcases/basic/simple_struct/main.rk.out"), include_str!("testcases/basic/simple_struct/main.rk.stdout")); } #[test] -fn testcases_basic_indice_assign_main() { - run("testcases/basic/indice_assign/main.rk", include_str!("testcases/basic/indice_assign/main.rk"), include_str!("testcases/basic/indice_assign/main.rk.out"), include_str!("testcases/basic/indice_assign/main.rk.stdout")); +fn testcases_basic_bool_false_main() { + run("testcases/basic/bool_false/main.rk", include_str!("testcases/basic/bool_false/main.rk"), include_str!("testcases/basic/bool_false/main.rk.out"), include_str!("testcases/basic/bool_false/main.rk.stdout")); } #[test] -fn testcases_basic_dot_assign_main() { - run("testcases/basic/dot_assign/main.rk", include_str!("testcases/basic/dot_assign/main.rk"), include_str!("testcases/basic/dot_assign/main.rk.out"), include_str!("testcases/basic/dot_assign/main.rk.stdout")); +fn testcases_basic_nested_array_main() { + run("testcases/basic/nested_array/main.rk", include_str!("testcases/basic/nested_array/main.rk"), include_str!("testcases/basic/nested_array/main.rk.out"), include_str!("testcases/basic/nested_array/main.rk.stdout")); } #[test] -fn testcases_basic_extern_main() { - run("testcases/basic/extern/main.rk", include_str!("testcases/basic/extern/main.rk"), include_str!("testcases/basic/extern/main.rk.out"), include_str!("testcases/basic/extern/main.rk.stdout")); +fn testcases_basic_reassign_return_main() { + run("testcases/basic/reassign_return/main.rk", include_str!("testcases/basic/reassign_return/main.rk"), include_str!("testcases/basic/reassign_return/main.rk.out"), include_str!("testcases/basic/reassign_return/main.rk.stdout")); } #[test] -fn testcases_basic_1_arg_fn_main() { - run("testcases/basic/1_arg_fn/main.rk", include_str!("testcases/basic/1_arg_fn/main.rk"), include_str!("testcases/basic/1_arg_fn/main.rk.out"), include_str!("testcases/basic/1_arg_fn/main.rk.stdout")); +fn testcases_basic_reassign_main() { + run("testcases/basic/reassign/main.rk", include_str!("testcases/basic/reassign/main.rk"), include_str!("testcases/basic/reassign/main.rk.out"), include_str!("testcases/basic/reassign/main.rk.stdout")); } #[test] fn testcases_basic_monomorph_main() { run("testcases/basic/monomorph/main.rk", include_str!("testcases/basic/monomorph/main.rk"), include_str!("testcases/basic/monomorph/main.rk.out"), include_str!("testcases/basic/monomorph/main.rk.stdout")); } #[test] -fn testcases_basic_bool_false_main() { - run("testcases/basic/bool_false/main.rk", include_str!("testcases/basic/bool_false/main.rk"), include_str!("testcases/basic/bool_false/main.rk.out"), include_str!("testcases/basic/bool_false/main.rk.stdout")); -} -#[test] -fn testcases_basic_struct_array_field_main() { - run("testcases/basic/struct_array_field/main.rk", include_str!("testcases/basic/struct_array_field/main.rk"), include_str!("testcases/basic/struct_array_field/main.rk.out"), include_str!("testcases/basic/struct_array_field/main.rk.stdout")); +fn testcases_basic_op_func_main() { + run("testcases/basic/op_func/main.rk", include_str!("testcases/basic/op_func/main.rk"), include_str!("testcases/basic/op_func/main.rk.out"), include_str!("testcases/basic/op_func/main.rk.stdout")); } #[test] -fn testcases_basic_main_main() { - run("testcases/basic/main/main.rk", include_str!("testcases/basic/main/main.rk"), include_str!("testcases/basic/main/main.rk.out"), include_str!("testcases/basic/main/main.rk.stdout")); +fn testcases_basic_struct_index_main() { + run("testcases/basic/struct_index/main.rk", include_str!("testcases/basic/struct_index/main.rk"), include_str!("testcases/basic/struct_index/main.rk.out"), include_str!("testcases/basic/struct_index/main.rk.stdout")); } #[test] -fn testcases_basic_while_main() { - run("testcases/basic/while/main.rk", include_str!("testcases/basic/while/main.rk"), include_str!("testcases/basic/while/main.rk.out"), include_str!("testcases/basic/while/main.rk.stdout")); +fn testcases_basic_0_arg_fn_main() { + run("testcases/basic/0_arg_fn/main.rk", include_str!("testcases/basic/0_arg_fn/main.rk"), include_str!("testcases/basic/0_arg_fn/main.rk.out"), include_str!("testcases/basic/0_arg_fn/main.rk.stdout")); } #[test] fn testcases_basic_fn_arg_main() { run("testcases/basic/fn_arg/main.rk", include_str!("testcases/basic/fn_arg/main.rk"), include_str!("testcases/basic/fn_arg/main.rk.out"), include_str!("testcases/basic/fn_arg/main.rk.stdout")); } #[test] -fn testcases_basic_recur_main() { - run("testcases/basic/recur/main.rk", include_str!("testcases/basic/recur/main.rk"), include_str!("testcases/basic/recur/main.rk.out"), include_str!("testcases/basic/recur/main.rk.stdout")); +fn testcases_basic_fn_arg_array_main() { + run("testcases/basic/fn_arg_array/main.rk", include_str!("testcases/basic/fn_arg_array/main.rk"), include_str!("testcases/basic/fn_arg_array/main.rk.out"), include_str!("testcases/basic/fn_arg_array/main.rk.stdout")); } #[test] -fn testcases_basic_struct_index_main() { - run("testcases/basic/struct_index/main.rk", include_str!("testcases/basic/struct_index/main.rk"), include_str!("testcases/basic/struct_index/main.rk.out"), include_str!("testcases/basic/struct_index/main.rk.stdout")); +fn testcases_basic_trait_monomorph_main() { + run("testcases/basic/trait_monomorph/main.rk", include_str!("testcases/basic/trait_monomorph/main.rk"), include_str!("testcases/basic/trait_monomorph/main.rk.out"), include_str!("testcases/basic/trait_monomorph/main.rk.stdout")); } #[test] -fn testcases_basic_nested_array_main() { - run("testcases/basic/nested_array/main.rk", include_str!("testcases/basic/nested_array/main.rk"), include_str!("testcases/basic/nested_array/main.rk.out"), include_str!("testcases/basic/nested_array/main.rk.stdout")); +fn testcases_basic_nested_struct_main() { + run("testcases/basic/nested_struct/main.rk", include_str!("testcases/basic/nested_struct/main.rk"), include_str!("testcases/basic/nested_struct/main.rk.out"), include_str!("testcases/basic/nested_struct/main.rk.stdout")); } #[test] -fn testcases_basic_if_else_main() { - run("testcases/basic/if_else/main.rk", include_str!("testcases/basic/if_else/main.rk"), include_str!("testcases/basic/if_else/main.rk.out"), include_str!("testcases/basic/if_else/main.rk.stdout")); +fn testcases_basic_reassign_self_main() { + run("testcases/basic/reassign_self/main.rk", include_str!("testcases/basic/reassign_self/main.rk"), include_str!("testcases/basic/reassign_self/main.rk.out"), include_str!("testcases/basic/reassign_self/main.rk.stdout")); } #[test] fn testcases_basic_operator_precedence_main() { run("testcases/basic/operator_precedence/main.rk", include_str!("testcases/basic/operator_precedence/main.rk"), include_str!("testcases/basic/operator_precedence/main.rk.out"), include_str!("testcases/basic/operator_precedence/main.rk.stdout")); } #[test] -fn testcases_basic_let_main() { - run("testcases/basic/let/main.rk", include_str!("testcases/basic/let/main.rk"), include_str!("testcases/basic/let/main.rk.out"), include_str!("testcases/basic/let/main.rk.stdout")); +fn testcases_basic_main_main() { + run("testcases/basic/main/main.rk", include_str!("testcases/basic/main/main.rk"), include_str!("testcases/basic/main/main.rk.out"), include_str!("testcases/basic/main/main.rk.stdout")); } #[test] -fn testcases_basic_fn_arg_array_main() { - run("testcases/basic/fn_arg_array/main.rk", include_str!("testcases/basic/fn_arg_array/main.rk"), include_str!("testcases/basic/fn_arg_array/main.rk.out"), include_str!("testcases/basic/fn_arg_array/main.rk.stdout")); +fn testcases_basic_bool_true_main() { + run("testcases/basic/bool_true/main.rk", include_str!("testcases/basic/bool_true/main.rk"), include_str!("testcases/basic/bool_true/main.rk.out"), include_str!("testcases/basic/bool_true/main.rk.stdout")); } #[test] -fn testcases_basic_0_arg_fn_main() { - run("testcases/basic/0_arg_fn/main.rk", include_str!("testcases/basic/0_arg_fn/main.rk"), include_str!("testcases/basic/0_arg_fn/main.rk.out"), include_str!("testcases/basic/0_arg_fn/main.rk.stdout")); +fn testcases_basic_array_main() { + run("testcases/basic/array/main.rk", include_str!("testcases/basic/array/main.rk"), include_str!("testcases/basic/array/main.rk.out"), include_str!("testcases/basic/array/main.rk.stdout")); } #[test] -fn testcases_basic_trait_monomorph_main() { - run("testcases/basic/trait_monomorph/main.rk", include_str!("testcases/basic/trait_monomorph/main.rk"), include_str!("testcases/basic/trait_monomorph/main.rk.out"), include_str!("testcases/basic/trait_monomorph/main.rk.stdout")); +fn testcases_basic_2_arg_fn_main() { + run("testcases/basic/2_arg_fn/main.rk", include_str!("testcases/basic/2_arg_fn/main.rk"), include_str!("testcases/basic/2_arg_fn/main.rk.out"), include_str!("testcases/basic/2_arg_fn/main.rk.stdout")); +} +#[test] +fn testcases_basic_dot_assign_main() { + run("testcases/basic/dot_assign/main.rk", include_str!("testcases/basic/dot_assign/main.rk"), include_str!("testcases/basic/dot_assign/main.rk.out"), include_str!("testcases/basic/dot_assign/main.rk.stdout")); +} +#[test] +fn testcases_basic_recur_main() { + run("testcases/basic/recur/main.rk", include_str!("testcases/basic/recur/main.rk"), include_str!("testcases/basic/recur/main.rk.out"), include_str!("testcases/basic/recur/main.rk.stdout")); +} +#[test] +fn testcases_trait_multi_resolution_main() { + run("testcases/trait/multi_resolution/main.rk", include_str!("testcases/trait/multi_resolution/main.rk"), include_str!("testcases/trait/multi_resolution/main.rk.out"), include_str!("testcases/trait/multi_resolution/main.rk.stdout")); +} +#[test] +fn testcases_trait_late_resolution_main() { + run("testcases/trait/late_resolution/main.rk", include_str!("testcases/trait/late_resolution/main.rk"), include_str!("testcases/trait/late_resolution/main.rk.out"), include_str!("testcases/trait/late_resolution/main.rk.stdout")); } From 17166130d7789911ec47b6d2d91e5dfd12759567 Mon Sep 17 00:00:00 2001 From: Champii Date: Sun, 16 Jan 2022 14:08:25 +0100 Subject: [PATCH 29/74] More tests for new parser --- src/lib/parser2/tests.rs | 46 ++++++++++++++++++++++++++++++++++++++++ 1 file changed, 46 insertions(+) diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index c68e3027..b6b3c771 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -397,3 +397,49 @@ mod parse_fn_decl { assert_eq!(parsed.signature, expected.signature); } } + +#[cfg(test)] +mod parse_prototype { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("toto :: Int64 -> Int64", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_prototype(input).finish().unwrap(); + + let expected = Prototype { + name: Identifier { + name: String::from("toto"), + node_id: 0, + }, + signature: FuncType { + ret: Box::new(Type::forall("Int64")), + arguments: vec![Type::forall("Int64")], + }, + node_id: 0, + }; + } +} + +#[cfg(test)] +mod parse_use { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("use foo", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_use(input).finish().unwrap(); + + assert_eq!( + parsed.path, + IdentifierPath { + path: vec![Identifier { + name: String::from("foo"), + node_id: 0, + }], + } + ); + } +} From 1e8c5a9f8421aca786afc698ae5fe649a0aa7a21 Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 17 Jan 2022 14:54:40 +0100 Subject: [PATCH 30/74] Add if/else if/else constructs --- src/lib/ast/tree2.rs | 20 ++++++ src/lib/parser2/mod.rs | 95 +++++++++++++++++++++++--- src/lib/parser2/tests.rs | 143 +++++++++++++++++++++++++++++++++++---- 3 files changed, 237 insertions(+), 21 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index fc166331..9928dfbf 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -303,6 +303,10 @@ impl Statement { pub fn new_expression(expr: Expression) -> Self { Self::Expression(Box::new(expr)) } + + pub fn new_if(if_: If) -> Self { + Self::If(Box::new(if_)) + } } #[derive(Debug, Clone)] @@ -373,6 +377,22 @@ pub struct If { pub else_: Option>, } +impl If { + pub fn new( + node_id: NodeId, + predicat: Expression, + body: Body, + else_: Option>, + ) -> Self { + Self { + node_id, + predicat, + body, + else_, + } + } +} + #[derive(Debug, Clone)] pub enum Else { If(If), diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 2975ec4a..11da3ce2 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -1,17 +1,17 @@ use std::collections::HashMap; + use std::path::PathBuf; use nom::branch::alt; use nom::bytes::complete::{tag, take_while}; use nom::character::complete::{ - alphanumeric0, alphanumeric1, char, line_ending, multispace0, one_of, satisfy, space0, space1, + alphanumeric0, alphanumeric1, char, line_ending, one_of, satisfy, space0, space1, }; -use nom::character::is_alphanumeric; -use nom::combinator::{map, map_res, opt, recognize}; +use nom::combinator::{map, opt, recognize}; use nom::error::{Error, ErrorKind}; -use nom::multi::{many0, many1, separated_list0, separated_list1}; -use nom::sequence::{delimited, preceded, separated_pair, terminated, tuple}; -use nom::{Err, IResult}; +use nom::multi::{many0, many1, separated_list1}; +use nom::sequence::{delimited, preceded, terminated, tuple}; +use nom::{error::ParseError, Err, IResult}; use crate::ast::identity2::Identity; use crate::ast::tree2::*; @@ -30,6 +30,7 @@ pub struct ParserCtx { cur_file_path: PathBuf, identities: Vec, operators_list: HashMap, + block_indent: usize, } impl ParserCtx { @@ -38,14 +39,17 @@ impl ParserCtx { cur_file_path: file_path, identities: Vec::new(), operators_list: HashMap::new(), + block_indent: 0, } } + #[cfg(test)] pub fn new_with_operators(file_path: PathBuf, operators: HashMap) -> Self { Self { cur_file_path: file_path, identities: Vec::new(), operators_list: operators, + block_indent: 0, } } @@ -159,12 +163,85 @@ pub fn parse_fn(input: Parser) -> IResult { )(input) } -pub fn parse_body(input: Parser) -> IResult { - map(many1(parse_statement), Body::new)(input) +pub fn parse_block_indent(input: Parser) -> IResult { + map(space0, |indents: Parser| indents.fragment().len())(input) +} + +pub fn parse_body(mut input: Parser) -> IResult { + input.extra.block_indent += 2; + + let output = map( + tuple(( + line_ending, + separated_list1(many1(line_ending), parse_statement), + )), + |(_, stmts)| Body::new(stmts), + )(input); + + output.map(|(mut input, body)| { + input.extra.block_indent -= 2; + + (input, body) + }) } pub fn parse_statement(input: Parser) -> IResult { - map(parse_expression, Statement::new_expression)(input) + let (input, indent) = parse_block_indent(input)?; + + if indent == input.extra.block_indent { + alt(( + map(parse_if, Statement::new_if), + map(parse_expression, Statement::new_expression), + ))(input) + } else { + Err(nom::Err::Error(ParseError::from_error_kind( + input, + ErrorKind::Tag, + ))) + } +} + +pub fn parse_if(input: Parser) -> IResult { + map( + tuple(( + terminated(tag("if"), space1), + terminated(parse_expression, space0), + parse_body, + opt(parse_else), + )), + |(_, cond, body, else_)| If::new(0, cond, body, else_.map(Box::new)), + )(input) +} + +pub fn parse_else(input: Parser) -> IResult { + let (input, indent) = parse_block_indent(input)?; + + if indent == input.extra.block_indent { + println!("ELSE {:#?}", indent); + alt(( + map( + tuple(( + line_ending, + terminated(tag("else"), space1), + terminated(parse_if, space0), + )), + |(_, _, if_)| Else::If(if_), + ), + map( + tuple(( + line_ending, + terminated(tag("else"), space0), + terminated(parse_body, space0), + )), + |(_, _, body)| Else::Body(body), + ), + ))(input) + } else { + Err(nom::Err::Error(ParseError::from_error_kind( + input, + ErrorKind::Tag, + ))) + } } pub fn parse_expression(input: Parser) -> IResult { diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index b6b3c771..2e1e79a0 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -191,7 +191,7 @@ mod parse_infix_op { let (rest, parsed) = parse_infix(input).finish().unwrap(); - matches!(parsed, TopLevel::Infix(op, 5)); + assert!(matches!(parsed, TopLevel::Infix(op, 5))); let operators = HashMap::from([("+".to_string(), 5)]); assert_eq!(rest.extra.operators_list, operators); @@ -281,13 +281,13 @@ mod parse_operand { let (_rest, parsed) = parse_operand(input).finish().unwrap(); - matches!( + assert!(matches!( parsed, Operand::Literal(Literal { kind: LiteralKind::Number(42), node_id: 0, }) - ); + )); } #[test] @@ -296,7 +296,10 @@ mod parse_operand { let (_rest, parsed) = parse_operand(input).finish().unwrap(); - matches!(parsed, Operand::Identifier(IdentifierPath { path })); + assert!(matches!( + parsed, + Operand::Identifier(IdentifierPath { path }) + )); } #[test] @@ -305,7 +308,7 @@ mod parse_operand { let (_rest, parsed) = parse_operand(input).finish().unwrap(); - matches!(parsed, Operand::Expression(expr)); + assert!(matches!(parsed, Operand::Expression(expr))); } } @@ -319,16 +322,21 @@ mod parse_expression { let (_rest, parsed) = parse_expression(input).finish().unwrap(); - matches!(parsed, Expression::UnaryExpr(_)); + assert!(matches!(parsed, Expression::UnaryExpr(_))); } #[test] fn valid_binary() { - let input = Parser::new_extra("3 + 4", ParserCtx::new(PathBuf::new())); + let operators = HashMap::from([("+".to_string(), 5)]); + + let input = Parser::new_extra( + "3 + 4", + ParserCtx::new_with_operators(PathBuf::new(), operators), + ); let (_rest, parsed) = parse_expression(input).finish().unwrap(); - matches!(parsed, Expression::BinopExpr(_, _, _)); + assert!(matches!(parsed, Expression::BinopExpr(_, _, _))); } } @@ -337,8 +345,46 @@ mod parse_fn_decl { use super::*; #[test] - fn valid() { - let input = Parser::new_extra("toto a b = a + b", ParserCtx::new(PathBuf::new())); + fn valid_no_args() { + let input = Parser::new_extra("toto =\n 2\n", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_fn(input).finish().unwrap(); + + let expected = FunctionDecl { + name: Identifier { + name: String::from("toto"), + node_id: 0, + }, + body: Body::new(vec![Statement::Expression(Box::new( + Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { + op: Operand::Literal(Literal { + kind: LiteralKind::Number(2), + node_id: 0, + }), + node_id: 0, + secondaries: None, + })), + ))]), + arguments: vec![], + signature: FuncType { + ret: Box::new(Type::forall("a")), + arguments: vec![], + }, + }; + + assert_eq!(parsed.name, expected.name); + assert_eq!(parsed.arguments, expected.arguments); + assert_eq!(parsed.signature, expected.signature); + } + + #[test] + fn valid_2_args() { + let operators = HashMap::from([("+".to_string(), 5)]); + + let input = Parser::new_extra( + "toto a b =\n a + b", + ParserCtx::new_with_operators(PathBuf::new(), operators), + ); let (_rest, parsed) = parse_fn(input).finish().unwrap(); @@ -396,6 +442,22 @@ mod parse_fn_decl { // assert_eq!(parsed.body, expected.body); assert_eq!(parsed.signature, expected.signature); } + + #[test] + fn valid_multiline() { + let operators = HashMap::from([("+".to_string(), 5)]); + + let input = Parser::new_extra( + "toto a b =\n a + b\n a + b", + ParserCtx::new_with_operators(PathBuf::new(), operators), + ); + + let (rest, parsed) = parse_fn(input).finish().unwrap(); + + println!("{:?}", rest); + + assert!(rest.fragment().is_empty()); + } } #[cfg(test)] @@ -414,11 +476,13 @@ mod parse_prototype { node_id: 0, }, signature: FuncType { - ret: Box::new(Type::forall("Int64")), - arguments: vec![Type::forall("Int64")], + ret: Box::new(Type::int64()), + arguments: vec![Type::int64()], }, node_id: 0, }; + + assert_eq!(parsed.name, expected.name); } } @@ -443,3 +507,58 @@ mod parse_use { ); } } + +#[cfg(test)] +mod parse_if { + use super::*; + + #[test] + fn valid_if() { + let input = Parser::new_extra("if a\n b", ParserCtx::new(PathBuf::new())); + + let (rest, parsed) = parse_if(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_if_else() { + let input = Parser::new_extra("if a\n b\nelse\n c", ParserCtx::new(PathBuf::new())); + + let (rest, parsed) = parse_if(input).finish().unwrap(); + + println!("{:#?}", rest); + println!("{:#?}", parsed); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_if_else_if() { + let input = Parser::new_extra( + "if a\n b\nelse if false\n c", + ParserCtx::new(PathBuf::new()), + ); + + let (rest, parsed) = parse_if(input).finish().unwrap(); + + println!("{:#?}", rest); + println!("{:#?}", parsed); + + assert!(rest.fragment().is_empty()); + } + #[test] + fn valid_if_else_if_else() { + let input = Parser::new_extra( + "if a\n b\nelse if true\n c\nelse\n d", + ParserCtx::new(PathBuf::new()), + ); + + let (rest, parsed) = parse_if(input).finish().unwrap(); + + println!("{:#?}", rest); + println!("{:#?}", parsed); + + assert!(rest.fragment().is_empty()); + } +} From 1a6c3ffe56222110be42c87fd52672a1afcbff6e Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 17 Jan 2022 14:59:19 +0100 Subject: [PATCH 31/74] Cleanup --- src/lib/parser2/tests.rs | 20 +++++--------------- 1 file changed, 5 insertions(+), 15 deletions(-) diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index 2e1e79a0..9015490d 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -150,6 +150,7 @@ mod parse_signature { assert_eq!(parsed.ret, Box::new(Type::int64())); } + #[test] fn valid_2_arg() { let input = Parser::new_extra("Int64 -> Int64", ParserCtx::new(PathBuf::new())); @@ -191,7 +192,7 @@ mod parse_infix_op { let (rest, parsed) = parse_infix(input).finish().unwrap(); - assert!(matches!(parsed, TopLevel::Infix(op, 5))); + assert!(matches!(parsed, TopLevel::Infix(_op, 5))); let operators = HashMap::from([("+".to_string(), 5)]); assert_eq!(rest.extra.operators_list, operators); @@ -452,9 +453,7 @@ mod parse_fn_decl { ParserCtx::new_with_operators(PathBuf::new(), operators), ); - let (rest, parsed) = parse_fn(input).finish().unwrap(); - - println!("{:?}", rest); + let (rest, _parsed) = parse_fn(input).finish().unwrap(); assert!(rest.fragment().is_empty()); } @@ -516,7 +515,7 @@ mod parse_if { fn valid_if() { let input = Parser::new_extra("if a\n b", ParserCtx::new(PathBuf::new())); - let (rest, parsed) = parse_if(input).finish().unwrap(); + let (rest, _parsed) = parse_if(input).finish().unwrap(); assert!(rest.fragment().is_empty()); } @@ -525,10 +524,7 @@ mod parse_if { fn valid_if_else() { let input = Parser::new_extra("if a\n b\nelse\n c", ParserCtx::new(PathBuf::new())); - let (rest, parsed) = parse_if(input).finish().unwrap(); - - println!("{:#?}", rest); - println!("{:#?}", parsed); + let (rest, _parsed) = parse_if(input).finish().unwrap(); assert!(rest.fragment().is_empty()); } @@ -542,9 +538,6 @@ mod parse_if { let (rest, parsed) = parse_if(input).finish().unwrap(); - println!("{:#?}", rest); - println!("{:#?}", parsed); - assert!(rest.fragment().is_empty()); } #[test] @@ -556,9 +549,6 @@ mod parse_if { let (rest, parsed) = parse_if(input).finish().unwrap(); - println!("{:#?}", rest); - println!("{:#?}", parsed); - assert!(rest.fragment().is_empty()); } } From 1b200d50fd2a7c02ee7e759ff79895634875480e Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 17 Jan 2022 15:00:38 +0100 Subject: [PATCH 32/74] Cleanup --- src/lib/diagnostics/diagnostic.rs | 2 +- src/lib/parser/span2.rs | 2 +- src/lib/parser2/tests.rs | 10 +++++----- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index f94317a9..58be1e8e 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -1,6 +1,6 @@ use std::fmt::Display; -use crate::parser2::Parser; + use crate::{diagnostics::DiagnosticType, parser::Span}; use crate::{ hir::HirId, diff --git a/src/lib/parser/span2.rs b/src/lib/parser/span2.rs index f1a0e9e1..8a55d216 100644 --- a/src/lib/parser/span2.rs +++ b/src/lib/parser/span2.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use nom_locate::LocatedSpan; + use crate::parser2::Parser; diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index 9015490d..dad03cff 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -212,7 +212,7 @@ mod parse_operator { ParserCtx::new_with_operators(PathBuf::new(), operators), ); - let (rest, parsed) = parse_operator(input).finish().unwrap(); + let (_rest, parsed) = parse_operator(input).finish().unwrap(); assert_eq!( parsed, @@ -299,7 +299,7 @@ mod parse_operand { assert!(matches!( parsed, - Operand::Identifier(IdentifierPath { path }) + Operand::Identifier(IdentifierPath { path: _ }) )); } @@ -309,7 +309,7 @@ mod parse_operand { let (_rest, parsed) = parse_operand(input).finish().unwrap(); - assert!(matches!(parsed, Operand::Expression(expr))); + assert!(matches!(parsed, Operand::Expression(_expr))); } } @@ -536,7 +536,7 @@ mod parse_if { ParserCtx::new(PathBuf::new()), ); - let (rest, parsed) = parse_if(input).finish().unwrap(); + let (rest, _parsed) = parse_if(input).finish().unwrap(); assert!(rest.fragment().is_empty()); } @@ -547,7 +547,7 @@ mod parse_if { ParserCtx::new(PathBuf::new()), ); - let (rest, parsed) = parse_if(input).finish().unwrap(); + let (rest, _parsed) = parse_if(input).finish().unwrap(); assert!(rest.fragment().is_empty()); } From d41de67dcdd2646d17b496414c5a4ee0e2f6fecd Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 17 Jan 2022 15:22:23 +0100 Subject: [PATCH 33/74] Fix else blocks --- src/lib/parser2/mod.rs | 13 ++++++------- 1 file changed, 6 insertions(+), 7 deletions(-) diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 11da3ce2..4bfb3ddc 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -207,9 +207,9 @@ pub fn parse_if(input: Parser) -> IResult { terminated(tag("if"), space1), terminated(parse_expression, space0), parse_body, - opt(parse_else), + opt(tuple((line_ending, parse_else))), )), - |(_, cond, body, else_)| If::new(0, cond, body, else_.map(Box::new)), + |(_, cond, body, else_)| If::new(0, cond, body, else_.map(|(_, else_)| Box::new(else_))), )(input) } @@ -217,23 +217,22 @@ pub fn parse_else(input: Parser) -> IResult { let (input, indent) = parse_block_indent(input)?; if indent == input.extra.block_indent { - println!("ELSE {:#?}", indent); alt(( map( tuple(( - line_ending, + // line_ending, terminated(tag("else"), space1), terminated(parse_if, space0), )), - |(_, _, if_)| Else::If(if_), + |(_, if_)| Else::If(if_), ), map( tuple(( - line_ending, + // line_ending, terminated(tag("else"), space0), terminated(parse_body, space0), )), - |(_, _, body)| Else::Body(body), + |(_, body)| Else::Body(body), ), ))(input) } else { From 2ea4d8fb5b6786adbf12b468c7dc684e26caa683 Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 17 Jan 2022 16:02:41 +0100 Subject: [PATCH 34/74] Add for in and while loops --- src/lib/ast/tree2.rs | 16 ++++++++++++++++ src/lib/parser2/mod.rs | 39 +++++++++++++++++++++++++++++++++++---- src/lib/parser2/tests.rs | 23 +++++++++++++++++++++++ 3 files changed, 74 insertions(+), 4 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index 9928dfbf..c85d1d35 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -307,6 +307,10 @@ impl Statement { pub fn new_if(if_: If) -> Self { Self::If(Box::new(if_)) } + + pub fn new_for(for_: For) -> Self { + Self::For(for_) + } } #[derive(Debug, Clone)] @@ -321,6 +325,12 @@ pub struct While { pub body: Body, } +impl While { + pub fn new(predicat: Expression, body: Body) -> Self { + Self { predicat, body } + } +} + #[derive(Debug, Clone)] pub struct ForIn { pub value: Identifier, @@ -328,6 +338,12 @@ pub struct ForIn { pub body: Body, } +impl ForIn { + pub fn new(value: Identifier, expr: Expression, body: Body) -> Self { + Self { value, expr, body } + } +} + #[derive(Debug, Clone)] pub enum AssignLeftSide { Identifier(Identifier), diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 4bfb3ddc..53bf7316 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -191,6 +191,7 @@ pub fn parse_statement(input: Parser) -> IResult { if indent == input.extra.block_indent { alt(( map(parse_if, Statement::new_if), + map(parse_for, Statement::new_for), map(parse_expression, Statement::new_expression), ))(input) } else { @@ -209,8 +210,12 @@ pub fn parse_if(input: Parser) -> IResult { parse_body, opt(tuple((line_ending, parse_else))), )), - |(_, cond, body, else_)| If::new(0, cond, body, else_.map(|(_, else_)| Box::new(else_))), - )(input) + |(if_, cond, body, else_)| { + let (_input, node_id) = new_identity(input.clone(), &if_); + + If::new(node_id, cond, body, else_.map(|(_, else_)| Box::new(else_))) + }, + )(input.clone()) } pub fn parse_else(input: Parser) -> IResult { @@ -220,7 +225,6 @@ pub fn parse_else(input: Parser) -> IResult { alt(( map( tuple(( - // line_ending, terminated(tag("else"), space1), terminated(parse_if, space0), )), @@ -228,7 +232,6 @@ pub fn parse_else(input: Parser) -> IResult { ), map( tuple(( - // line_ending, terminated(tag("else"), space0), terminated(parse_body, space0), )), @@ -243,6 +246,34 @@ pub fn parse_else(input: Parser) -> IResult { } } +pub fn parse_for(input: Parser) -> IResult { + alt((map(parse_for_in, For::In), map(parse_while, For::While)))(input) +} + +pub fn parse_for_in(input: Parser) -> IResult { + map( + tuple(( + terminated(tag("for"), space1), + terminated(parse_identifier, space0), + terminated(tag("in"), space0), + terminated(parse_expression, space0), + parse_body, + )), + |(_, var, _, expr, body)| ForIn::new(var, expr, body), + )(input) +} + +pub fn parse_while(input: Parser) -> IResult { + map( + tuple(( + terminated(tag("while"), space1), + terminated(parse_expression, space0), + parse_body, + )), + |(_, cond, body)| While::new(cond, body), + )(input) +} + pub fn parse_expression(input: Parser) -> IResult { alt(( map( diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index dad03cff..4df75e45 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -552,3 +552,26 @@ mod parse_if { assert!(rest.fragment().is_empty()); } } + +#[cfg(test)] +mod parse_for { + use super::*; + + #[test] + fn valid_for_in() { + let input = Parser::new_extra("for x in a\n b", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_for(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_while() { + let input = Parser::new_extra("while a\n b", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_for(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} From f8501ae649136d297bc081e94ba03801540df50c Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 18 Jan 2022 02:46:14 +0100 Subject: [PATCH 35/74] Add parsing for assign and dot/indice exprs --- src/lib/ast/tree2.rs | 72 ++++++++++++--- src/lib/parser2/mod.rs | 93 ++++++++++++++++++- src/lib/parser2/tests.rs | 187 +++++++++++++++++++++++++++++++++++++++ 3 files changed, 338 insertions(+), 14 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index c85d1d35..fb931625 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -346,7 +346,7 @@ impl ForIn { #[derive(Debug, Clone)] pub enum AssignLeftSide { - Identifier(Identifier), + Identifier(Expression), Indice(Expression), Dot(Expression), } @@ -354,14 +354,7 @@ pub enum AssignLeftSide { impl AssignLeftSide { pub fn as_expression(&self) -> Expression { match self { - AssignLeftSide::Identifier(i) => { - Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { - op: Operand::new_identifier(i.clone()), - node_id: i.node_id.clone(), - secondaries: None, - })) - } - + AssignLeftSide::Identifier(i) => i.clone(), AssignLeftSide::Indice(i) => i.clone(), AssignLeftSide::Dot(d) => d.clone(), } @@ -385,6 +378,16 @@ pub struct Assign { pub is_let: bool, } +impl Assign { + pub fn new(name: AssignLeftSide, value: Expression, is_let: bool) -> Self { + Self { + name, + value, + is_let, + } + } +} + #[derive(Debug, Clone)] pub struct If { pub node_id: NodeId, @@ -450,6 +453,14 @@ impl Expression { } } + #[allow(dead_code)] + pub fn is_dot(&self) -> bool { + match &self { + Expression::UnaryExpr(unary) => unary.is_dot(), + _ => false, + } + } + #[allow(dead_code)] pub fn new_unary(unary: UnaryExpr) -> Expression { Expression::UnaryExpr(unary) @@ -512,6 +523,13 @@ impl UnaryExpr { } } + pub fn is_dot(&self) -> bool { + match self { + UnaryExpr::UnaryExpr(_, unary) => unary.is_dot(), + UnaryExpr::PrimaryExpr(prim) => prim.is_dot(), + } + } + // pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> UnaryExpr { // UnaryExpr::PrimaryExpr(PrimaryExpr { // node_id: node_id::new_placeholder(), @@ -552,13 +570,33 @@ impl PrimaryExpr { } } - pub fn new(op: Operand) -> PrimaryExpr { + pub fn is_dot(&self) -> bool { + if let Some(secondaries) = &self.secondaries { + secondaries.iter().any(|secondary| secondary.is_dot()) + } else { + false + } + } + + pub fn new_empty(op: Operand) -> PrimaryExpr { PrimaryExpr { op, node_id: 0, secondaries: None, } } + + pub fn new(op: Operand, secondaries: Vec) -> PrimaryExpr { + PrimaryExpr { + op, + node_id: 0, + secondaries: if secondaries.len() == 0 { + None + } else { + Some(secondaries) + }, + } + } } // #[derive(Debug, Clone)] @@ -625,6 +663,14 @@ impl SecondaryExpr { pub fn is_indice(&self) -> bool { matches!(self, SecondaryExpr::Indice(_)) } + + pub fn is_dot(&self) -> bool { + matches!(self, SecondaryExpr::Dot(_)) + } + + pub fn is_arguments(&self) -> bool { + matches!(self, SecondaryExpr::Arguments(_)) + } } #[derive(Debug, Clone)] @@ -682,6 +728,12 @@ pub struct Argument { pub arg: UnaryExpr, } +impl Argument { + pub fn new(arg: UnaryExpr) -> Self { + Self { arg } + } +} + #[derive(Debug, Clone)] pub struct NativeOperator { pub kind: NativeOperatorKind, diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 53bf7316..9ed39864 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -9,7 +9,7 @@ use nom::character::complete::{ }; use nom::combinator::{map, opt, recognize}; use nom::error::{Error, ErrorKind}; -use nom::multi::{many0, many1, separated_list1}; +use nom::multi::{many0, many1, separated_list0, separated_list1}; use nom::sequence::{delimited, preceded, terminated, tuple}; use nom::{error::ParseError, Err, IResult}; @@ -274,6 +274,32 @@ pub fn parse_while(input: Parser) -> IResult { )(input) } +pub fn parse_assign(input: Parser) -> IResult { + map( + tuple(( + opt(terminated(tag("let"), space1)), + terminated(parse_assign_left_side, space0), + terminated(tag("="), space0), + terminated(parse_expression, space0), + )), + |(opt_let, var, _, expr)| Assign::new(var, expr, opt_let.is_some()), + )(input) +} + +pub fn parse_assign_left_side(input: Parser) -> IResult { + map(parse_expression, |expr| { + if expr.is_dot() { + AssignLeftSide::Dot(expr) + } else if expr.is_indice() { + AssignLeftSide::Indice(expr) + } else if expr.is_identifier() { + AssignLeftSide::Identifier(expr) + } else { + panic!("Invalid left side of assignment: {:?}", expr); + } + })(input) +} + pub fn parse_expression(input: Parser) -> IResult { alt(( map( @@ -293,7 +319,66 @@ pub fn parse_unary(input: Parser) -> IResult { } pub fn parse_primary(input: Parser) -> IResult { - map(parse_operand, PrimaryExpr::new)(input) + map( + tuple((parse_operand, many0(parse_secondary))), + |(op, secs)| PrimaryExpr::new(op, secs), + )(input) +} + +pub fn parse_secondary(input: Parser) -> IResult { + alt(( + map(parse_indice, SecondaryExpr::Indice), + map(parse_dot, SecondaryExpr::Dot), + map(parse_arguments, SecondaryExpr::Arguments), + ))(input) +} + +pub fn parse_arguments(input: Parser) -> IResult { + alt(( + map( + tuple(( + terminated(tag("("), space0), + separated_list0(tuple((space0, tag(","), space0)), parse_argument), + terminated(tag(")"), space0), + )), + |(_, args, _)| args, + ), + map( + tuple(( + space1, + separated_list1( + tuple((space0, terminated(tag(","), space0), space0)), + parse_argument, + ), + )), + |(_, args)| args, + ), + ))(input) +} + +pub fn parse_argument(input: Parser) -> IResult { + map(parse_unary, Argument::new)(input) +} + +pub fn parse_indice(input: Parser) -> IResult> { + map( + tuple(( + terminated(tag("["), space0), + terminated(parse_expression, space0), + terminated(tag("]"), space0), + )), + |(_, index, _)| Box::new(index), + )(input) +} + +pub fn parse_dot(input: Parser) -> IResult { + map( + tuple(( + terminated(tag("."), space0), + terminated(parse_identifier, space0), + )), + |(_, ident)| ident, + )(input) } pub fn parse_operand(input: Parser) -> IResult { @@ -302,9 +387,9 @@ pub fn parse_operand(input: Parser) -> IResult { map(parse_identifier_path, Operand::new_identifier_path), map( delimited( - delimited(space0, tag("("), space0), + terminated(tag("("), space0), parse_expression, - delimited(space0, tag(")"), space0), + terminated(space0, tag(")")), ), Operand::new_expression, ), diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index 4df75e45..a1c5c031 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -340,6 +340,152 @@ mod parse_expression { assert!(matches!(parsed, Expression::BinopExpr(_, _, _))); } } +#[cfg(test)] +mod parse_primary { + use super::*; + + mod arguments { + use super::*; + + mod parenthesis { + use super::*; + + #[test] + fn valid_no_args() { + let input = Parser::new_extra("foo()", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 0), + _ => panic!("expected Arguments"), + } + } + + #[test] + fn valid_one_arg() { + let input = Parser::new_extra("foo(2)", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 1), + _ => panic!("expected Arguments"), + } + } + + #[test] + fn valid_two_args() { + let input = Parser::new_extra("foo(2, 3)", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 2), + _ => panic!("expected Arguments"), + } + } + } + + mod no_parenthesis { + use super::*; + + #[test] + fn valid_one_arg() { + let input = Parser::new_extra("foo 2", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 1), + _ => panic!("expected Arguments"), + } + } + + #[test] + fn valid_two_args() { + let input = Parser::new_extra("foo 2, 3", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 2), + _ => panic!("expected Arguments"), + } + } + } + } + + #[test] + fn valid_indice() { + let input = Parser::new_extra("foo[3]", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Indice(expr) => {} + _ => panic!("expected indice"), + } + } + + #[test] + fn valid_dot() { + let input = Parser::new_extra("foo.toto", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Dot(expr) => {} + _ => panic!("expected dot"), + } + } + + #[test] + fn valid_mixed() { + let input = Parser::new_extra("foo.toto()[a]", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + + assert_eq!(secondaries.len(), 3); + } +} #[cfg(test)] mod parse_fn_decl { @@ -575,3 +721,44 @@ mod parse_for { assert!(rest.fragment().is_empty()); } } + +#[cfg(test)] +mod parse_assign { + use super::*; + + #[test] + fn valid_assign() { + let input = Parser::new_extra("let a = 2", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_assign(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_reassign_ident() { + let input = Parser::new_extra("a = 2", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_assign(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_reassign_dot() { + let input = Parser::new_extra("a.b = 2", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_assign(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_reassign_indice() { + let input = Parser::new_extra("a[2] = 2", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_assign(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} From 8b9566f5db677f948b693a85d2c75de90f2b76d8 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 18 Jan 2022 14:31:22 +0100 Subject: [PATCH 36/74] Add struct decl parsing --- src/lib/ast/tree2.rs | 14 ++++++++++++++ src/lib/parser2/mod.rs | 32 ++++++++++++++++++++++++++++++-- src/lib/parser2/tests.rs | 26 ++++++++++++++++++++++++++ 3 files changed, 70 insertions(+), 2 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index fb931625..9d99db74 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -75,6 +75,10 @@ impl TopLevel { pub fn new_use(u: Use) -> Self { Self::Use(u) } + + pub fn new_struct(s: StructDecl) -> Self { + Self::Struct(s) + } } #[derive(Debug, Clone)] @@ -84,6 +88,16 @@ pub struct StructDecl { pub defs: Vec, } +impl StructDecl { + pub fn new(node_id: NodeId, name: Type, defs: Vec) -> Self { + Self { + node_id, + name, + defs, + } + } +} + #[derive(Debug, Clone)] pub struct StructCtor { pub node_id: NodeId, diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 9ed39864..c3264a76 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -7,7 +7,7 @@ use nom::bytes::complete::{tag, take_while}; use nom::character::complete::{ alphanumeric0, alphanumeric1, char, line_ending, one_of, satisfy, space0, space1, }; -use nom::combinator::{map, opt, recognize}; +use nom::combinator::{eof, map, opt, recognize}; use nom::error::{Error, ErrorKind}; use nom::multi::{many0, many1, separated_list0, separated_list1}; use nom::sequence::{delimited, preceded, terminated, tuple}; @@ -25,6 +25,14 @@ pub type Parser<'a> = LocatedSpan<&'a str, ParserCtx>; #[cfg(test)] mod tests; +// TODO: +// - add support for comments +// - add support for string literals +// - add support for array literals +// - add support for struct declarations +// - add support for struct literals +// - add support for module declarations + #[derive(Debug, Clone)] pub struct ParserCtx { cur_file_path: PathBuf, @@ -79,7 +87,7 @@ impl ParserCtx { } pub fn parse_root(input: Parser) -> IResult { - map(parse_mod, Root::new)(input) + map(terminated(parse_mod, eof), Root::new)(input) } pub fn parse_mod(input: Parser) -> IResult { @@ -97,10 +105,30 @@ pub fn parse_top_level(input: Parser) -> IResult { ), parse_infix, map(parse_use, TopLevel::new_use), + map(parse_struct_decl, TopLevel::new_struct), map(parse_fn, TopLevel::new_function), ))(input) } +pub fn parse_struct_decl(input: Parser) -> IResult { + map( + tuple(( + terminated(tag("struct"), space1), + parse_type, + many0(line_ending), + separated_list0( + terminated(line_ending, space1), + preceded(parse_block_indent, parse_prototype), + ), + )), + |(tag, name, _, defs)| { + let (_input, node_id) = new_identity(input.clone(), &tag); + + StructDecl::new(node_id, name, defs) + }, + )(input.clone()) +} + pub fn parse_use(input: Parser) -> IResult { preceded( terminated(tag("use"), space1), diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index a1c5c031..827afecc 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -762,3 +762,29 @@ mod parse_assign { assert!(rest.fragment().is_empty()); } } + +#[cfg(test)] +mod parse_struct_decl { + use super::*; + + #[test] + fn valid_struct_decl() { + let input = Parser::new_extra("struct Foo", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_struct_decl(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_struct_decl_with_fields() { + let input = Parser::new_extra( + "struct Foo\n a :: Int64\n b :: Float64", + ParserCtx::new(PathBuf::new()), + ); + + let (rest, _parsed) = parse_struct_decl(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} From d2582fa4b45a2156f785c7710316cdd7d9c5379b Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 18 Jan 2022 15:42:41 +0100 Subject: [PATCH 37/74] Fix some tests --- src/lib/ast/tree2.rs | 18 ++++++++++ src/lib/diagnostics/diagnostic.rs | 1 - src/lib/parser/span2.rs | 2 -- src/lib/parser2/mod.rs | 56 ++++++++++++++++++++++++------- src/lib/parser2/tests.rs | 23 +++++++++++++ 5 files changed, 84 insertions(+), 16 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index 9d99db74..7a10027e 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -105,6 +105,16 @@ pub struct StructCtor { pub defs: HashMap, } +impl StructCtor { + pub fn new(node_id: NodeId, name: Type, defs: HashMap) -> Self { + Self { + node_id, + name, + defs, + } + } +} + #[derive(Debug, Clone)] pub struct Trait { pub name: Type, @@ -325,6 +335,10 @@ impl Statement { pub fn new_for(for_: For) -> Self { Self::For(for_) } + + pub fn new_assign(assign: Assign) -> Self { + Self::Assign(Box::new(assign)) + } } #[derive(Debug, Clone)] @@ -485,6 +499,10 @@ impl Expression { Expression::BinopExpr(unary, operator, Box::new(expr)) } + pub fn new_struct_ctor(ctor: StructCtor) -> Expression { + Expression::StructCtor(ctor) + } + // #[allow(dead_code)] // pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> Expression { // Expression { diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index 58be1e8e..9a04b5dd 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -1,6 +1,5 @@ use std::fmt::Display; - use crate::{diagnostics::DiagnosticType, parser::Span}; use crate::{ hir::HirId, diff --git a/src/lib/parser/span2.rs b/src/lib/parser/span2.rs index 8a55d216..99f3ef82 100644 --- a/src/lib/parser/span2.rs +++ b/src/lib/parser/span2.rs @@ -1,7 +1,5 @@ use std::path::PathBuf; - - use crate::parser2::Parser; // TODO: merge spans diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index c3264a76..781865e0 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -29,9 +29,8 @@ mod tests; // - add support for comments // - add support for string literals // - add support for array literals -// - add support for struct declarations -// - add support for struct literals // - add support for module declarations +// - add support for native operations #[derive(Debug, Clone)] pub struct ParserCtx { @@ -220,6 +219,7 @@ pub fn parse_statement(input: Parser) -> IResult { alt(( map(parse_if, Statement::new_if), map(parse_for, Statement::new_for), + map(parse_assign, Statement::new_assign), map(parse_expression, Statement::new_expression), ))(input) } else { @@ -315,17 +315,22 @@ pub fn parse_assign(input: Parser) -> IResult { } pub fn parse_assign_left_side(input: Parser) -> IResult { - map(parse_expression, |expr| { - if expr.is_dot() { - AssignLeftSide::Dot(expr) - } else if expr.is_indice() { - AssignLeftSide::Indice(expr) - } else if expr.is_identifier() { - AssignLeftSide::Identifier(expr) - } else { - panic!("Invalid left side of assignment: {:?}", expr); - } - })(input) + let (input, expr) = parse_expression(input)?; + + let res = if expr.is_dot() { + AssignLeftSide::Dot(expr) + } else if expr.is_indice() { + AssignLeftSide::Indice(expr) + } else if expr.is_identifier() { + AssignLeftSide::Identifier(expr) + } else { + return Err(nom::Err::Error(ParseError::from_error_kind( + input, + ErrorKind::Tag, + ))); + }; + + Ok((input, res)) } pub fn parse_expression(input: Parser) -> IResult { @@ -339,9 +344,34 @@ pub fn parse_expression(input: Parser) -> IResult { |(l, op, r)| Expression::new_binop(l, op, r), ), map(parse_unary, Expression::new_unary), + map(parse_struct_ctor, Expression::new_struct_ctor), ))(input) } +pub fn parse_struct_ctor(input: Parser) -> IResult { + map( + tuple(( + terminated(parse_type, line_ending), + separated_list0( + line_ending, + preceded( + parse_block_indent, + tuple(( + terminated(parse_identifier, delimited(space0, tag(":"), space0)), + parse_expression, + )), + ), + ), + )), + |(name, decls)| { + // FIXME + // let (_input, node_id) = new_identity(input.clone(), &name); + + StructCtor::new(0, name, decls.into_iter().collect()) + }, + )(input) +} + pub fn parse_unary(input: Parser) -> IResult { map(parse_primary, UnaryExpr::new_primary)(input) } diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index 827afecc..85481904 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -788,3 +788,26 @@ mod parse_struct_decl { assert!(rest.fragment().is_empty()); } } + +#[cfg(test)] +mod parse_struct_ctor { + use super::*; + + #[test] + fn valid_struct_ctor() { + let input = Parser::new_extra("Foo\n", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_struct_ctor(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_struct_ctor_with_fields() { + let input = Parser::new_extra("Foo\n a: 2\n b: 3.0", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_struct_ctor(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} From 2661872b78c67ea1e6842393d5bd876de5a364be Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 18 Jan 2022 18:06:33 +0100 Subject: [PATCH 38/74] Better indent, Impl and Trait. --- src/lib/ast/tree2.rs | 20 ++++++++ src/lib/parser2/mod.rs | 107 ++++++++++++++++++++++++++++----------- src/lib/parser2/tests.rs | 34 +++++++++++++ 3 files changed, 131 insertions(+), 30 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index 7a10027e..79f470b5 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -79,6 +79,14 @@ impl TopLevel { pub fn new_struct(s: StructDecl) -> Self { Self::Struct(s) } + + pub fn new_trait(t: Trait) -> Self { + Self::Trait(t) + } + + pub fn new_impl(t: Impl) -> Self { + Self::Impl(t) + } } #[derive(Debug, Clone)] @@ -122,6 +130,12 @@ pub struct Trait { pub defs: Vec, } +impl Trait { + pub fn new(name: Type, types: Vec, defs: Vec) -> Self { + Self { name, types, defs } + } +} + #[derive(Debug, Clone)] pub struct Impl { pub name: Type, @@ -129,6 +143,12 @@ pub struct Impl { pub defs: Vec, } +impl Impl { + pub fn new(name: Type, types: Vec, defs: Vec) -> Self { + Self { name, types, defs } + } +} + #[derive(Debug, Clone)] pub struct Prototype { pub name: Identifier, diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 781865e0..e3c63ab7 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -31,6 +31,9 @@ mod tests; // - add support for array literals // - add support for module declarations // - add support for native operations +// - add one-line blocks +// - restore if then else blocks +// - add support for traits and impl blocks #[derive(Debug, Clone)] pub struct ParserCtx { @@ -105,20 +108,69 @@ pub fn parse_top_level(input: Parser) -> IResult { parse_infix, map(parse_use, TopLevel::new_use), map(parse_struct_decl, TopLevel::new_struct), + map(parse_trait, TopLevel::new_trait), + map(parse_impl, TopLevel::new_impl), map(parse_fn, TopLevel::new_function), ))(input) } +pub fn parse_trait(input: Parser) -> IResult { + map( + tuple(( + terminated(tag("trait"), space1), + parse_type, + many0(delimited(space1, parse_type, space0)), + many0(line_ending), + indent(separated_list1( + line_ending, + preceded(parse_block_indent, parse_prototype), + )), + )), + |(_, name, types, _, defs)| Trait::new(name, types, defs), + )(input.clone()) +} + +pub fn parse_impl(input: Parser) -> IResult { + map( + tuple(( + terminated(tag("impl"), space1), + parse_type, + many0(delimited(space1, parse_type, space0)), + many0(line_ending), + indent(separated_list1( + line_ending, + preceded(parse_block_indent, parse_fn), + )), + )), + |(_, name, types, _, defs)| Impl::new(name, types, defs), + )(input.clone()) +} + +fn indent<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> IResult, O, E> +where + F: nom::Parser, O, E>, +{ + move |mut input: Parser<'a>| { + input.extra.block_indent += 2; + + let (mut input, output) = parser.parse(input)?; + + input.extra.block_indent -= 2; + + Ok((input, output)) + } +} + pub fn parse_struct_decl(input: Parser) -> IResult { map( tuple(( terminated(tag("struct"), space1), parse_type, many0(line_ending), - separated_list0( - terminated(line_ending, space1), + indent(separated_list0( + line_ending, preceded(parse_block_indent, parse_prototype), - ), + )), )), |(tag, name, _, defs)| { let (_input, node_id) = new_identity(input.clone(), &tag); @@ -191,43 +243,38 @@ pub fn parse_fn(input: Parser) -> IResult { } pub fn parse_block_indent(input: Parser) -> IResult { - map(space0, |indents: Parser| indents.fragment().len())(input) + let (input, indent) = space0(input)?; + let indent_len = indent.len(); + + if indent_len == input.extra.block_indent { + Ok((input, indent_len)) + } else { + Err(nom::Err::Error(ParseError::from_error_kind( + input, + ErrorKind::Tag, + ))) + } } pub fn parse_body(mut input: Parser) -> IResult { - input.extra.block_indent += 2; - - let output = map( + indent(map( tuple(( line_ending, separated_list1(many1(line_ending), parse_statement), )), |(_, stmts)| Body::new(stmts), - )(input); - - output.map(|(mut input, body)| { - input.extra.block_indent -= 2; - - (input, body) - }) + ))(input) } pub fn parse_statement(input: Parser) -> IResult { - let (input, indent) = parse_block_indent(input)?; + let (input, _indent) = parse_block_indent(input)?; - if indent == input.extra.block_indent { - alt(( - map(parse_if, Statement::new_if), - map(parse_for, Statement::new_for), - map(parse_assign, Statement::new_assign), - map(parse_expression, Statement::new_expression), - ))(input) - } else { - Err(nom::Err::Error(ParseError::from_error_kind( - input, - ErrorKind::Tag, - ))) - } + alt(( + map(parse_if, Statement::new_if), + map(parse_for, Statement::new_for), + map(parse_assign, Statement::new_assign), + map(parse_expression, Statement::new_expression), + ))(input) } pub fn parse_if(input: Parser) -> IResult { @@ -352,7 +399,7 @@ pub fn parse_struct_ctor(input: Parser) -> IResult { map( tuple(( terminated(parse_type, line_ending), - separated_list0( + indent(separated_list0( line_ending, preceded( parse_block_indent, @@ -361,7 +408,7 @@ pub fn parse_struct_ctor(input: Parser) -> IResult { parse_expression, )), ), - ), + )), )), |(name, decls)| { // FIXME diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index 85481904..dd3e2c15 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -811,3 +811,37 @@ mod parse_struct_ctor { assert!(rest.fragment().is_empty()); } } + +#[cfg(test)] +mod parse_trait { + use super::*; + + #[test] + fn valid_trait() { + let input = Parser::new_extra( + "trait Foo\n a :: Int64 -> Int64\n b :: Float64 -> String", + ParserCtx::new(PathBuf::new()), + ); + + let (rest, _parsed) = parse_trait(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} + +#[cfg(test)] +mod parse_impl { + use super::*; + + #[test] + fn valid_impl() { + let input = Parser::new_extra( + "impl Foo\n a =\n 2", + ParserCtx::new(PathBuf::new()), + ); + + let (rest, _parsed) = parse_impl(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} From a1b5c414dcc55c45c58052bc1c4bd47918240087 Mon Sep 17 00:00:00 2001 From: Champii Date: Wed, 19 Jan 2022 06:04:10 +0100 Subject: [PATCH 39/74] Better indent, almost done. --- src/lib/ast/tree2.rs | 57 ++++++++++- src/lib/parser2/mod.rs | 198 ++++++++++++++++++++++++++++++++------- src/lib/parser2/tests.rs | 38 +++++++- 3 files changed, 256 insertions(+), 37 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index 79f470b5..10b177e8 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -87,6 +87,10 @@ impl TopLevel { pub fn new_impl(t: Impl) -> Self { Self::Impl(t) } + + pub fn new_mod(ident: Identifier, mod_: Mod) -> Self { + Self::Mod(ident, mod_) + } } #[derive(Debug, Clone)] @@ -284,6 +288,15 @@ pub struct Identifier { pub node_id: NodeId, } +impl Identifier { + pub fn new(name: String) -> Self { + Self { + name, + node_id: 0, // FIXME: should have a valid node_id ? + } + } +} + // impl Identifier { // pub fn new(name: ) { @@ -523,6 +536,14 @@ impl Expression { Expression::StructCtor(ctor) } + pub fn new_native_operator( + operator: NativeOperator, + id1: Identifier, + id2: Identifier, + ) -> Expression { + Expression::NativeOperation(operator, id1, id2) + } + // #[allow(dead_code)] // pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> Expression { // Expression { @@ -792,7 +813,13 @@ pub struct NativeOperator { pub node_id: NodeId, } -#[derive(Debug, Clone)] +impl NativeOperator { + pub fn new(node_id: NodeId, kind: NativeOperatorKind) -> Self { + Self { kind, node_id } + } +} + +#[derive(Debug, Clone, PartialEq)] pub enum NativeOperatorKind { IAdd, ISub, @@ -815,3 +842,31 @@ pub enum NativeOperatorKind { BEq, Len, } + +impl NativeOperatorKind { + pub fn from_str(s: &str) -> Self { + match s { + "IAdd" => Self::IAdd, + "ISub" => Self::ISub, + "IMul" => Self::IMul, + "IDiv" => Self::IDiv, + "FAdd" => Self::FAdd, + "FSub" => Self::FSub, + "FMul" => Self::FMul, + "FDiv" => Self::FDiv, + "IEq" => Self::IEq, + "Igt" => Self::Igt, + "Ige" => Self::Ige, + "Ilt" => Self::Ilt, + "Ile" => Self::Ile, + "FEq" => Self::FEq, + "Fgt" => Self::Fgt, + "Fge" => Self::Fge, + "Flt" => Self::Flt, + "Fle" => Self::Fle, + "BEq" => Self::BEq, + "Len" => Self::Len, + _ => panic!("Unknown native operator"), + } + } +} diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index e3c63ab7..4b9909b2 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -7,7 +7,7 @@ use nom::bytes::complete::{tag, take_while}; use nom::character::complete::{ alphanumeric0, alphanumeric1, char, line_ending, one_of, satisfy, space0, space1, }; -use nom::combinator::{eof, map, opt, recognize}; +use nom::combinator::{eof, map, not, opt, recognize, peek}; use nom::error::{Error, ErrorKind}; use nom::multi::{many0, many1, separated_list0, separated_list1}; use nom::sequence::{delimited, preceded, terminated, tuple}; @@ -33,7 +33,8 @@ mod tests; // - add support for native operations // - add one-line blocks // - restore if then else blocks -// - add support for traits and impl blocks +// - fix duplicate node_id +// - fix null node_id #[derive(Debug, Clone)] pub struct ParserCtx { @@ -41,6 +42,7 @@ pub struct ParserCtx { identities: Vec, operators_list: HashMap, block_indent: usize, + first_indent: Option, } impl ParserCtx { @@ -50,6 +52,7 @@ impl ParserCtx { identities: Vec::new(), operators_list: HashMap::new(), block_indent: 0, + first_indent: None, } } @@ -60,6 +63,7 @@ impl ParserCtx { identities: Vec::new(), operators_list: operators, block_indent: 0, + first_indent: None, } } @@ -86,15 +90,28 @@ impl ParserCtx { pub fn add_operator(&mut self, op: String, prec: u8) { self.operators_list.insert(op, prec); } + + pub fn resolve_new_mod(&mut self, name: &str) -> Self { + Self::new( + self.cur_file_path + .parent() + .unwrap() + .join(name.to_owned() + ".rk"), + ) + } } pub fn parse_root(input: Parser) -> IResult { + // TODO: move eof check in parse_mod map(terminated(parse_mod, eof), Root::new)(input) } pub fn parse_mod(input: Parser) -> IResult { map( - many1(terminated(parse_top_level, many1(line_ending))), + many1(terminated( + parse_top_level, + many1(preceded(opt(parse_comment), line_ending)), + )), Mod::new, )(input) } @@ -111,9 +128,33 @@ pub fn parse_top_level(input: Parser) -> IResult { map(parse_trait, TopLevel::new_trait), map(parse_impl, TopLevel::new_impl), map(parse_fn, TopLevel::new_function), + map(parse_mod_decl, |(name, mod_)| TopLevel::new_mod(name, mod_)), ))(input) } +pub fn parse_comment(input: Parser) -> IResult { + let (input, _) = tuple((tag("#"), many0(satisfy(|c: char| c != '\n'))))(input)?; + + Ok((input, ())) +} + +pub fn parse_mod_decl(input: Parser) -> IResult { + let (mut input, mod_name) = preceded(terminated(tag("mod"), space1), parse_identifier)(input)?; + + let new_ctx = input.extra.resolve_new_mod(&mod_name.name); + + let content = std::fs::read_to_string(&new_ctx.current_file_path()).unwrap(); + + let mut new_parser = Parser::new_extra(&content, new_ctx); + + // FIXME: Errors are swallowed here + let (_input, mod_) = parse_mod(new_parser).unwrap(); + + // TODO: hydrate `input` with the new parser's operators + + Ok((input, (mod_name, mod_))) +} + pub fn parse_trait(input: Parser) -> IResult { map( tuple(( @@ -146,21 +187,6 @@ pub fn parse_impl(input: Parser) -> IResult { )(input.clone()) } -fn indent<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> IResult, O, E> -where - F: nom::Parser, O, E>, -{ - move |mut input: Parser<'a>| { - input.extra.block_indent += 2; - - let (mut input, output) = parser.parse(input)?; - - input.extra.block_indent -= 2; - - Ok((input, output)) - } -} - pub fn parse_struct_decl(input: Parser) -> IResult { map( tuple(( @@ -210,10 +236,17 @@ pub fn parse_infix(input: Parser) -> IResult { Ok((input, TopLevel::new_infix(op, pred.as_i64() as u8))) } +pub fn parse_identifier_or_operator(input: Parser) -> IResult { + alt((parse_identifier, map(parse_operator, |op| op.0)))(input) +} + pub fn parse_prototype(input: Parser) -> IResult { map( tuple(( - terminated(parse_identifier, delimited(space0, tag("::"), space0)), + terminated( + parse_identifier_or_operator, + delimited(space0, tag("::"), space0), + ), parse_signature, )), |(name, signature)| Prototype { @@ -228,7 +261,10 @@ pub fn parse_fn(input: Parser) -> IResult { map( tuple(( terminated( - tuple((parse_identifier, many0(preceded(space1, parse_identifier)))), + tuple(( + parse_identifier_or_operator, + many0(preceded(space1, parse_identifier)), + )), delimited(space0, char('='), space0), ), parse_body, @@ -242,9 +278,34 @@ pub fn parse_fn(input: Parser) -> IResult { )(input) } +fn indent<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> IResult, O, E> +where + F: nom::Parser, O, E>, +{ + move |mut input: Parser<'a>| { + if let Some(indent) = input.extra.first_indent { + input.extra.block_indent += indent; + } + + let (mut input, output) = parser.parse(input)?; + + if let Some(indent) = input.extra.first_indent { + input.extra.block_indent -= indent; + } + + Ok((input, output)) + } +} + pub fn parse_block_indent(input: Parser) -> IResult { - let (input, indent) = space0(input)?; - let indent_len = indent.len(); + let (mut input, indent) = space1(input)?; + let indent_len = indent.fragment().len(); + + if input.extra.first_indent == None { + println!("{:?}", indent_len); + input.extra.first_indent = Some(indent_len); + input.extra.block_indent = indent_len; + } if indent_len == input.extra.block_indent { Ok((input, indent_len)) @@ -257,18 +318,22 @@ pub fn parse_block_indent(input: Parser) -> IResult { } pub fn parse_body(mut input: Parser) -> IResult { - indent(map( - tuple(( - line_ending, - separated_list1(many1(line_ending), parse_statement), - )), - |(_, stmts)| Body::new(stmts), - ))(input) + let (input, opt_eol) = opt(line_ending)(input)?; // NOTE: should not fail + + if opt_eol.is_some() { + indent(map( + separated_list1( + many1(line_ending), + preceded(parse_block_indent, parse_statement), + ), + Body::new, + ))(input) + } else { + map(parse_statement, |stmt| Body::new(vec![stmt]))(input) + } } pub fn parse_statement(input: Parser) -> IResult { - let (input, _indent) = parse_block_indent(input)?; - alt(( map(parse_if, Statement::new_if), map(parse_for, Statement::new_for), @@ -294,7 +359,11 @@ pub fn parse_if(input: Parser) -> IResult { } pub fn parse_else(input: Parser) -> IResult { - let (input, indent) = parse_block_indent(input)?; + let (input, indent) = if input.extra.first_indent.is_some() && input.extra.block_indent > 0 { + parse_block_indent(input)? + } else { + (input, 0) + }; if indent == input.extra.block_indent { alt(( @@ -392,9 +461,57 @@ pub fn parse_expression(input: Parser) -> IResult { ), map(parse_unary, Expression::new_unary), map(parse_struct_ctor, Expression::new_struct_ctor), + map(parse_native_operator, |(op, id1, id2)| { + Expression::new_native_operator(op, id1, id2) + }), + // TODO: Return ))(input) } +pub fn parse_native_operator( + input: Parser, +) -> IResult { + map( + tuple(( + preceded( + tag("~"), + alt(( + tag("IAdd"), + tag("ISub"), + tag("IMul"), + tag("IDiv"), + tag("FAdd"), + tag("FSub"), + tag("FMul"), + tag("FDiv"), + tag("IEq"), + tag("Igt"), + tag("Ige"), + tag("Ilt"), + tag("Ile"), + tag("FEq"), + tag("Fgt"), + tag("Fge"), + tag("Flt"), + tag("Fle"), + tag("BEq"), + tag("Len"), + )), + ), + preceded(space1, parse_identifier), + preceded(space1, parse_identifier), + )), + |(tag, id1, id2)| { + let (input, node_id) = new_identity(input.clone(), &tag); + ( + NativeOperator::new(node_id, NativeOperatorKind::from_str(tag.fragment())), + id1, + id2, + ) + }, + )(input.clone()) +} + pub fn parse_struct_ctor(input: Parser) -> IResult { map( tuple(( @@ -503,13 +620,21 @@ pub fn parse_operand(input: Parser) -> IResult { pub fn parse_identifier_path(input: Parser) -> IResult { map( - separated_list1(tag("::"), parse_identifier), + separated_list1( + tag("::"), + alt(( + map(tag("*"), |_| Identifier::new("*".to_string())), + parse_identifier, + )), + ), IdentifierPath::new, )(input) } pub fn parse_identifier(input: Parser) -> IResult { - let (input, ident_parsed) = alphanumeric1(input)?; + // let (input, ident_parsed) = alphanumeric1(input)?; + let (input, ident_parsed) = + recognize(many1(one_of("abcdefghijklmnopqrstuvwxyz_0123456789")))(input)?; let (input, node_id) = new_identity(input, &ident_parsed); @@ -609,7 +734,10 @@ pub fn parse_signature(input: Parser) -> IResult { } pub fn parse_type(input: Parser) -> IResult { - let (input, parsed) = parse_capitalized_text(input)?; + let (input, parsed) = alt(( + parse_capitalized_text, + map(terminated(one_of("abcdefghijklmnopqrstuvwxyz"), peek(alt((space1, line_ending)))), |c| String::from(c)), + ))(input)?; let ty = Type::from(parsed); diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index dd3e2c15..3e8968b1 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -174,6 +174,14 @@ mod parse_type { assert_eq!(parsed, Type::int64()); } + fn valid_for_all() { + let input = Parser::new_extra("a", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_type(input).finish().unwrap(); + + assert_eq!(parsed, Type::forall("a")); + } + #[test] fn invalid() { let input = Parser::new_extra("int64", ParserCtx::new(PathBuf::new())); @@ -603,6 +611,20 @@ mod parse_fn_decl { assert!(rest.fragment().is_empty()); } + + #[test] + fn valid_one_line() { + let operators = HashMap::from([("+".to_string(), 5)]); + + let input = Parser::new_extra( + "toto a b = a + b", + ParserCtx::new_with_operators(PathBuf::new(), operators), + ); + + let (rest, _parsed) = parse_fn(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } } #[cfg(test)] @@ -836,7 +858,7 @@ mod parse_impl { #[test] fn valid_impl() { let input = Parser::new_extra( - "impl Foo\n a =\n 2", + "impl Foo\n a =\n 2\n b a =\n a", ParserCtx::new(PathBuf::new()), ); @@ -845,3 +867,17 @@ mod parse_impl { assert!(rest.fragment().is_empty()); } } + +#[cfg(test)] +mod parse_native_operator { + use super::*; + + #[test] + fn valid_native_operator() { + let input = Parser::new_extra("~IAdd a b", ParserCtx::new(PathBuf::new())); + + let (rest, (parsed, _, _)) = parse_native_operator(input).finish().unwrap(); + + assert_eq!(parsed.kind, NativeOperatorKind::IAdd); + } +} From 1fef240ae31925c36ed55b3fd6379a1bd735ae06 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 25 Jan 2022 01:23:22 +0100 Subject: [PATCH 40/74] Restored then in if/else constructs --- src/lib/ast/tree2.rs | 19 +++++++++++-- src/lib/parser2/mod.rs | 58 ++++++++++++++++++++++++++++++++-------- src/lib/parser2/tests.rs | 18 ++++++++++--- 3 files changed, 78 insertions(+), 17 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index 10b177e8..23e0cbcb 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -1,9 +1,13 @@ -use std::collections::HashMap; +use std::{collections::HashMap, str::FromStr}; + +use nom::Finish; use crate::{ ast::NodeId, helpers::*, parser::span2::Span, + parser2::create_parser, + parser2::parse_root, resolver::ResolutionMap, ty::{FuncType, Type}, }; @@ -17,6 +21,17 @@ pub struct Root { pub spans: HashMap, } +/* impl FromStr for Root { + type Err = String; + + fn from_str(s: &str) -> Result { + match parse_root(create_parser(s)).finish() { + Ok((_, root)) => Ok(root), + Err(e) => Err(format!("{:?}", e)), + } + } +} + */ impl Root { pub fn new(r#mod: Mod) -> Self { Self { @@ -565,7 +580,7 @@ pub enum Expression { UnaryExpr(UnaryExpr), NativeOperation(NativeOperator, Identifier, Identifier), StructCtor(StructCtor), - Return(Box), + Return(Box), // NOTE: Shouldn't that be a statement? } #[derive(Debug, Clone)] diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 4b9909b2..879f6994 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -7,7 +7,7 @@ use nom::bytes::complete::{tag, take_while}; use nom::character::complete::{ alphanumeric0, alphanumeric1, char, line_ending, one_of, satisfy, space0, space1, }; -use nom::combinator::{eof, map, not, opt, recognize, peek}; +use nom::combinator::{eof, map, not, opt, peek, recognize}; use nom::error::{Error, ErrorKind}; use nom::multi::{many0, many1, separated_list0, separated_list1}; use nom::sequence::{delimited, preceded, terminated, tuple}; @@ -26,13 +26,8 @@ pub type Parser<'a> = LocatedSpan<&'a str, ParserCtx>; mod tests; // TODO: -// - add support for comments // - add support for string literals // - add support for array literals -// - add support for module declarations -// - add support for native operations -// - add one-line blocks -// - restore if then else blocks // - fix duplicate node_id // - fix null node_id @@ -101,6 +96,14 @@ impl ParserCtx { } } +pub fn create_parser(s: &str) -> Parser<'_> { + LocatedSpan::new_extra(s, ParserCtx::new(PathBuf::from(""))) +} + +pub fn create_parser_with_filename(s: &str, path: PathBuf) -> Parser<'_> { + LocatedSpan::new_extra(s, ParserCtx::new(path)) +} + pub fn parse_root(input: Parser) -> IResult { // TODO: move eof check in parse_mod map(terminated(parse_mod, eof), Root::new)(input) @@ -147,10 +150,15 @@ pub fn parse_mod_decl(input: Parser) -> IResult { let mut new_parser = Parser::new_extra(&content, new_ctx); + use nom::Finish; // FIXME: Errors are swallowed here - let (_input, mod_) = parse_mod(new_parser).unwrap(); + let (input2, mod_) = parse_mod(new_parser).finish().unwrap(); - // TODO: hydrate `input` with the new parser's operators + // hydrate `input` with the new parser's operators + input + .extra + .operators_list + .extend(input2.extra.operators_list); Ok((input, (mod_name, mod_))) } @@ -302,7 +310,6 @@ pub fn parse_block_indent(input: Parser) -> IResult { let indent_len = indent.fragment().len(); if input.extra.first_indent == None { - println!("{:?}", indent_len); input.extra.first_indent = Some(indent_len); input.extra.block_indent = indent_len; } @@ -347,10 +354,12 @@ pub fn parse_if(input: Parser) -> IResult { tuple(( terminated(tag("if"), space1), terminated(parse_expression, space0), + many1(line_ending), + parse_then, parse_body, opt(tuple((line_ending, parse_else))), )), - |(if_, cond, body, else_)| { + |(if_, cond, _, _, body, else_)| { let (_input, node_id) = new_identity(input.clone(), &if_); If::new(node_id, cond, body, else_.map(|(_, else_)| Box::new(else_))) @@ -358,7 +367,28 @@ pub fn parse_if(input: Parser) -> IResult { )(input.clone()) } +pub fn parse_then(input: Parser) -> IResult { + // NOTE: This is a tweek for then block that are at indent 0 (i.e. in the test files) + let (input, indent) = if input.extra.first_indent.is_some() && input.extra.block_indent > 0 { + parse_block_indent(input)? + } else { + (input, 0) + }; + + if indent == input.extra.block_indent { + let (input, _) = terminated(tag("then"), space0)(input)?; + + Ok((input, ())) + } else { + Err(nom::Err::Error(ParseError::from_error_kind( + input, + ErrorKind::Tag, + ))) + } +} + pub fn parse_else(input: Parser) -> IResult { + // NOTE: This is a tweek for else block that are at indent 0 (i.e. in the test files) let (input, indent) = if input.extra.first_indent.is_some() && input.extra.block_indent > 0 { parse_block_indent(input)? } else { @@ -736,7 +766,13 @@ pub fn parse_signature(input: Parser) -> IResult { pub fn parse_type(input: Parser) -> IResult { let (input, parsed) = alt(( parse_capitalized_text, - map(terminated(one_of("abcdefghijklmnopqrstuvwxyz"), peek(alt((space1, line_ending)))), |c| String::from(c)), + map( + terminated( + one_of("abcdefghijklmnopqrstuvwxyz"), + peek(alt((space1, line_ending))), + ), + |c| String::from(c), + ), ))(input)?; let ty = Type::from(parsed); diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index 3e8968b1..42b0b47c 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -681,7 +681,7 @@ mod parse_if { #[test] fn valid_if() { - let input = Parser::new_extra("if a\n b", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("if a\nthen b", ParserCtx::new(PathBuf::new())); let (rest, _parsed) = parse_if(input).finish().unwrap(); @@ -690,7 +690,7 @@ mod parse_if { #[test] fn valid_if_else() { - let input = Parser::new_extra("if a\n b\nelse\n c", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("if a\nthen b\nelse c", ParserCtx::new(PathBuf::new())); let (rest, _parsed) = parse_if(input).finish().unwrap(); @@ -700,7 +700,7 @@ mod parse_if { #[test] fn valid_if_else_if() { let input = Parser::new_extra( - "if a\n b\nelse if false\n c", + "if a\nthen b\nelse if false\nthen c", ParserCtx::new(PathBuf::new()), ); @@ -708,10 +708,11 @@ mod parse_if { assert!(rest.fragment().is_empty()); } + #[test] fn valid_if_else_if_else() { let input = Parser::new_extra( - "if a\n b\nelse if true\n c\nelse\n d", + "if a\nthen b\nelse if true\nthen c\nelse d", ParserCtx::new(PathBuf::new()), ); @@ -719,6 +720,15 @@ mod parse_if { assert!(rest.fragment().is_empty()); } + + #[test] + fn valid_multiline_if_else() { + let input = Parser::new_extra("if a\nthen\n b\nelse\n d", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_if(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } } #[cfg(test)] From e99af228c6d48f7ee14564525406e457d9818457 Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 29 Jan 2022 03:37:17 +0100 Subject: [PATCH 41/74] Add array support --- src/lib/ast/tree2.rs | 18 ++++- src/lib/diagnostics/diagnostic.rs | 10 +-- src/lib/parser/span.rs | 11 +++ src/lib/parser/span2.rs | 10 +-- src/lib/parser2/mod.rs | 100 +++++++++++++++++++++----- src/lib/parser2/tests.rs | 17 ++++- src/lib/rock.rs | 15 ++++ src/lib/testcases/basic/while/main.rk | 4 +- 8 files changed, 155 insertions(+), 30 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index 23e0cbcb..da9e4adb 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -674,10 +674,10 @@ impl PrimaryExpr { } } - pub fn new(op: Operand, secondaries: Vec) -> PrimaryExpr { + pub fn new(node_id: NodeId, op: Operand, secondaries: Vec) -> PrimaryExpr { PrimaryExpr { op, - node_id: 0, + node_id, secondaries: if secondaries.len() == 0 { None } else { @@ -789,6 +789,13 @@ impl Literal { } } + pub fn new_array(arr: Array, node_id: NodeId) -> Self { + Self { + kind: LiteralKind::Array(arr), + node_id, + } + } + pub fn as_i64(&self) -> i64 { match self.kind { LiteralKind::Number(n) => n, @@ -802,6 +809,7 @@ pub enum LiteralKind { Bool(bool), Number(i64), Float(f64), + Array(Array), } #[derive(Debug, Clone)] @@ -809,6 +817,12 @@ pub struct Array { pub values: Vec, } +impl Array { + pub fn new(values: Vec) -> Self { + Self { values } + } +} + pub type Arguments = Vec; #[derive(Debug, Clone)] diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index 9a04b5dd..05ba728e 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -1,6 +1,7 @@ use std::fmt::Display; -use crate::{diagnostics::DiagnosticType, parser::Span}; +use crate::parser2::Parser; +use crate::{diagnostics::DiagnosticType, parser::Span, parser::span2::Span as Span2}; use crate::{ hir::HirId, parser::SourceFile, @@ -272,12 +273,13 @@ impl Display for DiagnosticKind { } } -/* impl<'a> From> for Diagnostic { +impl<'a> From> for Diagnostic { fn from(err: Parser<'a>) -> Self { - let span = Span::from(err); + let span2 = Span2::from(err); + let span = Span::from(span2); let msg = "Syntax error".to_string(); Diagnostic::new_syntax_error(span, msg) } -} */ +} diff --git a/src/lib/parser/span.rs b/src/lib/parser/span.rs index 68e6385e..9890073f 100644 --- a/src/lib/parser/span.rs +++ b/src/lib/parser/span.rs @@ -1,4 +1,5 @@ use std::path::PathBuf; +use super::span2::Span as Span2; #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct Span { @@ -24,3 +25,13 @@ impl Span { } } } + +impl From for Span { + fn from(span: Span2) -> Self { + Self { + start: span.offset, + end: span.txt.len() + span.offset, + file_path: span.file_path, + } + } +} diff --git a/src/lib/parser/span2.rs b/src/lib/parser/span2.rs index 99f3ef82..1bfff1b2 100644 --- a/src/lib/parser/span2.rs +++ b/src/lib/parser/span2.rs @@ -6,11 +6,11 @@ use crate::parser2::Parser; #[derive(Debug, Clone, Hash, PartialEq, Eq)] pub struct Span { - file_path: PathBuf, - offset: usize, - line: usize, - column: usize, - txt: String, + pub file_path: PathBuf, + pub offset: usize, + pub line: usize, + pub column: usize, + pub txt: String, } impl<'a> From> for Span { diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 879f6994..29bf01a6 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -28,7 +28,6 @@ mod tests; // TODO: // - add support for string literals // - add support for array literals -// - fix duplicate node_id // - fix null node_id #[derive(Debug, Clone)] @@ -38,6 +37,7 @@ pub struct ParserCtx { operators_list: HashMap, block_indent: usize, first_indent: Option, + next_node_id: NodeId, } impl ParserCtx { @@ -48,6 +48,7 @@ impl ParserCtx { operators_list: HashMap::new(), block_indent: 0, first_indent: None, + next_node_id: 0, } } @@ -59,11 +60,28 @@ impl ParserCtx { operators_list: operators, block_indent: 0, first_indent: None, + next_node_id: 0, + } + } + + pub fn new_from(&self, name: &str) -> Self { + Self { + cur_file_path: self.cur_file_path + .parent() + .unwrap() + .join(name.to_owned() + ".rk"), + identities: Vec::new(), + operators_list: HashMap::new(), + block_indent: 0, + first_indent: None, + next_node_id: self.next_node_id, } } pub fn new_identity(&mut self, span: Span) -> NodeId { - let node_id = self.identities.len() as NodeId; + let node_id = self.next_node_id; + + self.next_node_id += 1; self.identities.push(Identity::new(node_id, span)); @@ -86,14 +104,18 @@ impl ParserCtx { self.operators_list.insert(op, prec); } - pub fn resolve_new_mod(&mut self, name: &str) -> Self { - Self::new( + /* pub fn resolve_new_mod(&mut self, name: &str) -> Self { + let mut new = Self::new( self.cur_file_path .parent() .unwrap() .join(name.to_owned() + ".rk"), - ) - } + ); + + new.identities = self.identities.clone(); + + new + } */ } pub fn create_parser(s: &str) -> Parser<'_> { @@ -144,7 +166,7 @@ pub fn parse_comment(input: Parser) -> IResult { pub fn parse_mod_decl(input: Parser) -> IResult { let (mut input, mod_name) = preceded(terminated(tag("mod"), space1), parse_identifier)(input)?; - let new_ctx = input.extra.resolve_new_mod(&mod_name.name); + let new_ctx = input.extra.new_from(&mod_name.name); let content = std::fs::read_to_string(&new_ctx.current_file_path()).unwrap(); @@ -155,11 +177,16 @@ pub fn parse_mod_decl(input: Parser) -> IResult { let (input2, mod_) = parse_mod(new_parser).finish().unwrap(); // hydrate `input` with the new parser's operators + // TODO: handle duplicate operators input .extra .operators_list .extend(input2.extra.operators_list); + // extend identities + input.extra.identities.extend(input2.extra.identities); + input.extra.next_node_id = input2.extra.next_node_id; + Ok((input, (mod_name, mod_))) } @@ -176,7 +203,7 @@ pub fn parse_trait(input: Parser) -> IResult { )), )), |(_, name, types, _, defs)| Trait::new(name, types, defs), - )(input.clone()) + )(input) } pub fn parse_impl(input: Parser) -> IResult { @@ -192,13 +219,14 @@ pub fn parse_impl(input: Parser) -> IResult { )), )), |(_, name, types, _, defs)| Impl::new(name, types, defs), - )(input.clone()) + )(input) } pub fn parse_struct_decl(input: Parser) -> IResult { map( tuple(( terminated(tag("struct"), space1), + parse_identity, parse_type, many0(line_ending), indent(separated_list0( @@ -206,9 +234,7 @@ pub fn parse_struct_decl(input: Parser) -> IResult { preceded(parse_block_indent, parse_prototype), )), )), - |(tag, name, _, defs)| { - let (_input, node_id) = new_identity(input.clone(), &tag); - + |(tag, node_id, name, _, defs)| { StructDecl::new(node_id, name, defs) }, )(input.clone()) @@ -573,8 +599,12 @@ pub fn parse_unary(input: Parser) -> IResult { pub fn parse_primary(input: Parser) -> IResult { map( tuple((parse_operand, many0(parse_secondary))), - |(op, secs)| PrimaryExpr::new(op, secs), - )(input) + |(op, secs)| { + let (_input, node_id) = new_identity(input.clone(), &input.clone()); + + PrimaryExpr::new(node_id, op, secs) + }, + )(input.clone()) } pub fn parse_secondary(input: Parser) -> IResult { @@ -678,7 +708,7 @@ pub fn parse_identifier(input: Parser) -> IResult { } pub fn parse_operator(input: Parser) -> IResult { - let (input, parsed_op) = one_of(LocatedSpan::new( + let (input, parsed_op) = recognize(many1(one_of(LocatedSpan::new( input .extra .operators() @@ -687,7 +717,7 @@ pub fn parse_operator(input: Parser) -> IResult { .collect::>() .join("") .as_str(), - ))(input)?; + ))))(input)?; let (input, pos) = position(input)?; @@ -703,7 +733,22 @@ pub fn parse_operator(input: Parser) -> IResult { } pub fn parse_literal(input: Parser) -> IResult { - alt((parse_bool, parse_float, parse_number))(input) + alt((parse_bool, parse_float, parse_number, parse_array))(input) +} + +pub fn parse_array(input: Parser) -> IResult { + map( + tuple(( + parse_identity, + terminated(tag("["), space0), + separated_list0( + tuple((space0, terminated(tag(","), space0), space0)), + parse_expression, + ), + terminated(tag("]"), space0), + )), + |(node_id, _, elements, _)| Literal::new_array(Array::new(elements.into_iter().collect()), node_id), + )(input) } pub fn parse_bool(input: Parser) -> IResult { @@ -801,6 +846,27 @@ fn new_identity<'a>(mut input: Parser<'a>, parsed: &Parser<'a>) -> (Parser<'a>, (input, node_id) } +fn parse_identity(input: Parser) -> IResult { + let (input, pos) = position(input)?; + + let (input, node_id) = new_identity(input, &pos); + + Ok((input, node_id)) +} + +/* fn parse_identity2<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> IResult, O, E> +where + F: nom::Parser, O, E>, +{ + move |mut input: Parser<'a>| { + let (mut input, output) = parser.parse(input)?; + + let (input, node_id) = new_identity(input, &output); + + Ok(()) + } +} */ + pub fn allowed_operator_chars(input: Parser) -> IResult { let (input, c) = one_of(LocatedSpan::new( crate::parser::accepted_operator_chars() diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index 42b0b47c..7092b35a 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -746,7 +746,7 @@ mod parse_for { #[test] fn valid_while() { - let input = Parser::new_extra("while a\n b", ParserCtx::new(PathBuf::new())); + let input = Parser::new_extra("while a\n b = 2", ParserCtx::new(PathBuf::new())); let (rest, _parsed) = parse_for(input).finish().unwrap(); @@ -891,3 +891,18 @@ mod parse_native_operator { assert_eq!(parsed.kind, NativeOperatorKind::IAdd); } } + +#[cfg(test)] +mod parse_array { + use super::*; + + #[test] + fn valid_array() { + let input = Parser::new_extra("[1, 2, 3]", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_array(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} + diff --git a/src/lib/rock.rs b/src/lib/rock.rs index ae09757e..7707e153 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -78,6 +78,21 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { + + + Ok(ast) + } + Err(e) => { + let diagnostic = Diagnostic::from(e.input); + + parsing_ctx.diagnostics.push_error(diagnostic.clone()); + + Err(diagnostic) + } + }; + // Text to Ast debug!(" -> Parsing"); let mut ast = parser::parse_root(parsing_ctx)?; diff --git a/src/lib/testcases/basic/while/main.rk b/src/lib/testcases/basic/while/main.rk index 36c6f397..8286a272 100644 --- a/src/lib/testcases/basic/while/main.rk +++ b/src/lib/testcases/basic/while/main.rk @@ -7,6 +7,8 @@ infix < 3 main = let i = 0 let x = 42 - for i < x + # This fails because old parser does not handle while keyword + # Waiting for new parser to be merged + while i < x i = i + 1 i From 4a990a5a20db9f56d0fdaf5fa1598ba38ba3b244 Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 29 Jan 2022 03:59:56 +0100 Subject: [PATCH 42/74] Add basic strings --- src/lib/ast/tree2.rs | 8 ++++++++ src/lib/diagnostics/diagnostic.rs | 2 +- src/lib/parser/span.rs | 2 +- src/lib/parser2/mod.rs | 33 +++++++++++++++++++++++-------- src/lib/parser2/tests.rs | 13 ++++++++++++ src/lib/rock.rs | 6 +----- 6 files changed, 49 insertions(+), 15 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index da9e4adb..a6ee02af 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -796,6 +796,13 @@ impl Literal { } } + pub fn new_string(str: String, node_id: NodeId) -> Self { + Self { + kind: LiteralKind::String(str), + node_id, + } + } + pub fn as_i64(&self) -> i64 { match self.kind { LiteralKind::Number(n) => n, @@ -810,6 +817,7 @@ pub enum LiteralKind { Number(i64), Float(f64), Array(Array), + String(String), } #[derive(Debug, Clone)] diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index 05ba728e..e019e123 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -1,7 +1,7 @@ use std::fmt::Display; use crate::parser2::Parser; -use crate::{diagnostics::DiagnosticType, parser::Span, parser::span2::Span as Span2}; +use crate::{diagnostics::DiagnosticType, parser::span2::Span as Span2, parser::Span}; use crate::{ hir::HirId, parser::SourceFile, diff --git a/src/lib/parser/span.rs b/src/lib/parser/span.rs index 9890073f..5089460d 100644 --- a/src/lib/parser/span.rs +++ b/src/lib/parser/span.rs @@ -1,5 +1,5 @@ -use std::path::PathBuf; use super::span2::Span as Span2; +use std::path::PathBuf; #[derive(Debug, Clone, Hash, PartialEq, Eq, Serialize, Deserialize)] pub struct Span { diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 29bf01a6..bfa97c86 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -12,6 +12,8 @@ use nom::error::{Error, ErrorKind}; use nom::multi::{many0, many1, separated_list0, separated_list1}; use nom::sequence::{delimited, preceded, terminated, tuple}; use nom::{error::ParseError, Err, IResult}; +use nom::bytes::complete::escaped; +use nom::character::complete::anychar; use crate::ast::identity2::Identity; use crate::ast::tree2::*; @@ -26,8 +28,7 @@ pub type Parser<'a> = LocatedSpan<&'a str, ParserCtx>; mod tests; // TODO: -// - add support for string literals -// - add support for array literals +// - add support for escaped string // - fix null node_id #[derive(Debug, Clone)] @@ -66,7 +67,8 @@ impl ParserCtx { pub fn new_from(&self, name: &str) -> Self { Self { - cur_file_path: self.cur_file_path + cur_file_path: self + .cur_file_path .parent() .unwrap() .join(name.to_owned() + ".rk"), @@ -234,9 +236,7 @@ pub fn parse_struct_decl(input: Parser) -> IResult { preceded(parse_block_indent, parse_prototype), )), )), - |(tag, node_id, name, _, defs)| { - StructDecl::new(node_id, name, defs) - }, + |(tag, node_id, name, _, defs)| StructDecl::new(node_id, name, defs), )(input.clone()) } @@ -733,7 +733,22 @@ pub fn parse_operator(input: Parser) -> IResult { } pub fn parse_literal(input: Parser) -> IResult { - alt((parse_bool, parse_float, parse_number, parse_array))(input) + alt(( + parse_bool, + parse_float, + parse_number, + parse_array, + parse_string, + ))(input) +} + +pub fn parse_string(input: Parser) -> IResult { + map(tuple(( + parse_identity, + terminated(tag("\""), space0), + recognize(take_while(|c: char| c != '"')), + terminated(tag("\""), space0), + )), |(node_id, _, s, _)| Literal::new_string(String::from(*s.fragment()), node_id))(input) } pub fn parse_array(input: Parser) -> IResult { @@ -747,7 +762,9 @@ pub fn parse_array(input: Parser) -> IResult { ), terminated(tag("]"), space0), )), - |(node_id, _, elements, _)| Literal::new_array(Array::new(elements.into_iter().collect()), node_id), + |(node_id, _, elements, _)| { + Literal::new_array(Array::new(elements.into_iter().collect()), node_id) + }, )(input) } diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index 7092b35a..443d521d 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -906,3 +906,16 @@ mod parse_array { } } +#[cfg(test)] +mod parse_string { + use super::*; + + #[test] + fn valid_string() { + let input = Parser::new_extra("\"foo\"", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_string(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} diff --git a/src/lib/rock.rs b/src/lib/rock.rs index 7707e153..a22fedd3 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -79,11 +79,7 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { - - - Ok(ast) - } + Ok((_, ast)) => Ok(ast), Err(e) => { let diagnostic = Diagnostic::from(e.input); From f55ba9ba114cf5c4e708b57900407e83de07865c Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 29 Jan 2022 05:12:14 +0100 Subject: [PATCH 43/74] add array type parsing --- src/lib/parser2/mod.rs | 37 ++++++++++++------- .../basic/multiline_struct_const/main.rk | 7 ++-- .../nested_struct_dect_multiline/main.rk | 11 ++---- .../basic/struct_array_field/main.rk | 7 ++-- src/lib/ty/type.rs | 7 ++++ 5 files changed, 40 insertions(+), 29 deletions(-) diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index bfa97c86..306f1253 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -3,7 +3,9 @@ use std::collections::HashMap; use std::path::PathBuf; use nom::branch::alt; +use nom::bytes::complete::escaped; use nom::bytes::complete::{tag, take_while}; +use nom::character::complete::anychar; use nom::character::complete::{ alphanumeric0, alphanumeric1, char, line_ending, one_of, satisfy, space0, space1, }; @@ -12,14 +14,12 @@ use nom::error::{Error, ErrorKind}; use nom::multi::{many0, many1, separated_list0, separated_list1}; use nom::sequence::{delimited, preceded, terminated, tuple}; use nom::{error::ParseError, Err, IResult}; -use nom::bytes::complete::escaped; -use nom::character::complete::anychar; use crate::ast::identity2::Identity; use crate::ast::tree2::*; use crate::ast::NodeId; use crate::parser::span2::Span; -use crate::ty::{FuncType, Type}; +use crate::ty::{FuncType, Type, PrimitiveType}; use nom_locate::{position, LocatedSpan}; pub type Parser<'a> = LocatedSpan<&'a str, ParserCtx>; @@ -29,6 +29,7 @@ mod tests; // TODO: // - add support for escaped string +// - fix typing (check every types) // - fix null node_id #[derive(Debug, Clone)] @@ -743,12 +744,15 @@ pub fn parse_literal(input: Parser) -> IResult { } pub fn parse_string(input: Parser) -> IResult { - map(tuple(( - parse_identity, - terminated(tag("\""), space0), - recognize(take_while(|c: char| c != '"')), - terminated(tag("\""), space0), - )), |(node_id, _, s, _)| Literal::new_string(String::from(*s.fragment()), node_id))(input) + map( + tuple(( + parse_identity, + terminated(tag("\""), space0), + recognize(take_while(|c: char| c != '"')), + terminated(tag("\""), space0), + )), + |(node_id, _, s, _)| Literal::new_string(String::from(*s.fragment()), node_id), + )(input) } pub fn parse_array(input: Parser) -> IResult { @@ -826,19 +830,24 @@ pub fn parse_signature(input: Parser) -> IResult { } pub fn parse_type(input: Parser) -> IResult { - let (input, parsed) = alt(( - parse_capitalized_text, + let (input, ty) = alt(( + map(parse_capitalized_text, Type::Trait), map( terminated( one_of("abcdefghijklmnopqrstuvwxyz"), peek(alt((space1, line_ending))), ), - |c| String::from(c), + |c| Type::ForAll(String::from(c)), + ), + map( + delimited(tag("["), parse_type, tag("]")), + |t| Type::Primitive(PrimitiveType::Array( + Box::new(t), + 0, + )), ), ))(input)?; - let ty = Type::from(parsed); - Ok((input, ty)) } diff --git a/src/lib/testcases/basic/multiline_struct_const/main.rk b/src/lib/testcases/basic/multiline_struct_const/main.rk index 4beec3c8..ee020c56 100644 --- a/src/lib/testcases/basic/multiline_struct_const/main.rk +++ b/src/lib/testcases/basic/multiline_struct_const/main.rk @@ -3,9 +3,8 @@ struct Foo titi :: Float64 main = - let lol = - Foo - toto: 42 - titi: 10.2 + let lol = Foo + toto: 42 + titi: 10.2 lol.toto diff --git a/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk b/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk index 58fa03dc..362542a8 100644 --- a/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk +++ b/src/lib/testcases/basic/nested_struct_dect_multiline/main.rk @@ -6,12 +6,9 @@ struct Foo titi :: Float64 main = - let lol = - Foo - toto: - Bar - mdr: 42 - titi: - 10.2 + let lol = Foo + toto: Bar + mdr: 42 + titi: 10.2 lol.toto.mdr diff --git a/src/lib/testcases/basic/struct_array_field/main.rk b/src/lib/testcases/basic/struct_array_field/main.rk index 39c83411..e98935a4 100644 --- a/src/lib/testcases/basic/struct_array_field/main.rk +++ b/src/lib/testcases/basic/struct_array_field/main.rk @@ -3,9 +3,8 @@ struct Foo titi :: Float64 main = - let lol = - Foo - titi: 10.2 - toto: [10, 42] + let lol = Foo + titi: 10.2 + toto: [10, 42] lol.toto[1] diff --git a/src/lib/ty/type.rs b/src/lib/ty/type.rs index 6493264b..4323f256 100644 --- a/src/lib/ty/type.rs +++ b/src/lib/ty/type.rs @@ -217,6 +217,13 @@ impl From for Type { fn from(t: String) -> Self { if t.len() == 1 && (t.chars().next().unwrap()).is_lowercase() { Type::ForAll(t) + } else if t.chars().next().unwrap() == '[' { + Type::Primitive(PrimitiveType::Array( + Box::new(Type::from( + t.trim_matches('[').trim_matches(']').to_string(), + )), + 0, + )) } else { Type::Trait(t) } From f17223f7a8842eb8830df09e595cab9e8fe467ab Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 29 Jan 2022 05:28:03 +0100 Subject: [PATCH 44/74] Fix all tests with new parser --- src/lib/parser2/mod.rs | 3 ++- src/lib/parser2/tests.rs | 22 +------------------ src/lib/testcases/mods/basic_mod/main.rk | 1 - .../mods/func_arg_resolution/main.rk | 3 +-- .../mods/nested_trait_resolution/main.rk | 3 +-- src/lib/testcases/mods/unused_fn/main.rk | 2 -- src/lib/testcases/mods/unused_impl_fn/main.rk | 1 - 7 files changed, 5 insertions(+), 30 deletions(-) diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 306f1253..e3b4687f 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -686,6 +686,7 @@ pub fn parse_identifier_path(input: Parser) -> IResult { alt(( map(tag("*"), |_| Identifier::new("*".to_string())), parse_identifier, + // map(parse_operator, |op| op.0), )), ), IdentifierPath::new, @@ -835,7 +836,7 @@ pub fn parse_type(input: Parser) -> IResult { map( terminated( one_of("abcdefghijklmnopqrstuvwxyz"), - peek(alt((space1, line_ending))), + peek(alt((space1, line_ending, eof))), ), |c| Type::ForAll(String::from(c)), ), diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index 443d521d..91ece10f 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -114,27 +114,6 @@ mod parse_number { assert!(parse_number(input).finish().is_err()); } } -/* -#[cfg(test)] -mod parse_string { - use super::*; - - #[test] - fn valid() { - let input = Parser::new_extra("\"hello\"", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_string(input).finish().unwrap(); - - assert!(matches!(parsed.kind, LiteralKind::String(ref s) if s == "hello")); - } - - #[test] - fn invalid() { - let input = Parser::new_extra("\"hello", ParserCtx::new(PathBuf::new())); - - assert!(parse_string(input).finish().is_err()); - } -} */ #[cfg(test)] mod parse_signature { @@ -174,6 +153,7 @@ mod parse_type { assert_eq!(parsed, Type::int64()); } + #[test] fn valid_for_all() { let input = Parser::new_extra("a", ParserCtx::new(PathBuf::new())); diff --git a/src/lib/testcases/mods/basic_mod/main.rk b/src/lib/testcases/mods/basic_mod/main.rk index dcb4f719..af567311 100644 --- a/src/lib/testcases/mods/basic_mod/main.rk +++ b/src/lib/testcases/mods/basic_mod/main.rk @@ -1,6 +1,5 @@ mod _std -use _std::+ use _std::* test g h i j = g diff --git a/src/lib/testcases/mods/func_arg_resolution/main.rk b/src/lib/testcases/mods/func_arg_resolution/main.rk index 652ef2b0..60417302 100644 --- a/src/lib/testcases/mods/func_arg_resolution/main.rk +++ b/src/lib/testcases/mods/func_arg_resolution/main.rk @@ -1,7 +1,6 @@ mod _std -use _std::|> -use _std::+ +use _std::* f a = a + 2 diff --git a/src/lib/testcases/mods/nested_trait_resolution/main.rk b/src/lib/testcases/mods/nested_trait_resolution/main.rk index 5faea77a..1c29f982 100644 --- a/src/lib/testcases/mods/nested_trait_resolution/main.rk +++ b/src/lib/testcases/mods/nested_trait_resolution/main.rk @@ -1,7 +1,6 @@ mod _std -use _std::|> -use _std::+ +use _std::* f a = a + 2 main = 40 |> f diff --git a/src/lib/testcases/mods/unused_fn/main.rk b/src/lib/testcases/mods/unused_fn/main.rk index 84cc01ce..5b8c85f1 100644 --- a/src/lib/testcases/mods/unused_fn/main.rk +++ b/src/lib/testcases/mods/unused_fn/main.rk @@ -1,8 +1,6 @@ mod _std -use _std::+ use _std::* -use _std::- test g h = g diff --git a/src/lib/testcases/mods/unused_impl_fn/main.rk b/src/lib/testcases/mods/unused_impl_fn/main.rk index 36b5c972..9ddde04d 100644 --- a/src/lib/testcases/mods/unused_impl_fn/main.rk +++ b/src/lib/testcases/mods/unused_impl_fn/main.rk @@ -1,6 +1,5 @@ mod _std -use _std::+ use _std::* test g h i j = g From 8047cd0142941aca0acc6f30ebea66a39f3125a7 Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 29 Jan 2022 05:43:51 +0100 Subject: [PATCH 45/74] no more null node_id --- src/lib/ast/tree2.rs | 8 ++++---- src/lib/parser2/mod.rs | 37 ++++++++++++++++--------------------- src/lib/ty/type.rs | 2 +- 3 files changed, 21 insertions(+), 26 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index a6ee02af..2d58a9d6 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -188,8 +188,8 @@ pub struct Use { } impl Use { - pub fn new(path: IdentifierPath) -> Self { - Self { path, node_id: 0 } + pub fn new(path: IdentifierPath, node_id: NodeId) -> Self { + Self { path, node_id } } } @@ -304,10 +304,10 @@ pub struct Identifier { } impl Identifier { - pub fn new(name: String) -> Self { + pub fn new(name: String, node_id: NodeId) -> Self { Self { name, - node_id: 0, // FIXME: should have a valid node_id ? + node_id, } } } diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index e3b4687f..a5299db8 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -30,7 +30,6 @@ mod tests; // TODO: // - add support for escaped string // - fix typing (check every types) -// - fix null node_id #[derive(Debug, Clone)] pub struct ParserCtx { @@ -238,13 +237,13 @@ pub fn parse_struct_decl(input: Parser) -> IResult { )), )), |(tag, node_id, name, _, defs)| StructDecl::new(node_id, name, defs), - )(input.clone()) + )(input) } pub fn parse_use(input: Parser) -> IResult { preceded( terminated(tag("use"), space1), - map(parse_identifier_path, Use::new), + map(tuple((parse_identity, parse_identifier_path)), |(node_id, ident)| Use::new(ident, node_id)), )(input) } @@ -257,7 +256,9 @@ pub fn parse_infix(input: Parser) -> IResult { )), )(input)?; - // let (input, node_id) = new_identity(input, &parsed_op); + let (input, pos) = position(input)?; + + let (mut input, node_id) = new_identity(input, &pos); let op = parsed_op.join(""); @@ -265,7 +266,7 @@ pub fn parse_infix(input: Parser) -> IResult { let op = Operator(Identifier { name: op, - node_id: 0, + node_id, }); Ok((input, TopLevel::new_infix(op, pred.as_i64() as u8))) @@ -379,6 +380,7 @@ pub fn parse_statement(input: Parser) -> IResult { pub fn parse_if(input: Parser) -> IResult { map( tuple(( + parse_identity, terminated(tag("if"), space1), terminated(parse_expression, space0), many1(line_ending), @@ -386,9 +388,7 @@ pub fn parse_if(input: Parser) -> IResult { parse_body, opt(tuple((line_ending, parse_else))), )), - |(if_, cond, _, _, body, else_)| { - let (_input, node_id) = new_identity(input.clone(), &if_); - + |(node_id, if_, cond, _, _, body, else_)| { If::new(node_id, cond, body, else_.map(|(_, else_)| Box::new(else_))) }, )(input.clone()) @@ -572,6 +572,7 @@ pub fn parse_native_operator( pub fn parse_struct_ctor(input: Parser) -> IResult { map( tuple(( + parse_identity, terminated(parse_type, line_ending), indent(separated_list0( line_ending, @@ -584,11 +585,8 @@ pub fn parse_struct_ctor(input: Parser) -> IResult { ), )), )), - |(name, decls)| { - // FIXME - // let (_input, node_id) = new_identity(input.clone(), &name); - - StructCtor::new(0, name, decls.into_iter().collect()) + |(node_id, name, decls)| { + StructCtor::new(node_id, name, decls.into_iter().collect()) }, )(input) } @@ -599,13 +597,11 @@ pub fn parse_unary(input: Parser) -> IResult { pub fn parse_primary(input: Parser) -> IResult { map( - tuple((parse_operand, many0(parse_secondary))), - |(op, secs)| { - let (_input, node_id) = new_identity(input.clone(), &input.clone()); - + tuple((parse_identity, parse_operand, many0(parse_secondary))), + |(node_id, op, secs)| { PrimaryExpr::new(node_id, op, secs) }, - )(input.clone()) + )(input) } pub fn parse_secondary(input: Parser) -> IResult { @@ -684,7 +680,7 @@ pub fn parse_identifier_path(input: Parser) -> IResult { separated_list1( tag("::"), alt(( - map(tag("*"), |_| Identifier::new("*".to_string())), + map(tuple((parse_identity, tag("*"))), |(node_id, _)| Identifier::new("*".to_string(), node_id)), parse_identifier, // map(parse_operator, |op| op.0), )), @@ -694,7 +690,6 @@ pub fn parse_identifier_path(input: Parser) -> IResult { } pub fn parse_identifier(input: Parser) -> IResult { - // let (input, ident_parsed) = alphanumeric1(input)?; let (input, ident_parsed) = recognize(many1(one_of("abcdefghijklmnopqrstuvwxyz_0123456789")))(input)?; @@ -844,7 +839,7 @@ pub fn parse_type(input: Parser) -> IResult { delimited(tag("["), parse_type, tag("]")), |t| Type::Primitive(PrimitiveType::Array( Box::new(t), - 0, + 0,// FIXME )), ), ))(input)?; diff --git a/src/lib/ty/type.rs b/src/lib/ty/type.rs index 4323f256..1670447c 100644 --- a/src/lib/ty/type.rs +++ b/src/lib/ty/type.rs @@ -222,7 +222,7 @@ impl From for Type { Box::new(Type::from( t.trim_matches('[').trim_matches(']').to_string(), )), - 0, + 0, // FIXME )) } else { Type::Trait(t) From 8106903d4fefa632fbbed0b27e4ae02643e4fc1d Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 29 Jan 2022 15:54:55 +0100 Subject: [PATCH 46/74] checkpoint for better parse errors --- src/lib/parser2/mod.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index a5299db8..69c176cb 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -875,12 +875,14 @@ fn parse_identity(input: Parser) -> IResult { Ok((input, node_id)) } - -/* fn parse_identity2<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> IResult, O, E> +/* +fn parse_identity2<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> IResult, O, E> where F: nom::Parser, O, E>, { move |mut input: Parser<'a>| { + let (input, pos) = position(input)?; + let (mut input, output) = parser.parse(input)?; let (input, node_id) = new_identity(input, &output); From 0d6635c9a9daa72e9cffa03769051891758b974b Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Apr 2022 12:09:34 +0200 Subject: [PATCH 47/74] new Resolver compiles but not tested yet --- src/lib/ast/mod.rs | 2 + src/lib/ast/tree2.rs | 36 ++- src/lib/ast/visit2.rs | 304 ++++++++++++++++++++++++++ src/lib/diagnostics/diagnostic.rs | 14 ++ src/lib/parser/parsing_context.rs | 3 +- src/lib/parser2/mod.rs | 178 ++++++++------- src/lib/parser2/tests.rs | 2 + src/lib/resolver2/mod.rs | 48 ++++ src/lib/resolver2/resolution_map.rs | 57 +++++ src/lib/resolver2/resolve_ctx.rs | 298 +++++++++++++++++++++++++ src/lib/resolver2/unused_collector.rs | 111 ++++++++++ src/lib/rock.rs | 13 +- 12 files changed, 966 insertions(+), 100 deletions(-) create mode 100644 src/lib/ast/visit2.rs create mode 100644 src/lib/resolver2/mod.rs create mode 100644 src/lib/resolver2/resolution_map.rs create mode 100644 src/lib/resolver2/resolve_ctx.rs create mode 100644 src/lib/resolver2/unused_collector.rs diff --git a/src/lib/ast/mod.rs b/src/lib/ast/mod.rs index 7609dabb..a12b7593 100644 --- a/src/lib/ast/mod.rs +++ b/src/lib/ast/mod.rs @@ -8,10 +8,12 @@ pub mod span_collector; mod tree; pub mod tree2; pub mod visit; +pub mod visit2; pub use identity::*; pub use tree::*; pub use visit::*; +// pub use visit2; // TODO: Make it the same way as HirId and FnBodyId ? pub type NodeId = u64; diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index 2d58a9d6..9cf26ace 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -1,14 +1,10 @@ -use std::{collections::HashMap, str::FromStr}; - -use nom::Finish; +use std::collections::HashMap; use crate::{ ast::NodeId, helpers::*, parser::span2::Span, - parser2::create_parser, - parser2::parse_root, - resolver::ResolutionMap, + resolver2::ResolutionMap, ty::{FuncType, Type}, }; @@ -199,7 +195,7 @@ pub struct FunctionDecl { // pub mangled_name: Option, pub arguments: Vec, pub body: Body, - // pub node_id: NodeId, + pub node_id: NodeId, pub signature: FuncType, } @@ -305,10 +301,7 @@ pub struct Identifier { impl Identifier { pub fn new(name: String, node_id: NodeId) -> Self { - Self { - name, - node_id, - } + Self { name, node_id } } } @@ -559,6 +552,13 @@ impl Expression { Expression::NativeOperation(operator, id1, id2) } + pub fn as_identifier(&self) -> Option<&Identifier> { + match self { + Expression::UnaryExpr(unary) => unary.as_identifier(), + _ => None, + } + } + // #[allow(dead_code)] // pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> Expression { // Expression { @@ -632,6 +632,13 @@ impl UnaryExpr { pub fn new_primary(primary: PrimaryExpr) -> UnaryExpr { UnaryExpr::PrimaryExpr(primary) } + + pub fn as_identifier(&self) -> Option<&Identifier> { + match self { + UnaryExpr::PrimaryExpr(primary) => primary.as_identifier(), + _ => None, + } + } } #[derive(Debug, Clone, PartialEq)] @@ -685,6 +692,13 @@ impl PrimaryExpr { }, } } + + pub fn as_identifier(&self) -> Option<&Identifier> { + match &self.op { + Operand::Identifier(id) => Some(id.path.last().unwrap()), + _ => None, + } + } } // #[derive(Debug, Clone)] diff --git a/src/lib/ast/visit2.rs b/src/lib/ast/visit2.rs new file mode 100644 index 00000000..4c3b17e4 --- /dev/null +++ b/src/lib/ast/visit2.rs @@ -0,0 +1,304 @@ +use paste::paste; + +use crate::ast::tree2::*; +use crate::ty::*; + +macro_rules! generate_visitor_trait { + ($( + $name:ty + )+) => { + pub trait Visitor<'ast>: Sized { + fn visit_name(&mut self, _name: &str) {} + + fn visit_primitive(&mut self, _val: T) + where + T: std::fmt::Debug, + {} + + paste! { + $( + fn [](&mut self, node: &'ast $name) { + [](self, node); + } + )+ + } + } + }; +} + +generate_visitor_trait!( + Root + Mod + TopLevel + Assign + AssignLeftSide + Prototype + Use + Trait + Impl + FunctionDecl + StructDecl + Identifier + IdentifierPath + // ArgumentDecl + Body + Statement + For + ForIn + While + Expression + If + Else + UnaryExpr + Operator + PrimaryExpr + SecondaryExpr + Operand + Argument + Literal + StructCtor + Array + NativeOperator + FuncType + Type +); + +pub fn walk_root<'a, V: Visitor<'a>>(visitor: &mut V, root: &'a Root) { + visitor.visit_mod(&root.r#mod); +} + +pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, _mod: &'a Mod) { + walk_list!(visitor, visit_top_level, &_mod.top_levels); +} + +pub fn walk_top_level<'a, V: Visitor<'a>>(visitor: &mut V, top_level: &'a TopLevel) { + match &top_level { + TopLevel::Prototype(p) => visitor.visit_prototype(p), + TopLevel::Use(u) => visitor.visit_use(u), + TopLevel::Trait(t) => visitor.visit_trait(t), + TopLevel::Impl(i) => visitor.visit_impl(i), + TopLevel::Struct(i) => visitor.visit_struct_decl(i), + TopLevel::Mod(name, m) => { + visitor.visit_identifier(name); + visitor.visit_mod(m); + } + TopLevel::Function(f) => visitor.visit_function_decl(f), + TopLevel::Infix(ident, _) => visitor.visit_operator(ident), + }; +} + +pub fn walk_struct_decl<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructDecl) { + visitor.visit_type(&s.name); + + walk_list!(visitor, visit_prototype, &s.defs); +} + +pub fn walk_trait<'a, V: Visitor<'a>>(visitor: &mut V, t: &'a Trait) { + visitor.visit_type(&t.name); + + walk_list!(visitor, visit_type, &t.types); + + walk_list!(visitor, visit_prototype, &t.defs); +} + +pub fn walk_impl<'a, V: Visitor<'a>>(visitor: &mut V, i: &'a Impl) { + visitor.visit_type(&i.name); + + walk_list!(visitor, visit_type, &i.types); + + walk_list!(visitor, visit_function_decl, &i.defs); +} + +pub fn walk_prototype<'a, V: Visitor<'a>>(visitor: &mut V, prototype: &'a Prototype) { + visitor.visit_identifier(&prototype.name); + + visitor.visit_func_type(&prototype.signature); +} + +pub fn walk_use<'a, V: Visitor<'a>>(visitor: &mut V, r#use: &'a Use) { + visitor.visit_identifier_path(&r#use.path); +} + +pub fn walk_function_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_decl: &'a FunctionDecl) { + visitor.visit_identifier(&function_decl.name); + + walk_list!(visitor, visit_identifier, &function_decl.arguments); + + visitor.visit_body(&function_decl.body); +} + +pub fn walk_identifier_path<'a, V: Visitor<'a>>( + visitor: &mut V, + identifier_path: &'a IdentifierPath, +) { + walk_list!(visitor, visit_identifier, &identifier_path.path); +} + +pub fn walk_identifier<'a, V: Visitor<'a>>(visitor: &mut V, identifier: &'a Identifier) { + visitor.visit_name(&identifier.name); +} + +/* pub fn walk_argument_decl<'a, V: Visitor<'a>>(visitor: &mut V, argument: &'a ArgumentDecl) { + visitor.visit_name(&argument.name); +} */ + +pub fn walk_body<'a, V: Visitor<'a>>(visitor: &mut V, body: &'a Body) { + walk_list!(visitor, visit_statement, &body.stmts); +} + +pub fn walk_statement<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Statement) { + match &statement { + Statement::Expression(expr) => visitor.visit_expression(expr), + Statement::Assign(assign) => visitor.visit_assign(assign), + Statement::If(expr) => visitor.visit_if(expr), + Statement::For(for_loop) => visitor.visit_for(for_loop), + } +} + +pub fn walk_for<'a, V: Visitor<'a>>(visitor: &mut V, for_loop: &'a For) { + match for_loop { + For::In(for_in) => visitor.visit_for_in(for_in), + For::While(while_loop) => visitor.visit_while(while_loop), + } +} + +pub fn walk_for_in<'a, V: Visitor<'a>>(visitor: &mut V, for_in: &'a ForIn) { + visitor.visit_identifier(&for_in.value); + visitor.visit_expression(&for_in.expr); + visitor.visit_body(&for_in.body); +} + +pub fn walk_while<'a, V: Visitor<'a>>(visitor: &mut V, while_loop: &'a While) { + visitor.visit_expression(&while_loop.predicat); + visitor.visit_body(&while_loop.body); +} + +pub fn walk_assign_left_side<'a, V: Visitor<'a>>(visitor: &mut V, assign_left: &'a AssignLeftSide) { + match assign_left { + AssignLeftSide::Identifier(id) => visitor.visit_expression(id), + AssignLeftSide::Indice(expr) => visitor.visit_expression(expr), + AssignLeftSide::Dot(expr) => visitor.visit_expression(expr), + } +} + +pub fn walk_assign<'a, V: Visitor<'a>>(visitor: &mut V, assign: &'a Assign) { + visitor.visit_assign_left_side(&assign.name); + visitor.visit_expression(&assign.value); +} + +pub fn walk_if<'a, V: Visitor<'a>>(visitor: &mut V, r#if: &'a If) { + visitor.visit_expression(&r#if.predicat); + visitor.visit_body(&r#if.body); + if let Some(r#else) = &r#if.else_ { + visitor.visit_else(r#else); + } +} + +pub fn walk_else<'a, V: Visitor<'a>>(visitor: &mut V, r#else: &'a Else) { + match r#else { + Else::If(expr) => visitor.visit_if(expr), + Else::Body(expr) => visitor.visit_body(expr), + } +} + +pub fn walk_expression<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a Expression) { + match &expr { + Expression::BinopExpr(unary, operator, expr) => { + visitor.visit_unary_expr(unary); + visitor.visit_operator(operator); + visitor.visit_expression(&*expr); + } + Expression::UnaryExpr(unary) => visitor.visit_unary_expr(unary), + Expression::StructCtor(ctor) => visitor.visit_struct_ctor(ctor), + Expression::NativeOperation(op, left, right) => { + visitor.visit_identifier(left); + visitor.visit_identifier(right); + visitor.visit_native_operator(op); + } + Expression::Return(expr) => { + visitor.visit_expression(expr); + } + } +} + +pub fn walk_struct_ctor<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructCtor) { + visitor.visit_type(&s.name); + + walk_map!(visitor, visit_expression, &s.defs); +} + +pub fn walk_unary_expr<'a, V: Visitor<'a>>(visitor: &mut V, unary: &'a UnaryExpr) { + match unary { + UnaryExpr::PrimaryExpr(primary) => visitor.visit_primary_expr(primary), + UnaryExpr::UnaryExpr(op, unary) => { + visitor.visit_operator(op); + visitor.visit_unary_expr(&*unary); + } + } +} + +pub fn walk_primary_expr<'a, V: Visitor<'a>>(visitor: &mut V, primary: &'a PrimaryExpr) { + visitor.visit_operand(&primary.op); + + if let Some(secondaries) = &primary.secondaries { + walk_list!(visitor, visit_secondary_expr, secondaries); + } +} + +pub fn walk_secondary_expr<'a, V: Visitor<'a>>(visitor: &mut V, secondary: &'a SecondaryExpr) { + match secondary { + SecondaryExpr::Arguments(args) => { + walk_list!(visitor, visit_argument, args); + } + SecondaryExpr::Indice(expr) => { + visitor.visit_expression(expr); + } + SecondaryExpr::Dot(expr) => { + visitor.visit_identifier(expr); + } + } +} + +pub fn walk_operator<'a, V: Visitor<'a>>(visitor: &mut V, operator: &'a Operator) { + visitor.visit_identifier(&operator.0) +} + +pub fn walk_operand<'a, V: Visitor<'a>>(visitor: &mut V, operand: &'a Operand) { + match &operand { + Operand::Literal(l) => visitor.visit_literal(l), + Operand::Identifier(i) => visitor.visit_identifier_path(i), + Operand::Expression(e) => visitor.visit_expression(&*e), + } +} + +pub fn walk_argument<'a, V: Visitor<'a>>(visitor: &mut V, argument: &'a Argument) { + visitor.visit_unary_expr(&argument.arg); +} + +pub fn walk_literal<'a, V: Visitor<'a>>(visitor: &mut V, literal: &'a Literal) { + match &literal.kind { + LiteralKind::Number(n) => visitor.visit_primitive(n), + LiteralKind::Float(f) => visitor.visit_primitive(f), + LiteralKind::String(s) => visitor.visit_primitive(s), + LiteralKind::Bool(b) => visitor.visit_primitive(b), + LiteralKind::Array(arr) => visitor.visit_array(arr), + } +} + +pub fn walk_array<'a, V: Visitor<'a>>(visitor: &mut V, arr: &'a Array) { + walk_list!(visitor, visit_expression, &arr.values); +} + +pub fn walk_native_operator<'a, V: Visitor<'a>>(_visitor: &mut V, _operator: &'a NativeOperator) { + // Nothing to do +} + +pub fn walk_func_type<'a, V: Visitor<'a>>(visitor: &mut V, signature: &'a FuncType) { + walk_list!(visitor, visit_type, &signature.arguments); + + visitor.visit_type(&signature.ret); +} + +pub fn walk_type<'a, V: Visitor<'a>>(_visitor: &mut V, _t: &'a Type) { + // Nothing to do +} diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index e019e123..1b8c1039 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -8,6 +8,7 @@ use crate::{ ty::{FuncType, Type}, }; use colored::*; +use nom::error::VerboseError; #[derive(Clone, Debug)] pub struct Diagnostic { @@ -283,3 +284,16 @@ impl<'a> From> for Diagnostic { Diagnostic::new_syntax_error(span, msg) } } + +impl<'a> From>> for Diagnostic { + fn from(err: VerboseError>) -> Self { + let (input, kind) = err.errors.into_iter().next().unwrap(); + + let span2 = Span2::from(input); + let span = Span::from(span2); + + let msg = "Syntax error".to_string(); + + Diagnostic::new_syntax_error(span, msg) + } +} diff --git a/src/lib/parser/parsing_context.rs b/src/lib/parser/parsing_context.rs index 961e6e10..fa214f7c 100644 --- a/src/lib/parser/parsing_context.rs +++ b/src/lib/parser/parsing_context.rs @@ -6,7 +6,7 @@ use std::{ use colored::*; use crate::{ - ast::{ast_print::AstPrintContext, Identifier, Root}, + ast::{ast_print::AstPrintContext, identity2::Identity, Identifier, Root, NodeId}, diagnostics::{Diagnostic, DiagnosticType, Diagnostics}, Config, }; @@ -20,6 +20,7 @@ pub struct ParsingCtx { pub current_file: Option, pub diagnostics: Diagnostics, pub operators_list: HashMap, + pub identities: HashMap, } impl ParsingCtx { diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 69c176cb..74b84e92 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -3,14 +3,11 @@ use std::collections::HashMap; use std::path::PathBuf; use nom::branch::alt; -use nom::bytes::complete::escaped; use nom::bytes::complete::{tag, take_while}; -use nom::character::complete::anychar; -use nom::character::complete::{ - alphanumeric0, alphanumeric1, char, line_ending, one_of, satisfy, space0, space1, -}; -use nom::combinator::{eof, map, not, opt, peek, recognize}; -use nom::error::{Error, ErrorKind}; +use nom::character::complete::{alphanumeric0, char, line_ending, one_of, satisfy, space0, space1}; +use nom::combinator::{eof, map, opt, peek, recognize}; +use nom::error::{make_error, ErrorKind, VerboseError}; +use nom::error_position; use nom::multi::{many0, many1, separated_list0, separated_list1}; use nom::sequence::{delimited, preceded, terminated, tuple}; use nom::{error::ParseError, Err, IResult}; @@ -19,11 +16,13 @@ use crate::ast::identity2::Identity; use crate::ast::tree2::*; use crate::ast::NodeId; use crate::parser::span2::Span; -use crate::ty::{FuncType, Type, PrimitiveType}; +use crate::ty::{FuncType, PrimitiveType, Type}; use nom_locate::{position, LocatedSpan}; pub type Parser<'a> = LocatedSpan<&'a str, ParserCtx>; +type Res = IResult>; + #[cfg(test)] mod tests; @@ -118,6 +117,13 @@ impl ParserCtx { new } */ + + pub fn identities(&self) -> HashMap { + self.identities + .iter() + .map(|identity| (identity.node_id, identity.clone())) + .collect() + } } pub fn create_parser(s: &str) -> Parser<'_> { @@ -128,12 +134,12 @@ pub fn create_parser_with_filename(s: &str, path: PathBuf) -> Parser<'_> { LocatedSpan::new_extra(s, ParserCtx::new(path)) } -pub fn parse_root(input: Parser) -> IResult { +pub fn parse_root(input: Parser) -> Res { // TODO: move eof check in parse_mod map(terminated(parse_mod, eof), Root::new)(input) } -pub fn parse_mod(input: Parser) -> IResult { +pub fn parse_mod(input: Parser) -> Res { map( many1(terminated( parse_top_level, @@ -143,7 +149,7 @@ pub fn parse_mod(input: Parser) -> IResult { )(input) } -pub fn parse_top_level(input: Parser) -> IResult { +pub fn parse_top_level(input: Parser) -> Res { alt(( preceded( terminated(tag("extern"), space1), @@ -159,13 +165,13 @@ pub fn parse_top_level(input: Parser) -> IResult { ))(input) } -pub fn parse_comment(input: Parser) -> IResult { +pub fn parse_comment(input: Parser) -> Res { let (input, _) = tuple((tag("#"), many0(satisfy(|c: char| c != '\n'))))(input)?; Ok((input, ())) } -pub fn parse_mod_decl(input: Parser) -> IResult { +pub fn parse_mod_decl(input: Parser) -> Res { let (mut input, mod_name) = preceded(terminated(tag("mod"), space1), parse_identifier)(input)?; let new_ctx = input.extra.new_from(&mod_name.name); @@ -192,7 +198,7 @@ pub fn parse_mod_decl(input: Parser) -> IResult { Ok((input, (mod_name, mod_))) } -pub fn parse_trait(input: Parser) -> IResult { +pub fn parse_trait(input: Parser) -> Res { map( tuple(( terminated(tag("trait"), space1), @@ -208,7 +214,7 @@ pub fn parse_trait(input: Parser) -> IResult { )(input) } -pub fn parse_impl(input: Parser) -> IResult { +pub fn parse_impl(input: Parser) -> Res { map( tuple(( terminated(tag("impl"), space1), @@ -224,7 +230,7 @@ pub fn parse_impl(input: Parser) -> IResult { )(input) } -pub fn parse_struct_decl(input: Parser) -> IResult { +pub fn parse_struct_decl(input: Parser) -> Res { map( tuple(( terminated(tag("struct"), space1), @@ -240,14 +246,17 @@ pub fn parse_struct_decl(input: Parser) -> IResult { )(input) } -pub fn parse_use(input: Parser) -> IResult { +pub fn parse_use(input: Parser) -> Res { preceded( terminated(tag("use"), space1), - map(tuple((parse_identity, parse_identifier_path)), |(node_id, ident)| Use::new(ident, node_id)), + map( + tuple((parse_identity, parse_identifier_path)), + |(node_id, ident)| Use::new(ident, node_id), + ), )(input) } -pub fn parse_infix(input: Parser) -> IResult { +pub fn parse_infix(input: Parser) -> Res { let (mut input, (parsed_op, pred)) = preceded( terminated(tag("infix"), space1), tuple(( @@ -264,19 +273,16 @@ pub fn parse_infix(input: Parser) -> IResult { input.extra.add_operator(op.clone(), pred.as_i64() as u8); - let op = Operator(Identifier { - name: op, - node_id, - }); + let op = Operator(Identifier { name: op, node_id }); Ok((input, TopLevel::new_infix(op, pred.as_i64() as u8))) } -pub fn parse_identifier_or_operator(input: Parser) -> IResult { +pub fn parse_identifier_or_operator(input: Parser) -> Res { alt((parse_identifier, map(parse_operator, |op| op.0)))(input) } -pub fn parse_prototype(input: Parser) -> IResult { +pub fn parse_prototype(input: Parser) -> Res { map( tuple(( terminated( @@ -293,7 +299,7 @@ pub fn parse_prototype(input: Parser) -> IResult { )(input) } -pub fn parse_fn(input: Parser) -> IResult { +pub fn parse_fn(input: Parser) -> Res { map( tuple(( terminated( @@ -306,6 +312,7 @@ pub fn parse_fn(input: Parser) -> IResult { parse_body, )), |((name, arguments), body)| FunctionDecl { + node_id: name.node_id, name, body, signature: FuncType::from_args_nb(arguments.len()), @@ -333,7 +340,7 @@ where } } -pub fn parse_block_indent(input: Parser) -> IResult { +pub fn parse_block_indent(input: Parser) -> Res { let (mut input, indent) = space1(input)?; let indent_len = indent.fragment().len(); @@ -352,7 +359,7 @@ pub fn parse_block_indent(input: Parser) -> IResult { } } -pub fn parse_body(mut input: Parser) -> IResult { +pub fn parse_body(mut input: Parser) -> Res { let (input, opt_eol) = opt(line_ending)(input)?; // NOTE: should not fail if opt_eol.is_some() { @@ -368,7 +375,7 @@ pub fn parse_body(mut input: Parser) -> IResult { } } -pub fn parse_statement(input: Parser) -> IResult { +pub fn parse_statement(input: Parser) -> Res { alt(( map(parse_if, Statement::new_if), map(parse_for, Statement::new_for), @@ -377,7 +384,7 @@ pub fn parse_statement(input: Parser) -> IResult { ))(input) } -pub fn parse_if(input: Parser) -> IResult { +pub fn parse_if(input: Parser) -> Res { map( tuple(( parse_identity, @@ -394,7 +401,7 @@ pub fn parse_if(input: Parser) -> IResult { )(input.clone()) } -pub fn parse_then(input: Parser) -> IResult { +pub fn parse_then(input: Parser) -> Res { // NOTE: This is a tweek for then block that are at indent 0 (i.e. in the test files) let (input, indent) = if input.extra.first_indent.is_some() && input.extra.block_indent > 0 { parse_block_indent(input)? @@ -414,7 +421,7 @@ pub fn parse_then(input: Parser) -> IResult { } } -pub fn parse_else(input: Parser) -> IResult { +pub fn parse_else(input: Parser) -> Res { // NOTE: This is a tweek for else block that are at indent 0 (i.e. in the test files) let (input, indent) = if input.extra.first_indent.is_some() && input.extra.block_indent > 0 { parse_block_indent(input)? @@ -447,11 +454,11 @@ pub fn parse_else(input: Parser) -> IResult { } } -pub fn parse_for(input: Parser) -> IResult { +pub fn parse_for(input: Parser) -> Res { alt((map(parse_for_in, For::In), map(parse_while, For::While)))(input) } -pub fn parse_for_in(input: Parser) -> IResult { +pub fn parse_for_in(input: Parser) -> Res { map( tuple(( terminated(tag("for"), space1), @@ -464,7 +471,7 @@ pub fn parse_for_in(input: Parser) -> IResult { )(input) } -pub fn parse_while(input: Parser) -> IResult { +pub fn parse_while(input: Parser) -> Res { map( tuple(( terminated(tag("while"), space1), @@ -475,7 +482,7 @@ pub fn parse_while(input: Parser) -> IResult { )(input) } -pub fn parse_assign(input: Parser) -> IResult { +pub fn parse_assign(input: Parser) -> Res { map( tuple(( opt(terminated(tag("let"), space1)), @@ -487,9 +494,11 @@ pub fn parse_assign(input: Parser) -> IResult { )(input) } -pub fn parse_assign_left_side(input: Parser) -> IResult { +pub fn parse_assign_left_side(input: Parser) -> Res { let (input, expr) = parse_expression(input)?; + println!("{:#?}", expr); + let res = if expr.is_dot() { AssignLeftSide::Dot(expr) } else if expr.is_indice() { @@ -506,7 +515,7 @@ pub fn parse_assign_left_side(input: Parser) -> IResult Ok((input, res)) } -pub fn parse_expression(input: Parser) -> IResult { +pub fn parse_expression(input: Parser) -> Res { alt(( map( tuple(( @@ -527,7 +536,7 @@ pub fn parse_expression(input: Parser) -> IResult { pub fn parse_native_operator( input: Parser, -) -> IResult { +) -> Res { map( tuple(( preceded( @@ -569,7 +578,7 @@ pub fn parse_native_operator( )(input.clone()) } -pub fn parse_struct_ctor(input: Parser) -> IResult { +pub fn parse_struct_ctor(input: Parser) -> Res { map( tuple(( parse_identity, @@ -585,26 +594,22 @@ pub fn parse_struct_ctor(input: Parser) -> IResult { ), )), )), - |(node_id, name, decls)| { - StructCtor::new(node_id, name, decls.into_iter().collect()) - }, + |(node_id, name, decls)| StructCtor::new(node_id, name, decls.into_iter().collect()), )(input) } -pub fn parse_unary(input: Parser) -> IResult { +pub fn parse_unary(input: Parser) -> Res { map(parse_primary, UnaryExpr::new_primary)(input) } -pub fn parse_primary(input: Parser) -> IResult { +pub fn parse_primary(input: Parser) -> Res { map( tuple((parse_identity, parse_operand, many0(parse_secondary))), - |(node_id, op, secs)| { - PrimaryExpr::new(node_id, op, secs) - }, + |(node_id, op, secs)| PrimaryExpr::new(node_id, op, secs), )(input) } -pub fn parse_secondary(input: Parser) -> IResult { +pub fn parse_secondary(input: Parser) -> Res { alt(( map(parse_indice, SecondaryExpr::Indice), map(parse_dot, SecondaryExpr::Dot), @@ -612,7 +617,7 @@ pub fn parse_secondary(input: Parser) -> IResult { ))(input) } -pub fn parse_arguments(input: Parser) -> IResult { +pub fn parse_arguments(input: Parser) -> Res { alt(( map( tuple(( @@ -635,11 +640,11 @@ pub fn parse_arguments(input: Parser) -> IResult { ))(input) } -pub fn parse_argument(input: Parser) -> IResult { +pub fn parse_argument(input: Parser) -> Res { map(parse_unary, Argument::new)(input) } -pub fn parse_indice(input: Parser) -> IResult> { +pub fn parse_indice(input: Parser) -> Res> { map( tuple(( terminated(tag("["), space0), @@ -650,7 +655,7 @@ pub fn parse_indice(input: Parser) -> IResult> { )(input) } -pub fn parse_dot(input: Parser) -> IResult { +pub fn parse_dot(input: Parser) -> Res { map( tuple(( terminated(tag("."), space0), @@ -660,7 +665,7 @@ pub fn parse_dot(input: Parser) -> IResult { )(input) } -pub fn parse_operand(input: Parser) -> IResult { +pub fn parse_operand(input: Parser) -> Res { alt(( map(parse_literal, Operand::new_literal), map(parse_identifier_path, Operand::new_identifier_path), @@ -675,12 +680,14 @@ pub fn parse_operand(input: Parser) -> IResult { ))(input) } -pub fn parse_identifier_path(input: Parser) -> IResult { +pub fn parse_identifier_path(input: Parser) -> Res { map( separated_list1( tag("::"), alt(( - map(tuple((parse_identity, tag("*"))), |(node_id, _)| Identifier::new("*".to_string(), node_id)), + map(tuple((parse_identity, tag("*"))), |(node_id, _)| { + Identifier::new("*".to_string(), node_id) + }), parse_identifier, // map(parse_operator, |op| op.0), )), @@ -689,7 +696,7 @@ pub fn parse_identifier_path(input: Parser) -> IResult { )(input) } -pub fn parse_identifier(input: Parser) -> IResult { +pub fn parse_identifier(input: Parser) -> Res { let (input, ident_parsed) = recognize(many1(one_of("abcdefghijklmnopqrstuvwxyz_0123456789")))(input)?; @@ -704,18 +711,20 @@ pub fn parse_identifier(input: Parser) -> IResult { )) } -pub fn parse_operator(input: Parser) -> IResult { +pub fn parse_operator(input: Parser) -> Res { let (input, parsed_op) = recognize(many1(one_of(LocatedSpan::new( - input - .extra - .operators() - .keys() + // We parse any accepted operators chars here, and then check if it is a valid operator later + crate::parser::accepted_operator_chars() + .iter() .cloned() - .collect::>() - .join("") + .collect::() .as_str(), ))))(input)?; + if parsed_op.to_string() == "=" { + return Err(Err::Error(error_position!(input, ErrorKind::Eof))); + } + let (input, pos) = position(input)?; let (input, node_id) = new_identity(input, &pos); @@ -729,7 +738,7 @@ pub fn parse_operator(input: Parser) -> IResult { )) } -pub fn parse_literal(input: Parser) -> IResult { +pub fn parse_literal(input: Parser) -> Res { alt(( parse_bool, parse_float, @@ -739,7 +748,7 @@ pub fn parse_literal(input: Parser) -> IResult { ))(input) } -pub fn parse_string(input: Parser) -> IResult { +pub fn parse_string(input: Parser) -> Res { map( tuple(( parse_identity, @@ -751,7 +760,7 @@ pub fn parse_string(input: Parser) -> IResult { )(input) } -pub fn parse_array(input: Parser) -> IResult { +pub fn parse_array(input: Parser) -> Res { map( tuple(( parse_identity, @@ -768,37 +777,37 @@ pub fn parse_array(input: Parser) -> IResult { )(input) } -pub fn parse_bool(input: Parser) -> IResult { +pub fn parse_bool(input: Parser) -> Res { let (input, bool_parsed) = alt((tag("true"), tag("false")))(input)?; let num: bool = bool_parsed .parse() - .map_err(|_| Err::Error(Error::new(input.clone(), ErrorKind::Alpha)))?; + .map_err(|_| Err::Error(make_error(input.clone(), ErrorKind::Alpha)))?; let (input, node_id) = new_identity(input, &bool_parsed); Ok((input, Literal::new_bool(num, node_id))) } -pub fn parse_float(input: Parser) -> IResult { +pub fn parse_float(input: Parser) -> Res { let (input, float_parsed) = recognize(tuple((parse_number, char('.'), opt(parse_number))))(input)?; let num: f64 = float_parsed .parse() - .map_err(|_| Err::Error(Error::new(input.clone(), ErrorKind::Float)))?; + .map_err(|_| Err::Error(make_error(input.clone(), ErrorKind::Digit)))?; let (input, node_id) = new_identity(input, &float_parsed); Ok((input, Literal::new_float(num, node_id))) } -pub fn parse_number(input: Parser) -> IResult { +pub fn parse_number(input: Parser) -> Res { let (input, parsed) = take_while(is_digit)(input)?; let num: i64 = parsed .parse() - .map_err(|_| Err::Error(Error::new(input.clone(), ErrorKind::Digit)))?; + .map_err(|_| Err::Error(make_error(input.clone(), ErrorKind::Digit)))?; let (input, node_id) = new_identity(input, &parsed); @@ -807,7 +816,7 @@ pub fn parse_number(input: Parser) -> IResult { // Types -pub fn parse_signature(input: Parser) -> IResult { +pub fn parse_signature(input: Parser) -> Res { let (input, parsed) = tuple(( parse_type, many0(preceded(delimited(space0, tag("->"), space0), parse_type)), @@ -825,7 +834,7 @@ pub fn parse_signature(input: Parser) -> IResult { )) } -pub fn parse_type(input: Parser) -> IResult { +pub fn parse_type(input: Parser) -> Res { let (input, ty) = alt(( map(parse_capitalized_text, Type::Trait), map( @@ -835,19 +844,18 @@ pub fn parse_type(input: Parser) -> IResult { ), |c| Type::ForAll(String::from(c)), ), - map( - delimited(tag("["), parse_type, tag("]")), - |t| Type::Primitive(PrimitiveType::Array( + map(delimited(tag("["), parse_type, tag("]")), |t| { + Type::Primitive(PrimitiveType::Array( Box::new(t), - 0,// FIXME - )), - ), + 0, // FIXME + )) + }), ))(input)?; Ok((input, ty)) } -pub fn parse_capitalized_text(input: Parser) -> IResult { +pub fn parse_capitalized_text(input: Parser) -> Res { let (input, parsed) = tuple((satisfy(char::is_uppercase), alphanumeric0))(input)?; let txt = @@ -868,7 +876,7 @@ fn new_identity<'a>(mut input: Parser<'a>, parsed: &Parser<'a>) -> (Parser<'a>, (input, node_id) } -fn parse_identity(input: Parser) -> IResult { +fn parse_identity(input: Parser) -> Res { let (input, pos) = position(input)?; let (input, node_id) = new_identity(input, &pos); @@ -876,7 +884,7 @@ fn parse_identity(input: Parser) -> IResult { Ok((input, node_id)) } /* -fn parse_identity2<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> IResult, O, E> +fn parse_identity2<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> Res, O, E> where F: nom::Parser, O, E>, { @@ -891,7 +899,7 @@ where } } */ -pub fn allowed_operator_chars(input: Parser) -> IResult { +pub fn allowed_operator_chars(input: Parser) -> Res { let (input, c) = one_of(LocatedSpan::new( crate::parser::accepted_operator_chars() .iter() diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs index 91ece10f..e95ca5ef 100644 --- a/src/lib/parser2/tests.rs +++ b/src/lib/parser2/tests.rs @@ -505,6 +505,7 @@ mod parse_fn_decl { ret: Box::new(Type::forall("a")), arguments: vec![], }, + node_id: 0, }; assert_eq!(parsed.name, expected.name); @@ -538,6 +539,7 @@ mod parse_fn_decl { node_id: 0, }, ], + node_id: 0, body: Body { stmts: vec![Statement::Expression(Box::new(Expression::BinopExpr( UnaryExpr::PrimaryExpr(PrimaryExpr { diff --git a/src/lib/resolver2/mod.rs b/src/lib/resolver2/mod.rs new file mode 100644 index 00000000..838334b2 --- /dev/null +++ b/src/lib/resolver2/mod.rs @@ -0,0 +1,48 @@ +use crate::{ + ast::{tree2::IdentifierPath, tree2::Root, visit2::*}, + diagnostics::Diagnostic, + helpers::scopes::Scopes, + parser::{ParsingCtx, Span}, +}; + +mod resolution_map; +mod resolve_ctx; +mod unused_collector; + +use std::collections::HashMap; + +pub use resolution_map::*; +pub use resolve_ctx::*; + +pub fn resolve(root: &mut Root, parsing_ctx: &mut ParsingCtx) -> Result<(), Diagnostic> { + let mut scopes = HashMap::new(); + + scopes.insert(IdentifierPath::new_root(), Scopes::new()); + + let mut ctx = ResolveCtx { + parsing_ctx, + scopes, + cur_scope: IdentifierPath::new_root(), + resolutions: ResolutionMap::default(), + }; + + ctx.visit_root(root); + + root.resolutions = ctx.resolutions; + + let (mut unused_fns, unused_methods) = unused_collector::collect_unused(root); + + for unused_fn in &unused_fns { + let identity = parsing_ctx.identities.get(unused_fn).unwrap(); + + parsing_ctx + .diagnostics + .push_warning(Diagnostic::new_unused_function(Span::from( + identity.span.clone(), + ))); + } + + unused_fns.extend(unused_methods); + + parsing_ctx.return_if_error() +} diff --git a/src/lib/resolver2/resolution_map.rs b/src/lib/resolver2/resolution_map.rs new file mode 100644 index 00000000..adb652b1 --- /dev/null +++ b/src/lib/resolver2/resolution_map.rs @@ -0,0 +1,57 @@ +use std::collections::HashMap; + +use crate::{ast::NodeId, ast_lowering::HirMap, hir::HirId}; + +#[derive(Clone, Default, Debug, Serialize, Deserialize)] +pub struct ResolutionMap(HashMap) +where + T: Eq + Clone + std::hash::Hash + Default; + +impl ResolutionMap { + pub fn insert(&mut self, pointer_id: T, pointee_id: T) { + if self.0.insert(pointer_id, pointee_id).is_some() { + debug!("Overriding resolution"); + } + } + + pub fn get(&self, pointer_id: &T) -> Option { + self.0.get(pointer_id).cloned() + } + + pub fn get_recur(&self, pointer_id: &T) -> Option { + self.get(pointer_id).and_then(|pointee_id| { + if *pointer_id == pointee_id { + warn!("Resolution loop"); + + Some(pointee_id) + } else { + self.get_recur(&pointee_id).or(Some(pointee_id)) + } + }) + } + + pub fn get_map(&self) -> HashMap { + self.0.clone() + } + + #[allow(dead_code)] + pub fn clear(&mut self) { + self.0.clear() + } + + pub fn remove(&mut self, item: &T) { + self.0.remove(item); + } +} + +impl ResolutionMap { + pub fn lower_resolution_map(&self, hir_map: &HirMap) -> ResolutionMap { + ResolutionMap( + self.0 + .iter() + // FIXME: Code smell, we silently delete unknown references + .filter_map(|(k, v)| Some((hir_map.get_hir_id(*k)?, hir_map.get_hir_id(*v)?))) + .collect(), + ) + } +} diff --git a/src/lib/resolver2/resolve_ctx.rs b/src/lib/resolver2/resolve_ctx.rs new file mode 100644 index 00000000..c4278cd7 --- /dev/null +++ b/src/lib/resolver2/resolve_ctx.rs @@ -0,0 +1,298 @@ +use std::collections::HashMap; + +use crate::{ + ast::{tree2::*, visit2::*, NodeId}, + diagnostics::Diagnostic, + helpers::scopes::*, + parser::span2::Span as Span2, + parser::ParsingCtx, + resolver2::ResolutionMap, +}; + +#[derive(Debug)] +pub struct ResolveCtx<'a> { + pub parsing_ctx: &'a mut ParsingCtx, + pub scopes: HashMap>, // + pub cur_scope: IdentifierPath, + pub resolutions: ResolutionMap, +} + +impl<'a> ResolveCtx<'a> { + pub fn add_to_current_scope(&mut self, name: String, node_id: NodeId) { + if let Some(ref mut scopes) = self.scopes.get_mut(&self.cur_scope) { + scopes.add(name, node_id); + } + } + + pub fn new_mod(&mut self, name: IdentifierPath) { + self.scopes.insert(name.clone(), Scopes::new()); + + self.cur_scope = name; + } + + pub fn push_scope(&mut self) { + if let Some(ref mut scopes) = self.scopes.get_mut(&self.cur_scope) { + scopes.push(); + } + } + + pub fn pop_scope(&mut self) { + if let Some(ref mut scopes) = self.scopes.get_mut(&self.cur_scope) { + scopes.pop(); + } + } + + pub fn get(&mut self, name: String) -> Option { + match self.scopes.get_mut(&self.cur_scope) { + Some(ref mut scopes) => scopes.get(name), + None => None, + } + } + + pub fn get_span2(&self, node_id: NodeId) -> Span2 { + self.parsing_ctx + .identities + .get(&node_id) + .unwrap() + .span + .clone() + } +} + +impl<'a> Visitor<'a> for ResolveCtx<'a> { + fn visit_mod(&mut self, m: &'a Mod) { + // We add every top level first + for top in &m.top_levels { + match &top { + TopLevel::Prototype(p) => { + self.add_to_current_scope((*p.name).clone(), p.node_id); + } + TopLevel::Use(_u) => (), + TopLevel::Trait(t) => { + for proto in &t.defs { + self.add_to_current_scope((*proto.name).clone(), proto.node_id); + } + } + TopLevel::Struct(s) => { + self.add_to_current_scope(s.name.get_name(), s.node_id); + + s.defs.iter().for_each(|p| { + self.add_to_current_scope((*p.name).clone(), p.node_id); + }) + } + TopLevel::Impl(i) => { + for proto in &i.defs { + let mut proto = proto.clone(); + + proto.mangle(&i.types.iter().map(|t| t.get_name()).collect::>()); + + self.add_to_current_scope((*proto.name).clone(), proto.node_id); + } + } + TopLevel::Mod(_, _m) => (), + TopLevel::Infix(_, _) => (), + TopLevel::Function(f) => { + self.add_to_current_scope((*f.name).clone(), f.node_id); + } + } + } + + walk_list!(self, visit_top_level, &m.top_levels); + } + + // fn visit_for(&mut self, for_loop: &'a For) { + // self.visit_expression(&for_loop.expr); + // self.visit_body(&for_loop.body); + // } + + fn visit_for_in(&mut self, for_in: &'a ForIn) { + self.visit_expression(&for_in.expr); + + self.add_to_current_scope(for_in.value.name.clone(), for_in.value.node_id); + + self.visit_body(&for_in.body); + } + + fn visit_assign(&mut self, assign: &'a Assign) { + self.visit_expression(&assign.value); + + match &assign.name { + AssignLeftSide::Identifier(id) => { + let ident = id.as_identifier().unwrap(); + + if !assign.is_let { + if let Some(previous_assign_node_id) = self.get(ident.name.clone()) { + self.resolutions + .insert(ident.node_id, previous_assign_node_id); + } + + self.visit_identifier(ident) + } + + self.add_to_current_scope(ident.name.clone(), ident.node_id); + } + AssignLeftSide::Indice(expr) => self.visit_expression(expr), + AssignLeftSide::Dot(expr) => self.visit_expression(expr), + } + } + + fn visit_top_level(&mut self, top: &'a TopLevel) { + match &top { + TopLevel::Prototype(p) => self.visit_prototype(p), + TopLevel::Use(u) => { + self.visit_use(u); + } + TopLevel::Infix(_, _) => (), + TopLevel::Trait(t) => self.visit_trait(t), + TopLevel::Impl(i) => self.visit_impl(i), + TopLevel::Struct(s) => self.visit_struct_decl(s), + TopLevel::Function(f) => self.visit_function_decl(f), + TopLevel::Mod(name, m) => { + let current_mod = self.cur_scope.clone(); + + self.new_mod(self.cur_scope.child(name.clone())); + + self.visit_mod(m); + + self.cur_scope = current_mod; + } + }; + } + + fn visit_struct_decl(&mut self, s: &'a StructDecl) { + self.push_scope(); + + walk_struct_decl(self, s); + + self.pop_scope() + } + + fn visit_struct_ctor(&mut self, s: &'a StructCtor) { + match self.get(s.name.get_name()) { + Some(pointed) => self.resolutions.insert(s.node_id, pointed), + None => self + .parsing_ctx + .diagnostics + .push_error(Diagnostic::new_unknown_identifier( + self.get_span2(s.node_id).into(), + )), + }; + + self.visit_type(&s.name); + + walk_struct_ctor(self, s); + } + + fn visit_function_decl(&mut self, f: &'a FunctionDecl) { + self.push_scope(); + + walk_function_decl(self, f); + + self.pop_scope(); + } + + fn visit_use(&mut self, r#use: &'a Use) { + let ident = r#use.path.last_segment_ref(); + + if r#use.path.path.len() == 1 { + panic!("Unimplemented"); + } + + let mut mod_path = r#use.path.parent().prepend_mod(self.cur_scope.clone()); + + mod_path.resolve_supers(); + + match self.scopes.get(&mod_path) { + Some(scopes) => { + if ident.name == "*" { + let scope = scopes.scopes.get(0).unwrap(); + + for (k, v) in &scope.items.clone() { + self.add_to_current_scope(k.clone(), v.clone()); + } + } else { + match scopes.get((*ident).to_string()) { + Some(pointed) => { + self.add_to_current_scope((*ident).name.clone(), pointed); + } + None => self.parsing_ctx.diagnostics.push_error( + Diagnostic::new_unknown_identifier( + self.get_span2(ident.node_id).into(), + ), + ), + }; + } + } + + None => self + .parsing_ctx + .diagnostics + .push_error(Diagnostic::new_module_not_found( + self.get_span2(ident.node_id).into(), + mod_path + .path + .iter() + .map(|p| p.name.clone()) + .collect::>() + .join("/"), + )), + }; + } + + /* fn visit_argument_decl(&mut self, arg: &'a ArgumentDecl) { + self.add_to_current_scope(arg.name.clone(), arg.node_id); + } + */ + fn visit_identifier_path(&mut self, path: &'a IdentifierPath) { + let ident = path.last_segment_ref(); + + if path.path.len() == 1 { + self.visit_identifier(ident); + + return; + } + + let mut mod_path = path.parent().prepend_mod(self.cur_scope.clone()); + + mod_path.resolve_supers(); + + match self.scopes.get(&mod_path) { + Some(scopes) => match scopes.get((*ident).to_string()) { + Some(pointed) => self.resolutions.insert(ident.node_id, pointed), + None => { + self.parsing_ctx + .diagnostics + .push_error(Diagnostic::new_unknown_identifier( + self.get_span2(ident.node_id).into(), + )) + } + }, + + // TODO: change to Unknown Mod diagnostic + None => self + .parsing_ctx + .diagnostics + .push_error(Diagnostic::new_module_not_found( + self.get_span2(ident.node_id).into(), + mod_path + .path + .iter() + .map(|p| p.name.clone()) + .collect::>() + .join("/"), + )), + }; + } + + fn visit_identifier(&mut self, id: &'a Identifier) { + match self.get((*id).to_string()) { + Some(pointed) => self.resolutions.insert(id.node_id, pointed), + None => self + .parsing_ctx + .diagnostics + .push_error(Diagnostic::new_unknown_identifier( + self.get_span2(id.node_id).into(), + )), + }; + } +} diff --git a/src/lib/resolver2/unused_collector.rs b/src/lib/resolver2/unused_collector.rs new file mode 100644 index 00000000..54e1a2e4 --- /dev/null +++ b/src/lib/resolver2/unused_collector.rs @@ -0,0 +1,111 @@ +use std::collections::HashMap; + +use crate::{ + ast::{tree2::*, visit2::*, NodeId}, + resolver2::ResolutionMap, +}; + +#[derive(Debug, Default)] +pub struct UnusedCollector { + resolutions: ResolutionMap, + fn_list: HashMap, + method_list: HashMap, +} + +impl UnusedCollector { + pub fn new(resolutions: ResolutionMap) -> Self { + Self { + resolutions, + ..Default::default() + } + } + + // (fns, methods) + pub fn take_unused(self) -> (Vec, Vec) { + ( + self.fn_list + .into_iter() + .filter_map(|(id, used)| if !used { Some(id) } else { None }) + .collect(), + self.method_list + .into_iter() + .filter_map(|(id, used)| if !used { Some(id) } else { None }) + .collect(), + ) + } +} + +impl<'a> Visitor<'a> for UnusedCollector { + fn visit_mod(&mut self, m: &'a Mod) { + // We add every top level first + + for top in &m.top_levels { + match &top { + TopLevel::Prototype(_p) => {} + TopLevel::Use(_u) => (), + TopLevel::Trait(t) => { + for f in &t.defs { + self.method_list.insert(f.node_id, false); + } + } + TopLevel::Impl(_i) => {} + TopLevel::Struct(_s) => {} + TopLevel::Mod(_, _m) => (), + TopLevel::Infix(_, _) => (), + TopLevel::Function(f) => { + self.fn_list.insert(f.node_id, false); + + if f.name.name == *"main" { + self.fn_list.insert(f.node_id, true); + } + } + } + } + + walk_list!(self, visit_top_level, &m.top_levels); + } + + fn visit_top_level(&mut self, top_level: &'a TopLevel) { + match &top_level { + TopLevel::Prototype(p) => self.visit_prototype(p), + TopLevel::Use(_u) => (), + TopLevel::Trait(t) => self.visit_trait(t), + TopLevel::Impl(i) => self.visit_impl(i), + TopLevel::Struct(i) => self.visit_struct_decl(i), + TopLevel::Mod(name, m) => { + self.visit_identifier(name); + self.visit_mod(m); + } + TopLevel::Function(f) => self.visit_function_decl(f), + TopLevel::Infix(_ident, _) => (), + }; + } + + fn visit_prototype(&mut self, prototype: &'a Prototype) { + self.visit_func_type(&prototype.signature); + } + + fn visit_function_decl(&mut self, f: &'a FunctionDecl) { + walk_list!(self, visit_identifier, &f.arguments); + + self.visit_body(&f.body); + } + + fn visit_identifier(&mut self, id: &'a Identifier) { + if let Some(reso) = self.resolutions.get_recur(&id.node_id) { + if let Some(used) = self.fn_list.get_mut(&reso) { + *used = true; + } else if let Some(used) = self.method_list.get_mut(&reso) { + *used = true; + } + } + } +} + +pub fn collect_unused(root: &Root) -> (Vec, Vec) { + let mut unused_collector = UnusedCollector::new(root.resolutions.clone()); + + unused_collector.visit_root(root); + + unused_collector.take_unused() +} diff --git a/src/lib/rock.rs b/src/lib/rock.rs index a22fedd3..f043de83 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -1,4 +1,4 @@ -#![feature(associated_type_bounds, destructuring_assignment, derive_default_enum)] +#![feature(associated_type_bounds, derive_default_enum)] #[macro_use] extern crate serde_derive; @@ -29,6 +29,7 @@ mod hir; mod parser; mod parser2; mod resolver; +mod resolver2; mod tests; mod ty; @@ -79,9 +80,13 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result Ok(ast), + Ok((ctx, ast)) => { + parsing_ctx.identities = ctx.extra.identities(); + + Ok(ast) + } Err(e) => { - let diagnostic = Diagnostic::from(e.input); + let diagnostic = Diagnostic::from(e); parsing_ctx.diagnostics.push_error(diagnostic.clone()); @@ -89,6 +94,8 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result Parsing"); let mut ast = parser::parse_root(parsing_ctx)?; From ef875d8a8bb886b2b91f5c7514b98d8bbad72242 Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Apr 2022 12:39:09 +0200 Subject: [PATCH 48/74] New resolver seems ok. need more tests. --- src/lib/diagnostics/diagnostic.rs | 2 +- src/lib/parser2/mod.rs | 2 -- src/lib/resolver2/resolve_ctx.rs | 8 +++++++- src/lib/rock.rs | 11 ++++++++--- 4 files changed, 16 insertions(+), 7 deletions(-) diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index 1b8c1039..fd3713dc 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -161,7 +161,7 @@ impl Diagnostic { ); let line_span_start = line_start; - let mut line_span_stop = line_start + (self.span.end - self.span.start) + 1; + let mut line_span_stop = line_start + (self.span.end - self.span.start); let line_colored = lines[line - 1].iter().cloned().collect::(); if line_span_stop > line_colored.len() { diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 74b84e92..205e38ca 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -497,8 +497,6 @@ pub fn parse_assign(input: Parser) -> Res { pub fn parse_assign_left_side(input: Parser) -> Res { let (input, expr) = parse_expression(input)?; - println!("{:#?}", expr); - let res = if expr.is_dot() { AssignLeftSide::Dot(expr) } else if expr.is_indice() { diff --git a/src/lib/resolver2/resolve_ctx.rs b/src/lib/resolver2/resolve_ctx.rs index c4278cd7..69e1d41d 100644 --- a/src/lib/resolver2/resolve_ctx.rs +++ b/src/lib/resolver2/resolve_ctx.rs @@ -186,7 +186,13 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { fn visit_function_decl(&mut self, f: &'a FunctionDecl) { self.push_scope(); - walk_function_decl(self, f); + self.visit_identifier(&f.name); + + for arg in &f.arguments { + self.add_to_current_scope(arg.name.clone(), arg.node_id); + } + + self.visit_body(&f.body); self.pop_scope(); } diff --git a/src/lib/rock.rs b/src/lib/rock.rs index f043de83..65dea1c2 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -77,12 +77,17 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { + Ok((ctx, mut ast)) => { parsing_ctx.identities = ctx.extra.identities(); + debug!(" -> Resolving"); + resolver2::resolve(&mut ast, parsing_ctx)?; + + /* // Lowering to HIR + debug!(" -> Lowering to HIR"); + let mut hir = ast_lowering2::lower_crate(&ast); */ + Ok(ast) } Err(e) => { From ea5435bf4bf678b84a0de987a5d60b5677390cf7 Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Apr 2022 13:59:44 +0200 Subject: [PATCH 49/74] Full compilation with new parser, some tests are KO --- src/lib/ast/ast_print.rs | 8 +- src/lib/ast/mod.rs | 1 + src/lib/ast/return_placement2.rs | 77 +++ src/lib/ast/tree2.rs | 28 +- src/lib/ast_lowering2/ast_lowering_context.rs | 495 ++++++++++++++++++ src/lib/ast_lowering2/hir_map.rs | 66 +++ src/lib/ast_lowering2/infix_desugar.rs | 87 +++ src/lib/ast_lowering2/loop_desugar.rs | 63 +++ src/lib/ast_lowering2/mod.rs | 13 + src/lib/hir/tree.rs | 6 +- src/lib/infer/constraint.rs | 45 +- src/lib/infer/mod.rs | 1 + src/lib/infer/monomorphize/mod.rs | 2 +- src/lib/infer/monomorphize/monomorphizer.rs | 2 +- src/lib/infer/state.rs | 10 +- src/lib/parser/mod.rs | 8 +- src/lib/parser/parser_impl.rs | 4 +- src/lib/parser/parsing_context.rs | 6 +- src/lib/parser2/mod.rs | 10 +- src/lib/resolver/resolution_map.rs | 2 +- src/lib/resolver2/resolution_map.rs | 2 +- src/lib/rock.rs | 38 +- 22 files changed, 917 insertions(+), 57 deletions(-) create mode 100644 src/lib/ast/return_placement2.rs create mode 100644 src/lib/ast_lowering2/ast_lowering_context.rs create mode 100644 src/lib/ast_lowering2/hir_map.rs create mode 100644 src/lib/ast_lowering2/infix_desugar.rs create mode 100644 src/lib/ast_lowering2/loop_desugar.rs create mode 100644 src/lib/ast_lowering2/mod.rs diff --git a/src/lib/ast/ast_print.rs b/src/lib/ast/ast_print.rs index f9b7d1b1..e91c5027 100644 --- a/src/lib/ast/ast_print.rs +++ b/src/lib/ast/ast_print.rs @@ -1,7 +1,7 @@ use std::fmt::Debug; -use crate::ast::visit::*; -use crate::ast::*; +use crate::ast::tree2::*; +use crate::ast::visit2::*; use crate::helpers::*; use crate::ty::*; use paste::paste; @@ -83,7 +83,7 @@ macro_rules! impl_visitor_trait { impl_visitor_trait!( Root - Mod + // Mod TopLevel StructDecl Use @@ -92,7 +92,7 @@ impl_visitor_trait!( Impl FunctionDecl Identifier - ArgumentDecl + // ArgumentDecl Body Statement For diff --git a/src/lib/ast/mod.rs b/src/lib/ast/mod.rs index a12b7593..4d6bb6e4 100644 --- a/src/lib/ast/mod.rs +++ b/src/lib/ast/mod.rs @@ -4,6 +4,7 @@ pub mod ast_print; mod identity; pub mod identity2; pub mod return_placement; +pub mod return_placement2; pub mod span_collector; mod tree; pub mod tree2; diff --git a/src/lib/ast/return_placement2.rs b/src/lib/ast/return_placement2.rs new file mode 100644 index 00000000..18069af7 --- /dev/null +++ b/src/lib/ast/return_placement2.rs @@ -0,0 +1,77 @@ +use crate::ast::tree2::*; + +pub struct ReturnInserter<'a> { + pub body: &'a Body, +} + +impl<'a> ReturnInserter<'a> { + pub fn run(&mut self) -> Body { + let mut body = self.body.clone(); + + self.visit_body(&mut body); + + body.clone() + } + + fn visit_body(&mut self, body: &mut Body) { + // let mut is_assign = None; + + if let Some(stmt) = body.stmts.iter_mut().last() { + // if let StatementKind::Assign(ref mut a) = *stmt.kind.clone() { + // is_assign = Some(a.clone()); + // } + + self.visit_statement(stmt); + } + + // if let Some(a) = is_assign { + // body.stmts.push(Statement { + // kind: Box::new(StatementKind::Expression(Box::new(Expression { + // kind: ExpressionKind::Return(Box::new(a.name.as_expression())), + // }))), + // }); + // } + } + + fn visit_statement(&mut self, stmt: &mut Statement) { + let mut is_assign = None; + + match *stmt { + Statement::Expression(ref mut e) => { + *e = Box::new(Expression::Return(e.clone())); + } + Statement::If(ref mut i) => { + self.visit_if(i); + } + Statement::Assign(ref mut a) => { + is_assign = Some(a.value.clone()); + } + Statement::For(ref mut _fa) => { + unimplemented!("Cannot have loop in return position"); + } + } + + // FIXME: do this only if a.name is Identifier + // or else return the ident + if let Some(value) = is_assign { + *stmt = Statement::Expression(Box::new(Expression::Return(Box::new(value)))); + } + } + + fn visit_if(&mut self, r#if: &mut If) { + self.visit_body(&mut r#if.body); + + if let Some(ref mut r#else) = r#if.else_.as_mut() { + self.visit_else(r#else); + } else { + unimplemented!("Else is not found"); + } + } + + fn visit_else(&mut self, r#else: &mut Else) { + match r#else { + Else::If(i) => self.visit_if(i), + Else::Body(b) => self.visit_body(b), + } + } +} diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index 9cf26ace..f5192c36 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -221,7 +221,7 @@ impl IdentifierPath { Self { path: vec![Identifier { name: "root".to_string(), - node_id: 0, // FIXME: should have a valid node_id ? + node_id: 42, // FIXME: should have a valid node_id ? }], } } @@ -618,16 +618,16 @@ impl UnaryExpr { } } - // pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> UnaryExpr { - // UnaryExpr::PrimaryExpr(PrimaryExpr { - // node_id: node_id::new_placeholder(), - // op, - // secondaries: Some(vec![SecondaryExpr::Arguments(vec![ - // Argument { arg: arg1 }, - // Argument { arg: arg2 }, - // ])]), - // }) - // } + pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> UnaryExpr { + UnaryExpr::PrimaryExpr(PrimaryExpr { + node_id: u64::MAX, + op, + secondaries: Some(vec![SecondaryExpr::Arguments(vec![ + Argument { arg: arg1 }, + Argument { arg: arg2 }, + ])]), + }) + } pub fn new_primary(primary: PrimaryExpr) -> UnaryExpr { UnaryExpr::PrimaryExpr(primary) @@ -676,7 +676,7 @@ impl PrimaryExpr { pub fn new_empty(op: Operand) -> PrimaryExpr { PrimaryExpr { op, - node_id: 0, + node_id: u64::MAX, secondaries: None, } } @@ -741,6 +741,10 @@ impl Operand { pub fn new_literal(lit: Literal) -> Operand { Operand::Literal(lit) } + + pub fn from_identifier(id: Identifier) -> Operand { + Operand::new_identifier(id) + } } impl Operand { diff --git a/src/lib/ast_lowering2/ast_lowering_context.rs b/src/lib/ast_lowering2/ast_lowering_context.rs new file mode 100644 index 00000000..aee4e164 --- /dev/null +++ b/src/lib/ast_lowering2/ast_lowering_context.rs @@ -0,0 +1,495 @@ +use std::collections::{BTreeMap, HashMap}; + +use crate::{ + ast::{return_placement2::ReturnInserter, tree2::*, NodeId}, + hir::{self, Arena, FnBodyId, HirId}, + infer::Envs, + ty::*, +}; + +use super::{hir_map::HirMap, InfixDesugar}; + +pub struct AstLoweringContext { + hir_map: HirMap, + top_levels: Vec, + bodies: BTreeMap, + operators_list: HashMap, + traits: HashMap, + trait_methods: HashMap>, + structs: HashMap, +} + +impl AstLoweringContext { + pub fn new(operators_list: HashMap) -> Self { + Self { + hir_map: HirMap::new(), + top_levels: Vec::new(), + bodies: BTreeMap::new(), + traits: HashMap::new(), + trait_methods: HashMap::new(), + structs: HashMap::new(), + operators_list, + } + } + + pub fn lower_root(&mut self, root: &Root) -> hir::Root { + self.lower_mod(&root.r#mod); + + let mut hir = hir::Root { + arena: Arena::new(), + hir_map: self.hir_map.clone(), + resolutions: root.resolutions.lower_resolution_map(&self.hir_map), + type_envs: Envs::default(), + node_types: BTreeMap::new(), + top_levels: self.top_levels.clone(), + bodies: self.bodies.clone(), + traits: self.traits.clone(), + trait_methods: self.trait_methods.clone(), + spans: root.spans.clone(), + structs: self.structs.clone(), + }; + + hir.arena = hir::collect_arena(&hir); + + hir + } + + pub fn lower_mod(&mut self, r#mod: &Mod) { + r#mod + .top_levels + .iter() + .for_each(|t| self.lower_top_level(t)); + } + + pub fn lower_top_level(&mut self, top_level: &TopLevel) { + match &top_level { + TopLevel::Prototype(p) => { + let top_level = hir::TopLevel { + kind: hir::TopLevelKind::Prototype(self.lower_prototype(p)), + }; + + self.top_levels.push(top_level); + } + TopLevel::Function(f) => { + let top_level = hir::TopLevel { + kind: hir::TopLevelKind::Function(self.lower_function_decl(f)), + }; + + self.top_levels.push(top_level); + } + TopLevel::Trait(t) => { + self.lower_trait(t); + } + TopLevel::Struct(s) => { + self.lower_struct_decl(s); + } + TopLevel::Impl(i) => { + self.lower_impl(i); + } + TopLevel::Mod(_name, mod_) => self.lower_mod(mod_), + TopLevel::Infix(_, _) => (), + TopLevel::Use(_u) => (), + }; + } + + pub fn lower_struct_decl(&mut self, s: &StructDecl) -> hir::StructDecl { + let hir_t = hir::StructDecl { + hir_id: self.hir_map.next_hir_id(s.node_id), + name: s.name.clone(), + defs: s + .defs + .iter() + .map(|proto| self.lower_prototype(proto)) + .collect(), + }; + + self.structs.insert(s.name.get_name(), hir_t.clone()); + + hir_t + } + + pub fn lower_trait(&mut self, t: &Trait) -> hir::Trait { + let hir_t = hir::Trait { + name: t.name.clone(), + types: t.types.clone(), + defs: t + .defs + .iter() + .map(|proto| self.lower_prototype(proto)) + .collect(), + }; + + self.traits.insert(t.name.clone(), hir_t.clone()); + + hir_t + } + + pub fn lower_impl(&mut self, i: &Impl) { + for f in &i.defs { + let mut hir_f = self.lower_function_decl(f); + + let mut types = vec![i.name.get_name()]; + types.extend(i.types.iter().map(|t| t.get_name())); + + let body = self.bodies.get_mut(&hir_f.body_id).unwrap(); + body.mangle(&types); + + let r#trait = self.traits.get(&i.name).unwrap(); + + let type_sig = r#trait + .defs + .iter() + .find(|proto| *proto.name == *hir_f.name) + .unwrap() + .signature + .clone(); + + let type_sig = type_sig.apply_forall_types(&r#trait.types, &i.types); + + hir_f.signature = type_sig.clone(); + + let fn_decls = self + .trait_methods + .entry(hir_f.name.name.clone()) + .or_insert_with(HashMap::new); + + let _hir_id = self.hir_map.next_hir_id(f.node_id); + + (*fn_decls).insert(type_sig, hir_f); + } + } + + pub fn lower_prototype(&mut self, p: &Prototype) -> hir::Prototype { + let id = self.hir_map.next_hir_id(p.node_id); + let ident = self.lower_identifier(&p.name); + + hir::Prototype { + name: ident, + signature: p.signature.clone(), + hir_id: id, + } + } + + pub fn lower_function_decl(&mut self, f: &FunctionDecl) -> hir::FunctionDecl { + let body_id = self.hir_map.next_body_id(); + let id = self.hir_map.next_hir_id(f.node_id); + let ident = self.lower_identifier(&f.name); + + let body = self.lower_fn_body(&f.body, ident.clone(), body_id.clone(), id.clone()); + + self.bodies.insert(body_id.clone(), body); + + hir::FunctionDecl { + name: ident, + mangled_name: None, + arguments: f + .arguments + .iter() + .map(|arg| self.lower_argument_decl(arg)) + .collect(), + body_id, + signature: f.signature.clone(), + hir_id: id, + } + } + + pub fn lower_argument_decl(&mut self, identifier: &Identifier) -> hir::ArgumentDecl { + let id = self.hir_map.next_hir_id(identifier.node_id); + + hir::ArgumentDecl { + name: hir::Identifier { + hir_id: id, + name: identifier.name.clone(), + }, + } + } + + pub fn lower_fn_body( + &mut self, + fn_body: &Body, + name: hir::Identifier, + body_id: FnBodyId, + fn_id: HirId, + ) -> hir::FnBody { + let body = ReturnInserter { body: fn_body }.run(); + + let body = self.lower_body(&body); + + hir::FnBody { + id: body_id, + fn_id, + name, + mangled_name: None, + body, + } + } + + pub fn lower_body(&mut self, body: &Body) -> hir::Body { + hir::Body { + stmts: body + .stmts + .iter() + .map(|stmt| self.lower_statement(stmt)) + .collect(), + } + } + + pub fn lower_statement(&mut self, stmt: &Statement) -> hir::Statement { + hir::Statement { + kind: match &*stmt { + Statement::Expression(e) => { + Box::new(hir::StatementKind::Expression(self.lower_expression(e))) + } + Statement::If(e) => Box::new(hir::StatementKind::If(self.lower_if(e))), + Statement::Assign(a) => Box::new(hir::StatementKind::Assign(self.lower_assign(a))), + Statement::For(f) => Box::new(hir::StatementKind::For(self.lower_for(f))), + }, + } + } + + pub fn lower_for(&mut self, for_loop: &For) -> hir::For { + match for_loop { + For::In(i) => hir::For::In(self.lower_for_in(i)), + For::While(w) => hir::For::While(self.lower_while(w)), + } + } + + pub fn lower_for_in(&mut self, for_in: &ForIn) -> hir::ForIn { + hir::ForIn { + value: self.lower_identifier(&for_in.value), + expr: self.lower_expression(&for_in.expr), + body: self.lower_body(&for_in.body), + } + } + + pub fn lower_while(&mut self, while_loop: &While) -> hir::While { + hir::While { + predicat: self.lower_expression(&while_loop.predicat), + body: self.lower_body(&while_loop.body), + } + } + + pub fn lower_assign_left_side(&mut self, assign_left: &AssignLeftSide) -> hir::AssignLeftSide { + match assign_left { + AssignLeftSide::Identifier(id) => { + hir::AssignLeftSide::Identifier(self.lower_identifier(id.as_identifier().unwrap())) + } + AssignLeftSide::Indice(indice) => { + let expr_hir = self.lower_expression(indice); + let indice = match &*expr_hir.kind { + hir::ExpressionKind::Indice(indice) => indice, + _ => unimplemented!( + "Assign left hand side can be Identifiers, Indices or dot notation" + ), + }; + + hir::AssignLeftSide::Indice(indice.clone()) + } + AssignLeftSide::Dot(dot) => { + let expr_hir = self.lower_expression(dot); + let dot = match &*expr_hir.kind { + hir::ExpressionKind::Dot(dot) => dot, + _ => unimplemented!( + "Assign left hand side can be Identifiers, Indices or dot notation" + ), + }; + + hir::AssignLeftSide::Dot(dot.clone()) + } + } + } + + pub fn lower_assign(&mut self, assign: &Assign) -> hir::Assign { + hir::Assign { + name: self.lower_assign_left_side(&assign.name), + value: self.lower_expression(&assign.value), + is_let: assign.is_let, + } + } + + pub fn lower_expression(&mut self, expr: &Expression) -> hir::Expression { + match &expr { + Expression::UnaryExpr(unary) => self.lower_unary(unary), + Expression::StructCtor(s) => self.lower_struct_ctor(s), + Expression::NativeOperation(op, left, right) => { + self.lower_native_operation(op, left, right) + } + Expression::BinopExpr(_unary, _op, _expr22) => { + let mut infix = InfixDesugar::new(self.operators_list.clone()); + + self.lower_expression(&infix.desugar(expr)) + } + Expression::Return(expr) => hir::Expression { + kind: Box::new(hir::ExpressionKind::Return(self.lower_expression(&*expr))), + }, + } + } + + pub fn lower_struct_ctor(&mut self, s: &StructCtor) -> hir::Expression { + hir::Expression::new_struct_ctor(hir::StructCtor { + hir_id: self.hir_map.next_hir_id(s.node_id), + name: s.name.clone(), + defs: s + .defs + .iter() + .map(|(k, expr)| (self.lower_identifier(k), self.lower_expression(expr))) + .collect(), + }) + } + + pub fn lower_if(&mut self, r#if: &If) -> hir::If { + hir::If { + hir_id: self.hir_map.next_hir_id(r#if.node_id), + predicat: self.lower_expression(&r#if.predicat), + body: self.lower_body(&r#if.body), + else_: r#if.else_.as_ref().map(|e| Box::new(self.lower_else(e))), + } + } + + pub fn lower_else(&mut self, r#else: &Else) -> hir::Else { + match r#else { + Else::If(e) => hir::Else::If(self.lower_if(e)), + Else::Body(b) => hir::Else::Body(self.lower_body(b)), + } + } + + pub fn lower_unary(&mut self, unary: &UnaryExpr) -> hir::Expression { + match &unary { + UnaryExpr::PrimaryExpr(primary) => self.lower_primary(primary), + _ => unimplemented!(), + } + } + + pub fn lower_primary(&mut self, primary: &PrimaryExpr) -> hir::Expression { + if primary.secondaries.is_none() { + return self.lower_operand(&primary.op); + } + + let mut expr = self.lower_operand(&primary.op); + + for secondary in &primary.secondaries.clone().unwrap() { + expr = self.lower_secondary(expr, secondary, primary.node_id); + } + + expr + } + + pub fn lower_operand(&mut self, operand: &Operand) -> hir::Expression { + match &operand { + Operand::Literal(l) => hir::Expression::new_literal(self.lower_literal(l)), + Operand::Identifier(i) => { + hir::Expression::new_identifier_path(self.lower_identifier_path(i)) + } + Operand::Expression(e) => self.lower_expression(&**e), + } + } + + pub fn lower_secondary( + &mut self, + op: hir::Expression, + secondary: &SecondaryExpr, + node_id: NodeId, + ) -> hir::Expression { + match secondary { + SecondaryExpr::Arguments(args) => { + hir::Expression::new_function_call(hir::FunctionCall { + hir_id: self.hir_map.next_hir_id(node_id.clone()), + op, + args: args.iter().map(|arg| self.lower_unary(&arg.arg)).collect(), + }) + } + SecondaryExpr::Indice(expr) => hir::Expression::new_indice(hir::Indice { + hir_id: self.hir_map.next_hir_id(node_id.clone()), + op, + value: self.lower_expression(expr), + }), + SecondaryExpr::Dot(expr) => hir::Expression::new_dot(hir::Dot { + hir_id: self.hir_map.next_hir_id(node_id.clone()), + op, + value: self.lower_identifier(expr), + }), + } + } + + pub fn lower_literal(&mut self, lit: &Literal) -> hir::Literal { + let hir_id = self.hir_map.next_hir_id(lit.node_id); + + hir::Literal { + hir_id, + kind: match &lit.kind { + LiteralKind::Number(n) => hir::LiteralKind::Number(*n), + LiteralKind::Float(f) => hir::LiteralKind::Float(*f), + LiteralKind::String(s) => hir::LiteralKind::String(s.clone()), + LiteralKind::Bool(b) => hir::LiteralKind::Bool(*b), + LiteralKind::Array(arr) => hir::LiteralKind::Array(self.lower_array(arr)), + }, + } + } + + pub fn lower_array(&mut self, arr: &Array) -> hir::Array { + hir::Array { + values: arr + .values + .iter() + .map(|expr| self.lower_expression(expr)) + .collect(), + } + } + + pub fn lower_identifier_path(&mut self, path: &IdentifierPath) -> hir::IdentifierPath { + hir::IdentifierPath { + path: path.path.iter().map(|i| self.lower_identifier(i)).collect(), + } + } + + pub fn lower_identifier(&mut self, id: &Identifier) -> hir::Identifier { + let hir_id = self.hir_map.next_hir_id(id.node_id); + + hir::Identifier { + hir_id, + name: id.name.clone(), + } + } + + pub fn lower_native_operation( + &mut self, + op: &NativeOperator, + left: &Identifier, + right: &Identifier, + ) -> hir::Expression { + hir::Expression::new_native_operation( + self.lower_native_operator(op), + self.lower_identifier(left), + self.lower_identifier(right), + ) + } + + pub fn lower_native_operator(&mut self, op: &NativeOperator) -> hir::NativeOperator { + let hir_id = self.hir_map.next_hir_id(op.node_id); + + let kind = match op.kind { + NativeOperatorKind::IAdd => hir::NativeOperatorKind::IAdd, + NativeOperatorKind::ISub => hir::NativeOperatorKind::ISub, + NativeOperatorKind::IMul => hir::NativeOperatorKind::IMul, + NativeOperatorKind::IDiv => hir::NativeOperatorKind::IDiv, + NativeOperatorKind::FAdd => hir::NativeOperatorKind::FAdd, + NativeOperatorKind::FSub => hir::NativeOperatorKind::FSub, + NativeOperatorKind::FMul => hir::NativeOperatorKind::FMul, + NativeOperatorKind::FDiv => hir::NativeOperatorKind::FDiv, + NativeOperatorKind::IEq => hir::NativeOperatorKind::IEq, + NativeOperatorKind::Igt => hir::NativeOperatorKind::Igt, + NativeOperatorKind::Ige => hir::NativeOperatorKind::Ige, + NativeOperatorKind::Ilt => hir::NativeOperatorKind::Ilt, + NativeOperatorKind::Ile => hir::NativeOperatorKind::Ile, + NativeOperatorKind::FEq => hir::NativeOperatorKind::FEq, + NativeOperatorKind::Fgt => hir::NativeOperatorKind::Fgt, + NativeOperatorKind::Fge => hir::NativeOperatorKind::Fge, + NativeOperatorKind::Flt => hir::NativeOperatorKind::Flt, + NativeOperatorKind::Fle => hir::NativeOperatorKind::Fle, + NativeOperatorKind::BEq => hir::NativeOperatorKind::BEq, + NativeOperatorKind::Len => hir::NativeOperatorKind::Len, + }; + + hir::NativeOperator { hir_id, kind } + } +} diff --git a/src/lib/ast_lowering2/hir_map.rs b/src/lib/ast_lowering2/hir_map.rs new file mode 100644 index 00000000..5425b785 --- /dev/null +++ b/src/lib/ast_lowering2/hir_map.rs @@ -0,0 +1,66 @@ +use std::collections::HashMap; + +use crate::{ + ast::NodeId, + hir::{FnBodyId, HirId}, +}; + +#[derive(Clone, Debug, Default, Serialize, Deserialize)] +pub struct HirMap { + map: HashMap, + rev_map: HashMap, + pub hir_id_next: u64, + pub body_id_next: u64, +} + +impl HirMap { + pub fn new() -> Self { + Self::default() + } + + pub fn next_hir_id(&mut self, node_id: NodeId) -> HirId { + let hir_id = HirId(self.hir_id_next); + + self.hir_id_next += 1; + + self.add_hir_mapping(hir_id.clone(), node_id); + + hir_id + } + + pub fn next_body_id(&mut self) -> FnBodyId { + let body_id = FnBodyId(self.body_id_next); + + self.body_id_next += 1; + + body_id + } + + pub fn get_hir_id(&self, node_id: NodeId) -> Option { + self.rev_map.get(&node_id).cloned() + } + + pub fn get_node_id(&self, hir_id: &HirId) -> Option { + self.map.get(hir_id).cloned() + } + + fn add_hir_mapping(&mut self, hir_id: HirId, node_id: NodeId) { + self.map.insert(hir_id.clone(), node_id); + + self.rev_map.insert(node_id, hir_id); + } + + pub fn duplicate_hir_mapping(&mut self, hir_id: HirId) -> Option { + let node_id = self.get_node_id(&hir_id)?; + + /* let mut fake_ident = Identity::new_placeholder(); + + fake_ident.node_id = node_id; */ + + let new_id = self.next_hir_id(node_id); + + self.add_hir_mapping(new_id.clone(), node_id); + + Some(new_id) + } +} diff --git a/src/lib/ast_lowering2/infix_desugar.rs b/src/lib/ast_lowering2/infix_desugar.rs new file mode 100644 index 00000000..c2060535 --- /dev/null +++ b/src/lib/ast_lowering2/infix_desugar.rs @@ -0,0 +1,87 @@ +use std::collections::HashMap; + +use crate::ast::tree2::{Expression, Identifier, Operand, UnaryExpr}; + +#[derive(Debug)] +pub enum ExprOrIdentifier { + Expr(UnaryExpr), + Identifier(Identifier), +} + +#[derive(Debug)] +pub struct InfixDesugar { + pub opstack: Vec, + pub output: Vec, + pub operators_list: HashMap, +} + +impl InfixDesugar { + pub fn new(operators_list: HashMap) -> Self { + InfixDesugar { + opstack: vec![], + output: vec![], + operators_list, + } + } + + pub fn desugar(&mut self, expr: &Expression) -> Expression { + self.populate_rec(expr); + + self.pop_higher_operators(0); + + self.generate_calls() + } + + pub fn generate_calls(&self) -> Expression { + let mut stack = vec![]; + for item in &self.output { + match item { + ExprOrIdentifier::Expr(expr) => stack.push(expr.clone()), + ExprOrIdentifier::Identifier(id) => { + let right = stack.pop().unwrap(); + let left = stack.pop().unwrap(); + + stack.push(UnaryExpr::create_2_args_func_call( + Operand::from_identifier(id.clone()), + left.clone(), + right.clone(), + )); + } + } + } + + Expression::new_unary(stack.pop().unwrap()) + } + + pub fn populate_rec(&mut self, expr: &Expression) { + match &expr { + Expression::BinopExpr(unary, op, expr2) => { + self.output.push(ExprOrIdentifier::Expr(unary.clone())); + + self.pop_higher_operators( + *self.operators_list.get(&op.0.name.to_string()).unwrap(), + ); + + self.opstack.push(op.0.clone()); + + self.desugar(expr2); + } + Expression::UnaryExpr(unary) => self.output.push(ExprOrIdentifier::Expr(unary.clone())), + _ => unimplemented!(), + } + } + + pub fn pop_higher_operators(&mut self, precedence: u8) { + for op in self.opstack.clone().iter().rev() { + let item_precedence = self.operators_list.get(&op.name.to_string()).unwrap(); + + if precedence <= *item_precedence { + self.opstack.pop(); + + self.output.push(ExprOrIdentifier::Identifier(op.clone())); + } else { + break; + } + } + } +} diff --git a/src/lib/ast_lowering2/loop_desugar.rs b/src/lib/ast_lowering2/loop_desugar.rs new file mode 100644 index 00000000..f0c7ba8f --- /dev/null +++ b/src/lib/ast_lowering2/loop_desugar.rs @@ -0,0 +1,63 @@ +use std::collections::HashMap; + +use crate::ast::{Expression, ExpressionKind, Identifier, Operand, Statement, UnaryExpr}; + +pub struct Loop { + pre_loop: Vec, + predicat: Expression, + pre_body: Vec, + body: Body, + post_body: Vec, +} + +#[derive(Debug)] +pub struct LoopDesugar {} + +impl LoopDesugar { + pub fn new() -> Self { + LoopDesugar {} + } + + pub fn desugar(&mut self, for_loop: &For) -> Loop { + match for_loop { + For::In(for_in) => self.desugar_for_in(&for_in), + For::While(while_loop) => self.desugar_while(&while_loop), + } + } + + // for item in arr + // do item + // + // --- becomes + // + // let i = 0 + // let arr_len = ~Len arr + // for i < arr_len + // let item = arr[i] // pre_body + // do item + // i = i + 1 // post_body + + + + fn desugar_for_in(&mut self, for_in: &ForIn) -> Loop { + let i_var = Statement::new_assign() + + Loop { + pre_loop: vec![], + predicat: (), + pre_body: vec![], + body: for_in.body.clone(), + post_body: vec![], + } + } + + fn desugar_while(&mut self, while_loop: &While) -> Loop { + Loop { + pre_loop: vec![], + predicat: while_loop.predicat.clone(), + pre_body: vec![], + body: while_loop.body.clone(), + post_body: vec![], + } + } +} diff --git a/src/lib/ast_lowering2/mod.rs b/src/lib/ast_lowering2/mod.rs new file mode 100644 index 00000000..6e67c787 --- /dev/null +++ b/src/lib/ast_lowering2/mod.rs @@ -0,0 +1,13 @@ +use crate::{ast::tree2::Root, hir}; + +mod ast_lowering_context; +mod hir_map; +mod infix_desugar; + +use ast_lowering_context::AstLoweringContext; +pub use hir_map::*; +pub use infix_desugar::*; + +pub fn lower_crate(root: &Root) -> hir::Root { + AstLoweringContext::new(root.operators_list.clone()).lower_root(root) +} diff --git a/src/lib/hir/tree.rs b/src/lib/hir/tree.rs index d6f0d270..f3e37d36 100644 --- a/src/lib/hir/tree.rs +++ b/src/lib/hir/tree.rs @@ -2,11 +2,11 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ ast::NodeId, - ast_lowering::HirMap, + ast_lowering2::HirMap, hir::hir_id::*, infer::Envs, - parser::Span, - resolver::ResolutionMap, + parser::span2::Span, + resolver2::ResolutionMap, ty::{FuncType, StructType, Type}, }; diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index 73c0c0e6..35a03876 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -5,7 +5,7 @@ use crate::{ hir::visit::*, hir::*, infer::Envs, - resolver::ResolutionMap, + resolver2::ResolutionMap, ty::{FuncType, PrimitiveType, Type}, }; @@ -97,7 +97,12 @@ impl<'a> ConstraintContext<'a> { .or_else(|| { self.envs.diagnostics.push_error( Diagnostic::new_unresolved_trait_call( - self.envs.spans.get(&call_hir_id.clone()).unwrap().clone(), + self.envs + .spans + .get(&call_hir_id.clone()) + .unwrap() + .clone() + .into(), call_hir_id.clone(), new_sig, existing_impls.keys().cloned().collect(), @@ -162,7 +167,12 @@ impl<'a> ConstraintContext<'a> { self.envs .diagnostics .push_error(Diagnostic::new_type_conflict( - self.envs.spans.get(&fc.op.get_hir_id()).unwrap().clone(), + self.envs + .spans + .get(&fc.op.get_hir_id()) + .unwrap() + .clone() + .into(), fc.to_func_type(self.envs.get_current_env().unwrap()).into(), f.signature.clone().into(), fc.to_func_type(self.envs.get_current_env().unwrap()).into(), @@ -214,7 +224,12 @@ impl<'a> ConstraintContext<'a> { self.envs .diagnostics .push_error(Diagnostic::new_type_conflict( - self.envs.spans.get(&fc.op.get_hir_id()).unwrap().clone(), + self.envs + .spans + .get(&fc.op.get_hir_id()) + .unwrap() + .clone() + .into(), fc.to_func_type(self.envs.get_current_env().unwrap()).into(), sig.clone().into(), fc.to_func_type(self.envs.get_current_env().unwrap()).into(), @@ -515,7 +530,12 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { self.envs .diagnostics .push_error(Diagnostic::new_type_conflict( - self.envs.spans.get(&i.value.get_hir_id()).unwrap().clone(), + self.envs + .spans + .get(&i.value.get_hir_id()) + .unwrap() + .clone() + .into(), Type::Primitive(PrimitiveType::Int64), other.clone(), Type::Primitive(PrimitiveType::Int64), @@ -528,7 +548,12 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { .envs .diagnostics .push_error(Diagnostic::new_type_conflict( - self.envs.spans.get(&i.value.get_hir_id()).unwrap().clone(), + self.envs + .spans + .get(&i.value.get_hir_id()) + .unwrap() + .clone() + .into(), Type::Primitive(PrimitiveType::Array(Box::new(value_t.clone()), 0)), other.clone(), Type::Primitive(PrimitiveType::Array(Box::new(value_t), 0)), @@ -559,7 +584,12 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { self.envs .diagnostics .push_error(Diagnostic::new_type_conflict( - self.envs.spans.get(&d.value.get_hir_id()).unwrap().clone(), + self.envs + .spans + .get(&d.value.get_hir_id()) + .unwrap() + .clone() + .into(), value_t.clone(), other.clone(), value_t, @@ -680,6 +710,7 @@ pub fn solve(root: &mut Root) -> (BTreeMap>, Diagnos let mut constraint_ctx = ConstraintContext::new(infer_state, root); constraint_ctx.constraint(root); + println!("here_final"); let tmp_resolutions = constraint_ctx.tmp_resolutions.clone(); diff --git a/src/lib/infer/mod.rs b/src/lib/infer/mod.rs index d67874d4..7a838e1e 100644 --- a/src/lib/infer/mod.rs +++ b/src/lib/infer/mod.rs @@ -12,6 +12,7 @@ pub fn infer( parsing_ctx: &mut ParsingCtx, config: &Config, ) -> Result { + println!("lol"); let (tmp_resolutions, diags) = constraint::solve(root); parsing_ctx.diagnostics.append(diags); diff --git a/src/lib/infer/monomorphize/mod.rs b/src/lib/infer/monomorphize/mod.rs index 758e512f..0a0b9b5e 100644 --- a/src/lib/infer/monomorphize/mod.rs +++ b/src/lib/infer/monomorphize/mod.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ hir::{HirId, Root}, - resolver::ResolutionMap, + resolver2::ResolutionMap, }; use self::monomorphizer::Monomorphizer; diff --git a/src/lib/infer/monomorphize/monomorphizer.rs b/src/lib/infer/monomorphize/monomorphizer.rs index 72d923bf..6d46169f 100644 --- a/src/lib/infer/monomorphize/monomorphizer.rs +++ b/src/lib/infer/monomorphize/monomorphizer.rs @@ -4,7 +4,7 @@ use crate::{ hir::visit_mut::*, hir::*, infer::Env, - resolver::ResolutionMap, + resolver2::ResolutionMap, ty::{FuncType, Type}, }; diff --git a/src/lib/infer/state.rs b/src/lib/infer/state.rs index e9ea8453..c24718ed 100644 --- a/src/lib/infer/state.rs +++ b/src/lib/infer/state.rs @@ -3,7 +3,7 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ diagnostics::{Diagnostic, Diagnostics}, hir::*, - parser::Span, + parser::span2::Span, ty::*, }; @@ -81,7 +81,7 @@ impl Envs { (Type::Func(src_f), Some(Type::Func(prev_f))) if !src_f.eq(&prev_f) => { if prev_f.is_solved() && src_f.is_solved() { self.diagnostics.push_error(Diagnostic::new_type_conflict( - self.spans.get(dest).unwrap().clone(), + self.spans.get(dest).unwrap().clone().into(), previous.clone().unwrap(), src.clone(), previous.unwrap(), @@ -92,7 +92,7 @@ impl Envs { (src, Some(previous)) if !src.eq(&previous) => { if previous.is_solved() && src.is_solved() { self.diagnostics.push_error(Diagnostic::new_type_conflict( - self.spans.get(dest).unwrap().clone(), + self.spans.get(dest).unwrap().clone().into(), previous.clone(), src.clone(), previous, @@ -112,7 +112,7 @@ impl Envs { (Type::Func(src_f), Some(Type::Func(prev_f))) if !src_f.eq(&prev_f) => { if prev_f.is_solved() && src_f.is_solved() { self.diagnostics.push_error(Diagnostic::new_type_conflict( - self.spans.get(src).unwrap().clone(), + self.spans.get(src).unwrap().clone().into(), previous.clone().unwrap(), src_t.clone(), previous.unwrap(), @@ -123,7 +123,7 @@ impl Envs { (src_t, Some(previous)) if !src_t.eq(&previous) => { if previous.is_solved() && src_t.is_solved() { self.diagnostics.push_error(Diagnostic::new_type_conflict( - self.spans.get(src).unwrap().clone(), + self.spans.get(src).unwrap().clone().into(), previous.clone(), src_t.clone(), previous, diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index def03a57..bff13535 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -15,9 +15,9 @@ pub use source_file::*; pub use span::*; pub use token::*; -use crate::ast::visit::*; -use crate::{ast::ast_print::AstPrintContext, diagnostics::Diagnostic}; - +// use crate::ast::visit::*; +// use crate::{ast::ast_print::AstPrintContext, diagnostics::Diagnostic}; +/* fn parse_generic(ctx: &mut ParsingCtx, mut f: F) -> Result<(R, Vec), Diagnostic> where F: FnMut(&mut Parser) -> Result, @@ -83,4 +83,4 @@ pub fn parse_mod(name: String, ctx: &mut ParsingCtx) -> Result Res { pub fn parse_prototype(input: Parser) -> Res { map( tuple(( + parse_identity, terminated( parse_identifier_or_operator, delimited(space0, tag("::"), space0), ), parse_signature, )), - |(name, signature)| Prototype { - node_id: name.node_id, + |(node_id, name, signature)| Prototype { + node_id, name, signature, }, @@ -302,6 +303,7 @@ pub fn parse_prototype(input: Parser) -> Res { pub fn parse_fn(input: Parser) -> Res { map( tuple(( + parse_identity, terminated( tuple(( parse_identifier_or_operator, @@ -311,8 +313,8 @@ pub fn parse_fn(input: Parser) -> Res { ), parse_body, )), - |((name, arguments), body)| FunctionDecl { - node_id: name.node_id, + |(node_id, (name, arguments), body)| FunctionDecl { + node_id, name, body, signature: FuncType::from_args_nb(arguments.len()), diff --git a/src/lib/resolver/resolution_map.rs b/src/lib/resolver/resolution_map.rs index adb652b1..18d02b3b 100644 --- a/src/lib/resolver/resolution_map.rs +++ b/src/lib/resolver/resolution_map.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{ast::NodeId, ast_lowering::HirMap, hir::HirId}; +use crate::{ast::NodeId, ast_lowering2::HirMap, hir::HirId}; #[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct ResolutionMap(HashMap) diff --git a/src/lib/resolver2/resolution_map.rs b/src/lib/resolver2/resolution_map.rs index adb652b1..18d02b3b 100644 --- a/src/lib/resolver2/resolution_map.rs +++ b/src/lib/resolver2/resolution_map.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{ast::NodeId, ast_lowering::HirMap, hir::HirId}; +use crate::{ast::NodeId, ast_lowering2::HirMap, hir::HirId}; #[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct ResolutionMap(HashMap) diff --git a/src/lib/rock.rs b/src/lib/rock.rs index 65dea1c2..90659cc6 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -22,7 +22,8 @@ mod ast; #[macro_use] mod infer; -mod ast_lowering; +// mod ast_lowering; +mod ast_lowering2; mod codegen; pub mod diagnostics; mod hir; @@ -33,6 +34,7 @@ mod resolver2; mod tests; mod ty; +use ast::ast_print::AstPrintContext; use codegen::interpret; use diagnostics::Diagnostic; pub use helpers::config::Config; @@ -77,18 +79,35 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { parsing_ctx.identities = ctx.extra.identities(); + // Debug ast + if parsing_ctx.config.show_ast { + use crate::ast::visit2::Visitor; + + // AstPrintContext::new().visit_root(&ast); + println!("{:#?}", ast); + } + debug!(" -> Resolving"); resolver2::resolve(&mut ast, parsing_ctx)?; - /* // Lowering to HIR + // Lowering to HIR debug!(" -> Lowering to HIR"); - let mut hir = ast_lowering2::lower_crate(&ast); */ + let mut hir = ast_lowering2::lower_crate(&ast); - Ok(ast) + // Debug hir + if parsing_ctx.config.show_hir { + hir.print(); + } + + // Infer Hir + debug!(" -> Infer HIR"); + let new_hir = infer::infer(&mut hir, parsing_ctx, config)?; + + Ok(new_hir) } Err(e) => { let diagnostic = Diagnostic::from(e); @@ -97,11 +116,11 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result Parsing"); let mut ast = parser::parse_root(parsing_ctx)?; @@ -115,9 +134,10 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result Infer HIR"); - let new_hir = infer::infer(&mut hir, parsing_ctx, config)?; + let new_hir = infer::infer(&mut hir, parsing_ctx, config)?; */ - Ok(new_hir) + // Ok(new_hir) + Ok(hir) } pub fn generate_ir(hir: hir::Root, config: &Config) -> Result<(), Diagnostic> { From f0215473b913ab25fc4c27d8399c0d4cce94fe65 Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Apr 2022 14:09:27 +0200 Subject: [PATCH 50/74] Operators list is propagated to the root ast node --- src/lib/parser2/mod.rs | 4 ++++ src/lib/rock.rs | 1 + 2 files changed, 5 insertions(+) diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index d78c2526..beecf5a0 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -124,6 +124,10 @@ impl ParserCtx { .map(|identity| (identity.node_id, identity.clone())) .collect() } + + pub fn operators_list(&self) -> HashMap { + self.operators_list.clone() + } } pub fn create_parser(s: &str) -> Parser<'_> { diff --git a/src/lib/rock.rs b/src/lib/rock.rs index 90659cc6..09284958 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -82,6 +82,7 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { parsing_ctx.identities = ctx.extra.identities(); + ast.operators_list = ctx.extra.operators_list(); // Debug ast if parsing_ctx.config.show_ast { From 54b6cee82b528400a41e2713bdc92cb546bf7898 Mon Sep 17 00:00:00 2001 From: Champii Date: Sat, 2 Apr 2022 16:42:20 +0200 Subject: [PATCH 51/74] 12 tests to go --- src/lib/ast/tree2.rs | 24 +++----- src/lib/ast/visit2.rs | 4 +- src/lib/ast_lowering2/ast_lowering_context.rs | 10 ++-- src/lib/hir/has_hir_id.rs | 4 +- src/lib/hir/tree.rs | 20 +++++-- src/lib/hir/visit.rs | 4 +- src/lib/hir/visit_mut.rs | 4 +- src/lib/infer/constraint.rs | 9 ++- src/lib/infer/monomorphize/monomorphizer.rs | 28 ++++++---- src/lib/parser/lexer.rs | 6 +- src/lib/parser/parsing_context.rs | 24 ++++++-- src/lib/parser/span2.rs | 2 +- src/lib/parser2/mod.rs | 56 +++++++++++++------ src/lib/resolver2/mod.rs | 6 +- src/lib/resolver2/resolve_ctx.rs | 17 ++---- src/lib/rock.rs | 1 + src/lib/ty/struct_type.rs | 44 ++++++++++++++- src/lib/ty/type.rs | 7 ++- 18 files changed, 175 insertions(+), 95 deletions(-) diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index f5192c36..3f4f4654 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -5,7 +5,7 @@ use crate::{ helpers::*, parser::span2::Span, resolver2::ResolutionMap, - ty::{FuncType, Type}, + ty::{FuncType, StructType, Type}, }; #[derive(Debug, Clone)] @@ -106,35 +106,25 @@ impl TopLevel { #[derive(Debug, Clone)] pub struct StructDecl { - pub node_id: NodeId, - pub name: Type, + pub name: Identifier, pub defs: Vec, } impl StructDecl { - pub fn new(node_id: NodeId, name: Type, defs: Vec) -> Self { - Self { - node_id, - name, - defs, - } + pub fn new(name: Identifier, defs: Vec) -> Self { + Self { name, defs } } } #[derive(Debug, Clone)] pub struct StructCtor { - pub node_id: NodeId, - pub name: Type, + pub name: Identifier, pub defs: HashMap, } impl StructCtor { - pub fn new(node_id: NodeId, name: Type, defs: HashMap) -> Self { - Self { - node_id, - name, - defs, - } + pub fn new(name: Identifier, defs: HashMap) -> Self { + Self { name, defs } } } diff --git a/src/lib/ast/visit2.rs b/src/lib/ast/visit2.rs index 4c3b17e4..04953944 100644 --- a/src/lib/ast/visit2.rs +++ b/src/lib/ast/visit2.rs @@ -88,7 +88,7 @@ pub fn walk_top_level<'a, V: Visitor<'a>>(visitor: &mut V, top_level: &'a TopLev } pub fn walk_struct_decl<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructDecl) { - visitor.visit_type(&s.name); + visitor.visit_identifier(&s.name); walk_list!(visitor, visit_prototype, &s.defs); } @@ -222,7 +222,7 @@ pub fn walk_expression<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a Expression } pub fn walk_struct_ctor<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructCtor) { - visitor.visit_type(&s.name); + visitor.visit_identifier(&s.name); walk_map!(visitor, visit_expression, &s.defs); } diff --git a/src/lib/ast_lowering2/ast_lowering_context.rs b/src/lib/ast_lowering2/ast_lowering_context.rs index aee4e164..7652f93f 100644 --- a/src/lib/ast_lowering2/ast_lowering_context.rs +++ b/src/lib/ast_lowering2/ast_lowering_context.rs @@ -94,8 +94,8 @@ impl AstLoweringContext { pub fn lower_struct_decl(&mut self, s: &StructDecl) -> hir::StructDecl { let hir_t = hir::StructDecl { - hir_id: self.hir_map.next_hir_id(s.node_id), - name: s.name.clone(), + // hir_id: self.hir_map.next_hir_id(s.name.node_id), + name: self.lower_identifier(&s.name), defs: s .defs .iter() @@ -103,7 +103,7 @@ impl AstLoweringContext { .collect(), }; - self.structs.insert(s.name.get_name(), hir_t.clone()); + self.structs.insert(s.name.to_string(), hir_t.clone()); hir_t } @@ -327,8 +327,8 @@ impl AstLoweringContext { pub fn lower_struct_ctor(&mut self, s: &StructCtor) -> hir::Expression { hir::Expression::new_struct_ctor(hir::StructCtor { - hir_id: self.hir_map.next_hir_id(s.node_id), - name: s.name.clone(), + // hir_id: self.hir_map.next_hir_id(s.node_id), + name: self.lower_identifier(&s.name), defs: s .defs .iter() diff --git a/src/lib/hir/has_hir_id.rs b/src/lib/hir/has_hir_id.rs index e0d3c01d..e05e38bb 100644 --- a/src/lib/hir/has_hir_id.rs +++ b/src/lib/hir/has_hir_id.rs @@ -22,11 +22,9 @@ macro_rules! impl_direct_get_hir_id_trait { impl_direct_get_hir_id_trait!( Prototype FunctionDecl - StructDecl Identifier If FunctionCall - StructCtor Indice Dot Literal @@ -52,6 +50,8 @@ macro_rules! impl_indirect_get_hir_id_trait { impl_indirect_get_hir_id_trait!( TopLevel Statement + StructCtor + StructDecl Assign AssignLeftSide ArgumentDecl diff --git a/src/lib/hir/tree.rs b/src/lib/hir/tree.rs index f3e37d36..899ae34f 100644 --- a/src/lib/hir/tree.rs +++ b/src/lib/hir/tree.rs @@ -153,15 +153,15 @@ pub struct Impl { #[derive(Debug, Clone, Serialize, Deserialize)] pub struct StructDecl { - pub hir_id: HirId, - pub name: Type, + // pub hir_id: HirId, + pub name: Identifier, pub defs: Vec, } impl StructDecl { pub fn to_type(&self) -> Type { Type::Struct(StructType { - name: self.name.get_name(), + name: self.name.name.clone(), defs: self .defs .iter() @@ -178,15 +178,25 @@ impl StructDecl { .collect(), }) } + + pub fn get_terminal_hir_id(&self) -> HirId { + self.name.hir_id.clone() + } } #[derive(Debug, Clone, Serialize, Deserialize)] pub struct StructCtor { - pub hir_id: HirId, - pub name: Type, + // pub hir_id: HirId, + pub name: Identifier, pub defs: BTreeMap, } +impl StructCtor { + pub fn get_terminal_hir_id(&self) -> HirId { + self.name.hir_id.clone() + } +} + #[derive(Debug, Clone, Serialize, Deserialize)] pub struct TopLevel { pub kind: TopLevelKind, diff --git a/src/lib/hir/visit.rs b/src/lib/hir/visit.rs index 5a1a4443..313f3d1c 100644 --- a/src/lib/hir/visit.rs +++ b/src/lib/hir/visit.rs @@ -82,7 +82,7 @@ pub fn walk_top_level<'a, V: Visitor<'a>>(visitor: &mut V, top_level: &'a TopLev } pub fn walk_struct_decl<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructDecl) { - visitor.visit_type(&s.name); + visitor.visit_identifier(&s.name); walk_list!(visitor, visit_prototype, &s.defs); } @@ -194,7 +194,7 @@ pub fn walk_expression<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a Expression } pub fn walk_struct_ctor<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructCtor) { - visitor.visit_type(&s.name); + visitor.visit_identifier(&s.name); walk_map!(visitor, visit_expression, &s.defs); } diff --git a/src/lib/hir/visit_mut.rs b/src/lib/hir/visit_mut.rs index b11dc589..5c2928fe 100644 --- a/src/lib/hir/visit_mut.rs +++ b/src/lib/hir/visit_mut.rs @@ -75,13 +75,13 @@ pub fn walk_root<'a, V: VisitorMut<'a>>(visitor: &mut V, root: &'a mut Root) { } pub fn walk_struct_decl<'a, V: VisitorMut<'a>>(visitor: &mut V, s: &'a mut StructDecl) { - visitor.visit_type(&mut s.name); + visitor.visit_identifier(&mut s.name); walk_list!(visitor, visit_prototype, &mut s.defs); } pub fn walk_struct_ctor<'a, V: VisitorMut<'a>>(visitor: &mut V, s: &'a mut StructCtor) { - visitor.visit_type(&mut s.name); + visitor.visit_identifier(&mut s.name); walk_map!(visitor, visit_expression, &mut s.defs); } diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index 35a03876..368aedd0 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -371,7 +371,7 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { fn visit_struct_decl(&mut self, s: &StructDecl) { let t = s.into(); - self.envs.set_type(&s.hir_id, &t); + self.envs.set_type(&s.name.hir_id, &t); let struct_t = t.as_struct_type(); @@ -382,13 +382,15 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { } fn visit_struct_ctor(&mut self, s: &StructCtor) { - let s_decl = self.hir.structs.get(&s.name.get_name()).unwrap(); + let s_decl = self.hir.structs.get(&s.name.name).unwrap(); self.visit_struct_decl(s_decl); let t = s_decl.into(); - self.envs.set_type(&s.hir_id, &t); + self.envs.set_type(&s.name.hir_id, &t); + + println!("ENVS {:#?}", self.envs); let struct_t = t.as_struct_type(); @@ -705,6 +707,7 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { pub fn solve(root: &mut Root) -> (BTreeMap>, Diagnostics) { let diagnostics = Diagnostics::default(); + // println!("ROOT {:#?}", root.get_hir_spans()); let infer_state = Envs::new(diagnostics, root.get_hir_spans()); let mut constraint_ctx = ConstraintContext::new(infer_state, root); diff --git a/src/lib/infer/monomorphize/monomorphizer.rs b/src/lib/infer/monomorphize/monomorphizer.rs index 6d46169f..a9c5126e 100644 --- a/src/lib/infer/monomorphize/monomorphizer.rs +++ b/src/lib/infer/monomorphize/monomorphizer.rs @@ -397,15 +397,18 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { } fn visit_struct_decl(&mut self, s: &'a mut StructDecl) { - let old_hir_id = s.hir_id.clone(); + let old_hir_id = s.name.hir_id.clone(); - s.hir_id = self.duplicate_hir_id(&old_hir_id); + s.name.hir_id = self.duplicate_hir_id(&old_hir_id); if let Some(t) = self.root.type_envs.get_type(&old_hir_id) { - self.root.node_types.insert(s.hir_id.clone(), t.clone()); + self.root + .node_types + .insert(s.name.hir_id.clone(), t.clone()); } - self.trans_resolutions.insert(old_hir_id, s.hir_id.clone()); + self.trans_resolutions + .insert(old_hir_id, s.name.hir_id.clone()); s.defs.iter().for_each(|p| { let t = *s @@ -419,26 +422,29 @@ impl<'a, 'b> VisitorMut<'a> for Monomorphizer<'b> { self.root.node_types.insert(p.name.get_hir_id(), t); }); - self.structs.insert(s.name.get_name(), s.clone()); + self.structs.insert(s.name.name.clone(), s.clone()); } fn visit_struct_ctor(&mut self, s: &'a mut StructCtor) { - let old_hir_id = s.hir_id.clone(); + let old_hir_id = s.name.hir_id.clone(); - let mut s_decl = self.root.structs.get(&s.name.get_name()).unwrap().clone(); + let mut s_decl = self.root.structs.get(&s.name.name).unwrap().clone(); // TODO: Do that once self.visit_struct_decl(&mut s_decl); - s.hir_id = self.duplicate_hir_id(&old_hir_id); + s.name.hir_id = self.duplicate_hir_id(&old_hir_id); if let Some(t) = self.root.type_envs.get_type(&old_hir_id) { - self.root.node_types.insert(s.hir_id.clone(), t.clone()); + self.root + .node_types + .insert(s.name.hir_id.clone(), t.clone()); } - self.trans_resolutions.insert(old_hir_id, s.hir_id.clone()); + self.trans_resolutions + .insert(old_hir_id, s.name.hir_id.clone()); - self.visit_type(&mut s.name); + // self.visit_identifier(&mut s.name); s.defs = s .defs diff --git a/src/lib/parser/lexer.rs b/src/lib/parser/lexer.rs index f33386af..a3716bfc 100644 --- a/src/lib/parser/lexer.rs +++ b/src/lib/parser/lexer.rs @@ -113,7 +113,7 @@ impl<'a> Lexer<'a> { self.ctx .diagnostics .push_error(Diagnostic::new_unexpected_token( - self.ctx.new_span(self.cur_idx, self.cur_idx), + self.ctx.new_span(self.cur_idx, self.cur_idx).into(), )); self.end = true; @@ -170,7 +170,7 @@ impl<'a> Lexer<'a> { fn new_token(&self, t: TokenType, start: usize, txt: String) -> Token { Token { t, - span: self.ctx.new_span(start, self.cur_idx - 1), + span: self.ctx.new_span(start, self.cur_idx - 1).into(), txt, } } @@ -476,7 +476,7 @@ impl<'a> Lexer<'a> { if self.last_char == '\n' { let res = Some(Token { t: TokenType::Eol, - span: self.ctx.new_span(self.cur_idx, self.cur_idx), + span: self.ctx.new_span(self.cur_idx, self.cur_idx).into(), txt: "\n".to_string(), }); diff --git a/src/lib/parser/parsing_context.rs b/src/lib/parser/parsing_context.rs index 49eaf650..88d589de 100644 --- a/src/lib/parser/parsing_context.rs +++ b/src/lib/parser/parsing_context.rs @@ -1,17 +1,18 @@ use std::{ - collections::HashMap, + collections::{BTreeMap, HashMap}, path::{Component, PathBuf}, }; use colored::*; use crate::{ - ast::{ast_print::AstPrintContext, identity2::Identity, tree2, Identifier, NodeId, Root}, + ast::{ast_print::AstPrintContext, tree2, Identifier, NodeId, Root}, diagnostics::{Diagnostic, DiagnosticType, Diagnostics}, + parser::span2::Span, Config, }; -use super::{SourceFile, Span}; +use super::SourceFile; #[derive(Default, Debug)] pub struct ParsingCtx { @@ -20,7 +21,7 @@ pub struct ParsingCtx { pub current_file: Option, pub diagnostics: Diagnostics, pub operators_list: HashMap, - pub identities: HashMap, + pub identities: BTreeMap, } impl ParsingCtx { @@ -127,7 +128,11 @@ impl ParsingCtx { } pub fn new_span(&self, start: usize, end: usize) -> Span { - Span::new(self.get_current_file().file_path, start, end) + Span { + file_path: self.get_current_file().file_path, + offset: start, + ..Default::default() + } } pub fn resolve_and_add_file(&mut self, name: String) -> Result { @@ -135,7 +140,14 @@ impl ParsingCtx { let new_file = current_file.resolve_new(name).map_err(|m| { // Placeholder span, to be overriden by calling mod (TopLevel::parse()) - Diagnostic::new_module_not_found(Span::new(current_file.file_path.clone(), 0, 0), m) + Diagnostic::new_module_not_found( + Span { + file_path: current_file.file_path.clone(), + ..Default::default() + } + .into(), + m, + ) })?; if self.config.verbose { diff --git a/src/lib/parser/span2.rs b/src/lib/parser/span2.rs index 1bfff1b2..deaa5f80 100644 --- a/src/lib/parser/span2.rs +++ b/src/lib/parser/span2.rs @@ -4,7 +4,7 @@ use crate::parser2::Parser; // TODO: merge spans -#[derive(Debug, Clone, Hash, PartialEq, Eq)] +#[derive(Debug, Default, Clone, Hash, PartialEq, Eq)] pub struct Span { pub file_path: PathBuf, pub offset: usize, diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index beecf5a0..d4e48910 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -1,4 +1,4 @@ -use std::collections::HashMap; +use std::collections::{BTreeMap, HashMap}; use std::path::PathBuf; @@ -33,7 +33,7 @@ mod tests; #[derive(Debug, Clone)] pub struct ParserCtx { cur_file_path: PathBuf, - identities: Vec, + identities: BTreeMap, operators_list: HashMap, block_indent: usize, first_indent: Option, @@ -44,7 +44,7 @@ impl ParserCtx { pub fn new(file_path: PathBuf) -> Self { Self { cur_file_path: file_path, - identities: Vec::new(), + identities: BTreeMap::new(), operators_list: HashMap::new(), block_indent: 0, first_indent: None, @@ -56,7 +56,7 @@ impl ParserCtx { pub fn new_with_operators(file_path: PathBuf, operators: HashMap) -> Self { Self { cur_file_path: file_path, - identities: Vec::new(), + identities: BTreeMap::new(), operators_list: operators, block_indent: 0, first_indent: None, @@ -71,7 +71,7 @@ impl ParserCtx { .parent() .unwrap() .join(name.to_owned() + ".rk"), - identities: Vec::new(), + identities: BTreeMap::new(), operators_list: HashMap::new(), block_indent: 0, first_indent: None, @@ -84,7 +84,7 @@ impl ParserCtx { self.next_node_id += 1; - self.identities.push(Identity::new(node_id, span)); + self.identities.insert(node_id, span); node_id } @@ -118,11 +118,11 @@ impl ParserCtx { new } */ - pub fn identities(&self) -> HashMap { - self.identities - .iter() - .map(|identity| (identity.node_id, identity.clone())) - .collect() + pub fn identities(&self) -> BTreeMap { + self.identities.clone() + /* .iter() + .map(|identity| (identity.node_id, identity.clone())) + .collect() */ } pub fn operators_list(&self) -> HashMap { @@ -238,15 +238,14 @@ pub fn parse_struct_decl(input: Parser) -> Res { map( tuple(( terminated(tag("struct"), space1), - parse_identity, - parse_type, + parse_capitalized_identifier, many0(line_ending), indent(separated_list0( line_ending, preceded(parse_block_indent, parse_prototype), )), )), - |(tag, node_id, name, _, defs)| StructDecl::new(node_id, name, defs), + |(tag, name, _, defs)| StructDecl::new(name, defs), )(input) } @@ -585,8 +584,8 @@ pub fn parse_native_operator( pub fn parse_struct_ctor(input: Parser) -> Res { map( tuple(( - parse_identity, - terminated(parse_type, line_ending), + // parse_identity, + terminated(parse_capitalized_identifier, line_ending), indent(separated_list0( line_ending, preceded( @@ -598,7 +597,7 @@ pub fn parse_struct_ctor(input: Parser) -> Res { ), )), )), - |(node_id, name, decls)| StructCtor::new(node_id, name, decls.into_iter().collect()), + |(name, decls)| StructCtor::new(name, decls.into_iter().collect()), )(input) } @@ -700,6 +699,18 @@ pub fn parse_identifier_path(input: Parser) -> Res { )(input) } +pub fn parse_capitalized_identifier(input: Parser) -> Res { + let (input, (node_id, txt)) = tuple((parse_identity, parse_capitalized_text))(input)?; + + Ok(( + input, + Identifier { + name: txt.to_string(), + node_id, + }, + )) +} + pub fn parse_identifier(input: Parser) -> Res { let (input, ident_parsed) = recognize(many1(one_of("abcdefghijklmnopqrstuvwxyz_0123456789")))(input)?; @@ -840,7 +851,6 @@ pub fn parse_signature(input: Parser) -> Res { pub fn parse_type(input: Parser) -> Res { let (input, ty) = alt(( - map(parse_capitalized_text, Type::Trait), map( terminated( one_of("abcdefghijklmnopqrstuvwxyz"), @@ -854,6 +864,16 @@ pub fn parse_type(input: Parser) -> Res { 0, // FIXME )) }), + map( + alt(( + map(tag("Bool"), |_| PrimitiveType::Bool), + map(tag("Int64"), |_| PrimitiveType::Int64), + map(tag("Float64"), |_| PrimitiveType::Float64), + map(tag("String"), |_| PrimitiveType::String), + )), + |t| Type::from(t), + ), + map(parse_capitalized_text, Type::Trait), ))(input)?; Ok((input, ty)) diff --git a/src/lib/resolver2/mod.rs b/src/lib/resolver2/mod.rs index 838334b2..39eb19a1 100644 --- a/src/lib/resolver2/mod.rs +++ b/src/lib/resolver2/mod.rs @@ -33,13 +33,11 @@ pub fn resolve(root: &mut Root, parsing_ctx: &mut ParsingCtx) -> Result<(), Diag let (mut unused_fns, unused_methods) = unused_collector::collect_unused(root); for unused_fn in &unused_fns { - let identity = parsing_ctx.identities.get(unused_fn).unwrap(); + let span = parsing_ctx.identities.get(unused_fn).unwrap(); parsing_ctx .diagnostics - .push_warning(Diagnostic::new_unused_function(Span::from( - identity.span.clone(), - ))); + .push_warning(Diagnostic::new_unused_function(Span::from(span.clone()))); } unused_fns.extend(unused_methods); diff --git a/src/lib/resolver2/resolve_ctx.rs b/src/lib/resolver2/resolve_ctx.rs index 69e1d41d..002d14e3 100644 --- a/src/lib/resolver2/resolve_ctx.rs +++ b/src/lib/resolver2/resolve_ctx.rs @@ -50,12 +50,7 @@ impl<'a> ResolveCtx<'a> { } pub fn get_span2(&self, node_id: NodeId) -> Span2 { - self.parsing_ctx - .identities - .get(&node_id) - .unwrap() - .span - .clone() + self.parsing_ctx.identities.get(&node_id).unwrap().clone() } } @@ -74,7 +69,7 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { } } TopLevel::Struct(s) => { - self.add_to_current_scope(s.name.get_name(), s.node_id); + self.add_to_current_scope(s.name.name.clone(), s.name.node_id); s.defs.iter().for_each(|p| { self.add_to_current_scope((*p.name).clone(), p.node_id); @@ -168,17 +163,17 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { } fn visit_struct_ctor(&mut self, s: &'a StructCtor) { - match self.get(s.name.get_name()) { - Some(pointed) => self.resolutions.insert(s.node_id, pointed), + match self.get(s.name.name.clone()) { + Some(pointed) => self.resolutions.insert(s.name.node_id, pointed), None => self .parsing_ctx .diagnostics .push_error(Diagnostic::new_unknown_identifier( - self.get_span2(s.node_id).into(), + self.get_span2(s.name.node_id).into(), )), }; - self.visit_type(&s.name); + self.visit_identifier(&s.name); walk_struct_ctor(self, s); } diff --git a/src/lib/rock.rs b/src/lib/rock.rs index 09284958..2882e602 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -83,6 +83,7 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { parsing_ctx.identities = ctx.extra.identities(); ast.operators_list = ctx.extra.operators_list(); + ast.spans = ctx.extra.identities().into_iter().collect(); // Debug ast if parsing_ctx.config.show_ast { diff --git a/src/lib/ty/struct_type.rs b/src/lib/ty/struct_type.rs index 0bb156c8..08769eed 100644 --- a/src/lib/ty/struct_type.rs +++ b/src/lib/ty/struct_type.rs @@ -29,6 +29,46 @@ impl fmt::Debug for StructType { } } +impl From<&ast::tree2::StructDecl> for StructType { + fn from(s: &ast::tree2::StructDecl) -> Self { + s.into() + } +} + +impl From for StructType { + fn from(s: ast::tree2::StructDecl) -> Self { + StructType { + name: s.name.to_string(), + defs: s + .defs + .iter() + .map(|proto| { + if proto.signature.arguments.is_empty() { + (proto.name.name.clone(), proto.signature.ret.clone()) + } else { + ( + proto.name.name.clone(), + Box::new(proto.signature.clone().into()), + ) + } + }) + .collect(), + } + } +} + +/* impl From<&ast::tree2::StructCtor> for StructType { + fn from(s: &ast::tree2::StructCtor) -> Self { + s.into() + } +} + +impl From for StructType { + fn from(s: ast::tree2::StructCtor) -> Self { + s.ty.clone() + } +} + */ impl From<&ast::StructDecl> for StructType { fn from(s: &ast::StructDecl) -> Self { s.into() @@ -38,7 +78,7 @@ impl From<&ast::StructDecl> for StructType { impl From for StructType { fn from(s: ast::StructDecl) -> Self { StructType { - name: s.name.get_name(), + name: s.name.to_string(), defs: s .defs .iter() @@ -60,7 +100,7 @@ impl From for StructType { impl From for StructType { fn from(s: hir::StructDecl) -> Self { StructType { - name: s.name.get_name(), + name: s.name.name, defs: s .defs .iter() diff --git a/src/lib/ty/type.rs b/src/lib/ty/type.rs index 1670447c..8b0ab68c 100644 --- a/src/lib/ty/type.rs +++ b/src/lib/ty/type.rs @@ -151,7 +151,10 @@ impl fmt::Debug for Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self { Self::Func(f) => format!("{:?}", f), - Self::Struct(s) => format!("{:?}", s), + Self::Struct(s) => format!("{{{:?}}}", s), + Self::Trait(t) => format!("Trait {:?}", t), + Self::ForAll(t) => format!("forall. {:?}", t), + Self::Undefined(t) => format!("UNDEFINED {:?}", t), _ => self.get_name().cyan().to_string(), }; @@ -224,6 +227,8 @@ impl From for Type { )), 0, // FIXME )) + } else if PrimitiveType::from_name(&t).is_some() { + Type::Primitive(PrimitiveType::from_name(&t).unwrap()) } else { Type::Trait(t) } From 619f0eec61a53a308d0bbcb7f30d633684d1563b Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 18 Apr 2022 11:20:31 +0200 Subject: [PATCH 52/74] Fixed build.rs that was rerun each time --- Cargo.lock | 21 +++++++++++++++++++ Cargo.toml | 3 +++ build.rs | 40 ++++++++++++++++++++++++++++--------- src/lib/ast/tree2.rs | 7 +++++++ src/lib/infer/constraint.rs | 19 ++++++++++++++---- src/lib/rock.rs | 8 +++----- src/lib/tests.rs | 18 ++++++++--------- 7 files changed, 89 insertions(+), 27 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index edbcd330..2ff89c3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -482,6 +482,7 @@ dependencies = [ "rustyline", "serde", "serde_derive", + "walkdir", ] [[package]] @@ -508,6 +509,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "same-file" +version = "1.0.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "93fc1dc3aaa9bfed95e02e6eadabb4baf7e3078b0bd1b4d7b6b0b68378900502" +dependencies = [ + "winapi-util", +] + [[package]] name = "scopeguard" version = "1.1.0" @@ -638,6 +648,17 @@ version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5fecdca9a5291cc2b8dcf7dc02453fee791a280f3743cb0905f8822ae463b3fe" +[[package]] +name = "walkdir" +version = "2.3.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "808cf2735cd4b6866113f648b791c6adc5714537bc222d9347bb203386ffda56" +dependencies = [ + "same-file", + "winapi", + "winapi-util", +] + [[package]] name = "wasi" version = "0.10.2+wasi-snapshot-preview1" diff --git a/Cargo.toml b/Cargo.toml index 1ef7317e..12509478 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,6 +23,9 @@ rustyline = "9.0.0" nom = "7.0.0" nom_locate = "4.0.0" +[build-dependencies] +walkdir = "2" + [lib] name = "rock" path = "src/lib/rock.rs" diff --git a/build.rs b/build.rs index 7c53cb1d..93170e34 100644 --- a/build.rs +++ b/build.rs @@ -3,6 +3,9 @@ use std::fs::File; use std::io; use std::io::Write; use std::path::Path; +use std::path::PathBuf; + +use walkdir::WalkDir; fn visit_dirs(dir: &Path) -> io::Result> { let mut res = vec![]; @@ -25,8 +28,27 @@ fn visit_dirs(dir: &Path) -> io::Result> { Ok(res) } +fn schedule_build_if_folder_changed(path: &Path) { + for entry in WalkDir::new(path) { + let entry = entry.unwrap(); + println!("{}", entry.path().display()); + + if entry.path() == path { + continue; + } + + if entry.path().is_dir() { + schedule_build_if_folder_changed(&entry.path()); + } else { + println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap()); + } + } +} + // build script's entry point fn main() { + schedule_build_if_folder_changed(&PathBuf::from("src/lib/testcases/")); + let out_dir = "src/lib"; let destination = Path::new(&out_dir).join("tests.rs"); let mut output_file = File::create(&destination).unwrap(); @@ -62,19 +84,19 @@ fn write_header(output_file: &mut File) { r##"use std::path::PathBuf; #[allow(dead_code)] -fn run(path: &str, input: &str, expected_ret: &str, expected_output: &str) {{ - let mut config = super::Config::default(); + fn run(path: &str, input: &str, expected_ret: &str, expected_output: &str) {{ + let mut config = super::Config::default(); - config.project_config.entry_point = PathBuf::from(path); + config.project_config.entry_point = PathBuf::from(path); - let expected_ret = expected_ret.parse::().unwrap(); + let expected_ret = expected_ret.parse::().unwrap(); - let (ret_code, stdout) = super::test::run(path, input.to_string(), config); + let (ret_code, stdout) = super::test::run(path, input.to_string(), config); - assert_eq!(expected_ret, ret_code); - assert_eq!(expected_output, stdout); -}} -"## + assert_eq!(expected_ret, ret_code); + assert_eq!(expected_output, stdout); + }} + "## ) .unwrap(); } diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs index 3f4f4654..e906c758 100644 --- a/src/lib/ast/tree2.rs +++ b/src/lib/ast/tree2.rs @@ -8,6 +8,8 @@ use crate::{ ty::{FuncType, StructType, Type}, }; +use super::{ast_print::AstPrintContext, visit2::Visitor}; + #[derive(Debug, Clone)] pub struct Root { pub r#mod: Mod, @@ -38,6 +40,10 @@ impl Root { spans: HashMap::new(), } } + + pub fn print(&self) { + AstPrintContext::new().visit_root(self); + } } #[derive(Debug, Clone)] @@ -315,6 +321,7 @@ impl std::hash::Hash for Identifier { impl std::ops::Deref for Identifier { type Target = String; + fn deref(&self) -> &Self::Target { &self.name } diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index 368aedd0..68695467 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -376,8 +376,18 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { let struct_t = t.as_struct_type(); s.defs.iter().for_each(|p| { - self.envs - .set_type(&p.hir_id, struct_t.defs.get(&p.name.name).unwrap()); + let ty = *struct_t.defs.get(&p.name.name).unwrap().clone(); + + // FIXME: should not have to do this conversion from trait. + let ty = if let Type::Trait(t) = ty.clone() { + // println!("WHAT {:#?}, {:#?}, {:#?}", p, t, self.hir.structs); + self.hir.structs.get(&ty.get_name()).unwrap().to_type() + } else { + ty + }; + + println!("TRANSFORMED {:#?}", ty); + self.envs.set_type(&p.hir_id, &ty) }); } @@ -388,9 +398,9 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { let t = s_decl.into(); - self.envs.set_type(&s.name.hir_id, &t); + println!("TYPE {:#?}", t); - println!("ENVS {:#?}", self.envs); + self.envs.set_type(&s.name.hir_id, &t); let struct_t = t.as_struct_type(); @@ -567,6 +577,7 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { self.visit_expression(&d.op); self.visit_identifier(&d.value); + // println!("envs: {:#?}", self.envs); match &self.envs.get_type(&d.op.get_hir_id()).unwrap().clone() { t @ Type::Struct(struct_t) => { self.envs.set_type(&d.op.get_hir_id(), t); diff --git a/src/lib/rock.rs b/src/lib/rock.rs index 2882e602..bbcad991 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -71,7 +71,8 @@ pub fn compile_str(input: &SourceFile, config: &Config) -> Result<(), Diagnostic } pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { - let content = parsing_ctx.get_current_file().content.clone(); + let content = &parsing_ctx.get_current_file().content; + let parser = LocatedSpan::new_extra( content.as_str(), ParserCtx::new(parsing_ctx.get_current_file().file_path.clone()), @@ -87,10 +88,7 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result Resolving"); diff --git a/src/lib/tests.rs b/src/lib/tests.rs index 1c2c9833..e581e18d 100644 --- a/src/lib/tests.rs +++ b/src/lib/tests.rs @@ -1,19 +1,19 @@ use std::path::PathBuf; #[allow(dead_code)] -fn run(path: &str, input: &str, expected_ret: &str, expected_output: &str) { - let mut config = super::Config::default(); + fn run(path: &str, input: &str, expected_ret: &str, expected_output: &str) { + let mut config = super::Config::default(); - config.project_config.entry_point = PathBuf::from(path); + config.project_config.entry_point = PathBuf::from(path); - let expected_ret = expected_ret.parse::().unwrap(); + let expected_ret = expected_ret.parse::().unwrap(); - let (ret_code, stdout) = super::test::run(path, input.to_string(), config); + let (ret_code, stdout) = super::test::run(path, input.to_string(), config); - assert_eq!(expected_ret, ret_code); - assert_eq!(expected_output, stdout); -} -#[test] + assert_eq!(expected_ret, ret_code); + assert_eq!(expected_output, stdout); + } + #[test] fn testcases_mods_basic_mod_main() { run("testcases/mods/basic_mod/main.rk", include_str!("testcases/mods/basic_mod/main.rk"), include_str!("testcases/mods/basic_mod/main.rk.out"), include_str!("testcases/mods/basic_mod/main.rk.stdout")); } From b4f919ea54cc36c52da32303789c8a84ba33494b Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 18 Apr 2022 09:21:54 +0000 Subject: [PATCH 53/74] Generated files for new version --- Cargo.toml | 3 --- 1 file changed, 3 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 12509478..1ef7317e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -23,9 +23,6 @@ rustyline = "9.0.0" nom = "7.0.0" nom_locate = "4.0.0" -[build-dependencies] -walkdir = "2" - [lib] name = "rock" path = "src/lib/rock.rs" From 33fb567c02ee6b95e39efca958925f92f4d9e75f Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 18 Apr 2022 12:06:21 +0200 Subject: [PATCH 54/74] Checkpoint before sed --- build.rs | 14 +++++--------- src/lib/parser/source_file.rs | 2 +- src/lib/parser2/mod.rs | 4 ++-- src/lib/resolver/resolve_ctx.rs | 2 +- src/lib/testcases/mods/full_fact/main.rk | 2 +- .../testcases/mods/nested_trait_resolution/main.rk | 2 +- src/lib/testcases/mods/struct_new/main.rk | 2 +- 7 files changed, 12 insertions(+), 16 deletions(-) diff --git a/build.rs b/build.rs index 93170e34..11ca5d93 100644 --- a/build.rs +++ b/build.rs @@ -28,17 +28,16 @@ fn visit_dirs(dir: &Path) -> io::Result> { Ok(res) } -fn schedule_build_if_folder_changed(path: &Path) { +fn schedule_rerun_if_folder_changed(path: &Path) { for entry in WalkDir::new(path) { let entry = entry.unwrap(); - println!("{}", entry.path().display()); if entry.path() == path { continue; } if entry.path().is_dir() { - schedule_build_if_folder_changed(&entry.path()); + schedule_rerun_if_folder_changed(&entry.path()); } else { println!("cargo:rerun-if-changed={}", entry.path().to_str().unwrap()); } @@ -47,7 +46,7 @@ fn schedule_build_if_folder_changed(path: &Path) { // build script's entry point fn main() { - schedule_build_if_folder_changed(&PathBuf::from("src/lib/testcases/")); + schedule_rerun_if_folder_changed(&PathBuf::from("src/lib/testcases/")); let out_dir = "src/lib"; let destination = Path::new(&out_dir).join("tests.rs"); @@ -64,15 +63,12 @@ fn main() { fn write_test(output_file: &mut File, path: &str) { let path = path.replace("src/lib/", ""); - let name = path.replace("./", ""); - let name = name.replace("/", "_"); - let name = name.replace(".rk", ""); - let test_name = name; + let name = path.replace("./", "").replace("/", "_").replace(".rk", ""); write!( output_file, include_str!("src/lib/testcases/test_template"), - name = test_name, + name = name, path = path ) .unwrap(); diff --git a/src/lib/parser/source_file.rs b/src/lib/parser/source_file.rs index ee3fe9d7..4bab9df1 100644 --- a/src/lib/parser/source_file.rs +++ b/src/lib/parser/source_file.rs @@ -43,7 +43,7 @@ impl SourceFile { } let top_levels = r##"mod lib -use lib::prelude::* +use lib::prelude::(*) "## .to_owned() + &top_levels diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index d4e48910..1d6bb98b 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -688,8 +688,8 @@ pub fn parse_identifier_path(input: Parser) -> Res { separated_list1( tag("::"), alt(( - map(tuple((parse_identity, tag("*"))), |(node_id, _)| { - Identifier::new("*".to_string(), node_id) + map(tuple((parse_identity, tag("(*)"))), |(node_id, _)| { + Identifier::new("(*)".to_string(), node_id) }), parse_identifier, // map(parse_operator, |op| op.0), diff --git a/src/lib/resolver/resolve_ctx.rs b/src/lib/resolver/resolve_ctx.rs index d3bfff42..700dd856 100644 --- a/src/lib/resolver/resolve_ctx.rs +++ b/src/lib/resolver/resolve_ctx.rs @@ -190,7 +190,7 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { match self.scopes.get(&mod_path) { Some(scopes) => { - if ident.name == "*" { + if ident.name == "(*)" { let scope = scopes.scopes.get(0).unwrap(); for (k, v) in &scope.items.clone() { diff --git a/src/lib/testcases/mods/full_fact/main.rk b/src/lib/testcases/mods/full_fact/main.rk index 13b47ffd..481a0b29 100644 --- a/src/lib/testcases/mods/full_fact/main.rk +++ b/src/lib/testcases/mods/full_fact/main.rk @@ -1,6 +1,6 @@ mod lib -use lib::prelude::* +use lib::prelude::(*) fact a = if a <= 1 diff --git a/src/lib/testcases/mods/nested_trait_resolution/main.rk b/src/lib/testcases/mods/nested_trait_resolution/main.rk index 1c29f982..3a88b657 100644 --- a/src/lib/testcases/mods/nested_trait_resolution/main.rk +++ b/src/lib/testcases/mods/nested_trait_resolution/main.rk @@ -1,6 +1,6 @@ mod _std -use _std::* +use _std::(*) f a = a + 2 main = 40 |> f diff --git a/src/lib/testcases/mods/struct_new/main.rk b/src/lib/testcases/mods/struct_new/main.rk index 7535ca64..d3915208 100644 --- a/src/lib/testcases/mods/struct_new/main.rk +++ b/src/lib/testcases/mods/struct_new/main.rk @@ -1,6 +1,6 @@ mod lib -use lib::* +use lib::(*) main = let foo = new_foo "bar" From c9f9e25c4a55ea61138c8f06b00bdcb324362945 Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 18 Apr 2022 12:40:29 +0200 Subject: [PATCH 55/74] Changed the "all operator" `*` in `use ::*` to `use ::(*)` This may be subject to further changes --- src/lib/diagnostics/diagnostics_list.rs | 9 ++++++++- src/lib/parser/parsing_context.rs | 2 +- src/lib/parser2/mod.rs | 18 +++++++++++++++++- src/lib/resolver2/resolve_ctx.rs | 2 +- src/lib/rock.rs | 2 ++ src/lib/testcases/mods/basic_mod/main.rk | 2 +- src/lib/testcases/mods/full_fact/prelude.rk | 6 +++--- .../testcases/mods/func_arg_resolution/main.rk | 2 +- src/lib/testcases/mods/unused_fn/main.rk | 2 +- src/lib/testcases/mods/unused_impl_fn/main.rk | 2 +- 10 files changed, 36 insertions(+), 11 deletions(-) diff --git a/src/lib/diagnostics/diagnostics_list.rs b/src/lib/diagnostics/diagnostics_list.rs index 3015d0f0..838ad1fb 100644 --- a/src/lib/diagnostics/diagnostics_list.rs +++ b/src/lib/diagnostics/diagnostics_list.rs @@ -37,7 +37,14 @@ impl Diagnostics { pub fn print(&self, files: &HashMap) { for (i, diag) in self.list.iter().enumerate() { - let input = files.get(&diag.span.file_path).unwrap(); + let input = match files.get(&diag.span.file_path) { + Some(input) => input, + None => { + warn!("Diagnostic has been silenced because the file is not found"); + + continue; + } + }; diag.print(input, self.list_types.get(i).unwrap()); } diff --git a/src/lib/parser/parsing_context.rs b/src/lib/parser/parsing_context.rs index 88d589de..509051eb 100644 --- a/src/lib/parser/parsing_context.rs +++ b/src/lib/parser/parsing_context.rs @@ -16,7 +16,7 @@ use super::SourceFile; #[derive(Default, Debug)] pub struct ParsingCtx { - files: HashMap, + pub files: HashMap, pub config: Config, pub current_file: Option, pub diagnostics: Diagnostics, diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 1d6bb98b..dbcfac2a 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -16,6 +16,7 @@ use crate::ast::identity2::Identity; use crate::ast::tree2::*; use crate::ast::NodeId; use crate::parser::span2::Span; +use crate::parser::SourceFile; use crate::ty::{FuncType, PrimitiveType, Type}; use nom_locate::{position, LocatedSpan}; @@ -32,6 +33,7 @@ mod tests; #[derive(Debug, Clone)] pub struct ParserCtx { + files: HashMap, cur_file_path: PathBuf, identities: BTreeMap, operators_list: HashMap, @@ -43,6 +45,7 @@ pub struct ParserCtx { impl ParserCtx { pub fn new(file_path: PathBuf) -> Self { Self { + files: HashMap::new(), cur_file_path: file_path, identities: BTreeMap::new(), operators_list: HashMap::new(), @@ -55,6 +58,7 @@ impl ParserCtx { #[cfg(test)] pub fn new_with_operators(file_path: PathBuf, operators: HashMap) -> Self { Self { + files: HashMap::new(), cur_file_path: file_path, identities: BTreeMap::new(), operators_list: operators, @@ -66,6 +70,7 @@ impl ParserCtx { pub fn new_from(&self, name: &str) -> Self { Self { + files: HashMap::new(), cur_file_path: self .cur_file_path .parent() @@ -128,6 +133,10 @@ impl ParserCtx { pub fn operators_list(&self) -> HashMap { self.operators_list.clone() } + + pub fn files(&self) -> HashMap { + self.files.clone() + } } pub fn create_parser(s: &str) -> Parser<'_> { @@ -178,7 +187,13 @@ pub fn parse_comment(input: Parser) -> Res { pub fn parse_mod_decl(input: Parser) -> Res { let (mut input, mod_name) = preceded(terminated(tag("mod"), space1), parse_identifier)(input)?; - let new_ctx = input.extra.new_from(&mod_name.name); + let mut new_ctx = input.extra.new_from(&mod_name.name); + let file_path = new_ctx.current_file_path().to_str().unwrap().to_string(); + + let file = SourceFile::from_file(file_path).unwrap(); // FIXME: ERRORS ARE swallowed HERE + new_ctx + .files + .insert(new_ctx.current_file_path().clone(), file); let content = std::fs::read_to_string(&new_ctx.current_file_path()).unwrap(); @@ -198,6 +213,7 @@ pub fn parse_mod_decl(input: Parser) -> Res { // extend identities input.extra.identities.extend(input2.extra.identities); input.extra.next_node_id = input2.extra.next_node_id; + input.extra.files.extend(input2.extra.files); Ok((input, (mod_name, mod_))) } diff --git a/src/lib/resolver2/resolve_ctx.rs b/src/lib/resolver2/resolve_ctx.rs index 002d14e3..7660b1ea 100644 --- a/src/lib/resolver2/resolve_ctx.rs +++ b/src/lib/resolver2/resolve_ctx.rs @@ -205,7 +205,7 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { match self.scopes.get(&mod_path) { Some(scopes) => { - if ident.name == "*" { + if ident.name == "(*)" { let scope = scopes.scopes.get(0).unwrap(); for (k, v) in &scope.items.clone() { diff --git a/src/lib/rock.rs b/src/lib/rock.rs index bbcad991..144b3459 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -83,6 +83,8 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { parsing_ctx.identities = ctx.extra.identities(); + parsing_ctx.files = ctx.extra.files(); + ast.operators_list = ctx.extra.operators_list(); ast.spans = ctx.extra.identities().into_iter().collect(); diff --git a/src/lib/testcases/mods/basic_mod/main.rk b/src/lib/testcases/mods/basic_mod/main.rk index af567311..d80c607b 100644 --- a/src/lib/testcases/mods/basic_mod/main.rk +++ b/src/lib/testcases/mods/basic_mod/main.rk @@ -1,6 +1,6 @@ mod _std -use _std::* +use _std::(*) test g h i j = g diff --git a/src/lib/testcases/mods/full_fact/prelude.rk b/src/lib/testcases/mods/full_fact/prelude.rk index 7aea7a8b..4370815b 100644 --- a/src/lib/testcases/mods/full_fact/prelude.rk +++ b/src/lib/testcases/mods/full_fact/prelude.rk @@ -1,5 +1,5 @@ use super::print::print use super::show::show -use super::num::* -use super::eq::* -# use super::helpers::* +use super::num::(*) +use super::eq::(*) +# use super::helpers::(*) diff --git a/src/lib/testcases/mods/func_arg_resolution/main.rk b/src/lib/testcases/mods/func_arg_resolution/main.rk index 60417302..a1ecd045 100644 --- a/src/lib/testcases/mods/func_arg_resolution/main.rk +++ b/src/lib/testcases/mods/func_arg_resolution/main.rk @@ -1,6 +1,6 @@ mod _std -use _std::* +use _std::(*) f a = a + 2 diff --git a/src/lib/testcases/mods/unused_fn/main.rk b/src/lib/testcases/mods/unused_fn/main.rk index 5b8c85f1..4d476bfb 100644 --- a/src/lib/testcases/mods/unused_fn/main.rk +++ b/src/lib/testcases/mods/unused_fn/main.rk @@ -1,6 +1,6 @@ mod _std -use _std::* +use _std::(*) test g h = g diff --git a/src/lib/testcases/mods/unused_impl_fn/main.rk b/src/lib/testcases/mods/unused_impl_fn/main.rk index 9ddde04d..61b3a75d 100644 --- a/src/lib/testcases/mods/unused_impl_fn/main.rk +++ b/src/lib/testcases/mods/unused_impl_fn/main.rk @@ -1,6 +1,6 @@ mod _std -use _std::* +use _std::(*) test g h i j = g From 63a0db9265840905b959f04f8ad88ad9142de001 Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 18 Apr 2022 12:45:59 +0200 Subject: [PATCH 56/74] Fixed readme --- .github/templates/README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/.github/templates/README.md b/.github/templates/README.md index f0bfbd08..50ec8a21 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -89,7 +89,7 @@ Add some files like this: ```haskell mod lib -use lib::prelude::* +use lib::prelude::(*) fact a = if a <= 1 @@ -181,7 +181,7 @@ Test ``` haskell mod lib -use lib::prelude::* +use lib::prelude::(*) infix |> 1 |> x f = f x @@ -204,7 +204,7 @@ This `trait ToString` is redondant with the `trait Show` implemented in the lib, ``` haskell mod lib -use lib::prelude::* +use lib::prelude::(*) trait ToString a toString :: a -> String @@ -237,7 +237,7 @@ Prints ``` haskell mod lib -use lib::prelude::* +use lib::prelude::(*) struct Player level :: Int64 From 4c25798dfbbd56b5b5190e79c3eedd14c44a260f Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 18 Apr 2022 10:47:25 +0000 Subject: [PATCH 57/74] Generated files for new version --- README.md | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/README.md b/README.md index 86d88aa6..2208ac22 100644 --- a/README.md +++ b/README.md @@ -89,7 +89,7 @@ Add some files like this: ```haskell mod lib -use lib::prelude::* +use lib::prelude::(*) fact a = if a <= 1 @@ -181,7 +181,7 @@ Test ``` haskell mod lib -use lib::prelude::* +use lib::prelude::(*) infix |> 1 |> x f = f x @@ -204,7 +204,7 @@ This `trait ToString` is redondant with the `trait Show` implemented in the lib, ``` haskell mod lib -use lib::prelude::* +use lib::prelude::(*) trait ToString a toString :: a -> String @@ -237,7 +237,7 @@ Prints ``` haskell mod lib -use lib::prelude::* +use lib::prelude::(*) struct Player level :: Int64 From c91346ee29b0cb258378747dd093b456b76f76c0 Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 18 Apr 2022 12:47:05 +0200 Subject: [PATCH 58/74] Fixed readme --- .github/templates/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/templates/README.md b/.github/templates/README.md index 50ec8a21..42960b9b 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -154,7 +154,7 @@ This includes I/O of all sorts (Looking at you, open/read/write in loops) ``` haskell mod lib -use lib::prelude::* +use lib::prelude::(*) id a = a From 435fa9fb859cb5e03afd7c3ba1639811aebe6d12 Mon Sep 17 00:00:00 2001 From: Champii Date: Mon, 18 Apr 2022 10:48:27 +0000 Subject: [PATCH 59/74] Generated files for new version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 2208ac22..8f73f8c3 100644 --- a/README.md +++ b/README.md @@ -154,7 +154,7 @@ This includes I/O of all sorts (Looking at you, open/read/write in loops) ``` haskell mod lib -use lib::prelude::* +use lib::prelude::(*) id a = a From 56eda0311c3ac41d74f87d3ec20b356f312fa885 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 11:31:59 +0200 Subject: [PATCH 60/74] Fixed prototype parsing, 4 tests to go --- .github/templates/Cargo.toml | 3 +++ Cargo.lock | 2 +- Cargo.toml | 5 ++++- README.md | 10 +++++----- src/lib/infer/constraint.rs | 10 +++++----- src/lib/infer/mod.rs | 1 - src/lib/parser2/mod.rs | 5 +---- src/lib/ty/func_type.rs | 12 +++++++++++- std/src/clone.rk | 4 ++-- std/src/fs.rk | 6 +++--- std/src/functor.rk | 8 ++++---- std/src/lib.rk | 2 +- std/src/num.rk | 2 +- std/src/prelude.rk | 8 ++++---- std/src/print.rk | 2 +- std/src/show.rk | 8 ++++---- std/src/vec.rk | 6 +++--- 17 files changed, 53 insertions(+), 41 deletions(-) diff --git a/.github/templates/Cargo.toml b/.github/templates/Cargo.toml index 48842bc3..463911b3 100644 --- a/.github/templates/Cargo.toml +++ b/.github/templates/Cargo.toml @@ -23,6 +23,9 @@ rustyline = "9.0.0" nom = "7.0.0" nom_locate = "4.0.0" +[build-dependencies] +walkdir = "2" + [lib] name = "rock" path = "src/lib/rock.rs" diff --git a/Cargo.lock b/Cargo.lock index 2ff89c3f..9965e7b6 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -464,7 +464,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rock" -version = "0.1.8-new-parser" +version = "0.1.8-435fa9fb" dependencies = [ "bincode", "bitflags", diff --git a/Cargo.toml b/Cargo.toml index 1ef7317e..b47ba352 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.8-new-parser" +version = "0.1.8-435fa9fb" authors = ["champii "] edition = "2018" @@ -23,6 +23,9 @@ rustyline = "9.0.0" nom = "7.0.0" nom_locate = "4.0.0" +[build-dependencies] +walkdir = "2" + [lib] name = "rock" path = "src/lib/rock.rs" diff --git a/README.md b/README.md index 8f73f8c3..610e7ff7 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.8-new-parser +# Rock v0.1.8-435fa9fb -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=new_parser)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=435fa9fb)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little language made with Rust and LLVM. @@ -43,10 +43,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.8-new-parser](https://github.com/Champii/Rock/releases/download/v0.1.8-new-parser/rock) (Tested on arch, btw) +[Rock v0.1.8-435fa9fb](https://github.com/Champii/Rock/releases/download/v0.1.8-435fa9fb/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.8-new-parser/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.8-435fa9fb/rock chmod +x rock ./rock -V ``` @@ -124,7 +124,7 @@ rock --repl ``` ``` sh -Rock: v0.1.8-new-parser +Rock: v0.1.8-435fa9fb ---- Type ':?' for help diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index 68695467..cb7e2e1c 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -376,6 +376,10 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { let struct_t = t.as_struct_type(); s.defs.iter().for_each(|p| { + self.envs + .set_type(&p.hir_id, struct_t.defs.get(&p.name.name).unwrap()); + }); + /* s.defs.iter().for_each(|p| { let ty = *struct_t.defs.get(&p.name.name).unwrap().clone(); // FIXME: should not have to do this conversion from trait. @@ -388,7 +392,7 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { println!("TRANSFORMED {:#?}", ty); self.envs.set_type(&p.hir_id, &ty) - }); + }); */ } fn visit_struct_ctor(&mut self, s: &StructCtor) { @@ -398,8 +402,6 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { let t = s_decl.into(); - println!("TYPE {:#?}", t); - self.envs.set_type(&s.name.hir_id, &t); let struct_t = t.as_struct_type(); @@ -718,13 +720,11 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { pub fn solve(root: &mut Root) -> (BTreeMap>, Diagnostics) { let diagnostics = Diagnostics::default(); - // println!("ROOT {:#?}", root.get_hir_spans()); let infer_state = Envs::new(diagnostics, root.get_hir_spans()); let mut constraint_ctx = ConstraintContext::new(infer_state, root); constraint_ctx.constraint(root); - println!("here_final"); let tmp_resolutions = constraint_ctx.tmp_resolutions.clone(); diff --git a/src/lib/infer/mod.rs b/src/lib/infer/mod.rs index 7a838e1e..d67874d4 100644 --- a/src/lib/infer/mod.rs +++ b/src/lib/infer/mod.rs @@ -12,7 +12,6 @@ pub fn infer( parsing_ctx: &mut ParsingCtx, config: &Config, ) -> Result { - println!("lol"); let (tmp_resolutions, diags) = constraint::solve(root); parsing_ctx.diagnostics.append(diags); diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index dbcfac2a..37913e65 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -859,10 +859,7 @@ pub fn parse_signature(input: Parser) -> Res { let ret = types.pop().unwrap(); - Ok(( - input, - FuncType::from_args_nb(types.len()).apply_types(types, ret), - )) + Ok((input, FuncType::new(types, ret))) } pub fn parse_type(input: Parser) -> Res { diff --git a/src/lib/ty/func_type.rs b/src/lib/ty/func_type.rs index 6484eeca..a4ff9db1 100644 --- a/src/lib/ty/func_type.rs +++ b/src/lib/ty/func_type.rs @@ -123,7 +123,7 @@ impl FuncType { .enumerate() .filter_map(|(i, arg_t)| -> Option<(Type, Type)> { if !arg_t.is_forall() { - warn!("Trying to apply type to a not forall"); + warn!("Trying to apply type to a not forall: {:#?}", arg_t); return None; } @@ -318,4 +318,14 @@ mod tests { assert_eq!(res.arguments[1], Type::int64()); assert_eq!(*res.ret, Type::int64()); } + + #[test] + fn apply_to_same_forall() { + let sig = FuncType::new(vec![Type::forall("a")], Type::forall("a")); + + let res = sig.apply_forall_types(&[Type::forall("a")], &[Type::int64()]); + + assert_eq!(res.arguments[0], Type::int64()); + assert_eq!(*res.ret, Type::int64()); + } } diff --git a/std/src/clone.rk b/std/src/clone.rk index 26f82b8b..6f6ff74a 100644 --- a/std/src/clone.rk +++ b/std/src/clone.rk @@ -1,4 +1,4 @@ -use super::externs::* +use super::externs::(*) trait Clone a clone :: a -> a @@ -15,7 +15,7 @@ impl Clone String c_strcpy s, a s -use super::functor::* +use super::functor::(*) impl Clone [Int64] clone a = map clone, a diff --git a/std/src/fs.rk b/std/src/fs.rk index 6b6a1605..5a143301 100644 --- a/std/src/fs.rk +++ b/std/src/fs.rk @@ -1,9 +1,9 @@ -use super::externs::* +use super::externs::(*) use super::print::print use super::show::show -use super::num::* -use super::eq::* +use super::num::(*) +use super::eq::(*) struct File fd :: Int64 diff --git a/std/src/functor.rk b/std/src/functor.rk index 40106f5a..bdd97f93 100644 --- a/std/src/functor.rk +++ b/std/src/functor.rk @@ -1,17 +1,17 @@ -use super::num::* -use super::eq::* +use super::num::(*) +use super::eq::(*) map f arr = let i = 0 let arr2 = arr - for i < (~Len arr arr) + while i < (~Len arr arr) arr2[i] = f arr[i] i = i + 1 arr2 foreach f arr = let i = 0 - for i < (~Len arr arr) + while i < (~Len arr arr) f arr[i] i = i + 1 arr diff --git a/std/src/lib.rk b/std/src/lib.rk index 38acebaf..5d4d3acf 100644 --- a/std/src/lib.rk +++ b/std/src/lib.rk @@ -1,5 +1,5 @@ mod externs -use externs::* +use externs::(*) mod num mod eq diff --git a/std/src/num.rk b/std/src/num.rk index fb502840..f9f84ffc 100644 --- a/std/src/num.rk +++ b/std/src/num.rk @@ -21,7 +21,7 @@ impl Num Float64 * c d = ~FMul c d / c d = ~FDiv c d -use super::externs::* +use super::externs::(*) impl Num String + a b = diff --git a/std/src/prelude.rk b/std/src/prelude.rk index 0159ee59..9135268e 100644 --- a/std/src/prelude.rk +++ b/std/src/prelude.rk @@ -1,6 +1,6 @@ use super::show::show use super::print::print -use super::num::* -use super::eq::* -use super::functor::* -use super::clone::* +use super::num::(*) +use super::eq::(*) +use super::functor::(*) +use super::clone::(*) diff --git a/std/src/print.rk b/std/src/print.rk index db34cd91..785eac65 100644 --- a/std/src/print.rk +++ b/std/src/print.rk @@ -1,4 +1,4 @@ -use super::externs::* +use super::externs::(*) use super::show::show print a = c_puts show a diff --git a/std/src/show.rk b/std/src/show.rk index 5b573f98..740fe3ee 100644 --- a/std/src/show.rk +++ b/std/src/show.rk @@ -1,6 +1,6 @@ -use super::externs::* -use super::num::* -use super::eq::* +use super::externs::(*) +use super::num::(*) +use super::eq::(*) itoa a = let s = c_malloc 10 @@ -45,7 +45,7 @@ show_arr a = let len = ~Len a a - for i < len + while i < len c_strcat s, show a[i] c_strcat s, ", " diff --git a/std/src/vec.rk b/std/src/vec.rk index 1486141d..4157e4a9 100644 --- a/std/src/vec.rk +++ b/std/src/vec.rk @@ -4,7 +4,7 @@ struct Vec len :: Int64 use super::show::show -use super::externs::* +use super::externs::(*) impl Show Vec show v = show v.len @@ -16,8 +16,8 @@ new_vec = len: 0 -use super::num::* -use super::eq::* +use super::num::(*) +use super::eq::(*) realloc_vec v = let orig_data = v.data From 724ec1be9d7a983f278283df110bda5706588dc5 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 09:33:32 +0000 Subject: [PATCH 61/74] Generated files for new version --- Cargo.toml | 2 +- README.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index b47ba352..12509478 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.8-435fa9fb" +version = "0.1.8-new-parser" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 610e7ff7..8f73f8c3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.8-435fa9fb +# Rock v0.1.8-new-parser -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=435fa9fb)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=new_parser)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little language made with Rust and LLVM. @@ -43,10 +43,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.8-435fa9fb](https://github.com/Champii/Rock/releases/download/v0.1.8-435fa9fb/rock) (Tested on arch, btw) +[Rock v0.1.8-new-parser](https://github.com/Champii/Rock/releases/download/v0.1.8-new-parser/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.8-435fa9fb/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.8-new-parser/rock chmod +x rock ./rock -V ``` @@ -124,7 +124,7 @@ rock --repl ``` ``` sh -Rock: v0.1.8-435fa9fb +Rock: v0.1.8-new-parser ---- Type ':?' for help From bdd5724208bd07672bfbdaf1298022cb806823ec Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 12:18:04 +0200 Subject: [PATCH 62/74] Update readme --- .github/templates/README.md | 17 +++++++++++------ Cargo.lock | 2 +- 2 files changed, 12 insertions(+), 7 deletions(-) diff --git a/.github/templates/README.md b/.github/templates/README.md index 42960b9b..f216af74 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -4,8 +4,8 @@ Little language made with Rust and LLVM. -Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. -It's highly inspired from Livescript, and will borrow (pun intended) some features and syntaxes from Crystal, from functional languages like Haskell, or even from Rust itself. +Aim to follow the enforced safeness of the Rust model with a borrow checker (Soonâ„¢) and achieve high native performances thanks to LLVM. +Rock is highly inspired from Livescript and Rust, and will also borrow (pun intended) some features from Crystal, from functional languages like Haskell, and even from Rust itself. No to be taken seriously (yet) @@ -27,7 +27,7 @@ No to be taken seriously (yet) - Type inference - Custom operators - Typeclass (Traits) -- Parametric Polymorphism by default +- Polymorphism by default - Compile to LLVM IR - REPL (ALPHA) @@ -58,7 +58,7 @@ You will need `llvm-12.0.1` and `clang-12.0.1` somewhere in your $PATH #### With cargo from git ``` sh -cargo install --git https://github.com/Champii/Rock +cargo install --git https://github.com/Champii/Rock --locked rock -V ``` @@ -82,9 +82,9 @@ mkdir -P factorial/src && cd factorial Add some files like this: -- Copy the std lib files from [std](https://github.com/Champii/Rock/blob/master/std/src) into `./src/` +- Copy all the stdlib files from [std/src/\*.rk](https://github.com/Champii/Rock/blob/master/std/src) into `factorial/src/` -- Create a `./src/main.rk` file: +- Create a `factorial/src/main.rk` file: ```haskell mod lib @@ -113,6 +113,8 @@ Should output Take a look at `rock --help` for a quick tour of its flags and arguments +Note that you currently must be at the project root to run the compiler. (i.e. inside the `./factorial/` folder) + ### REPL You can start a REPL session with @@ -146,6 +148,9 @@ Only supports basic expressions for now. Be warned that for a given session, the whole code is re-executed at each entry. This includes I/O of all sorts (Looking at you, open/read/write in loops) +Note that the REPL expects to be run from the project root, and expects some version of the stdlib +to be available in the `./src` folder + ## Showcases ### Polymophic function diff --git a/Cargo.lock b/Cargo.lock index 9965e7b6..2ff89c3f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -464,7 +464,7 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b" [[package]] name = "rock" -version = "0.1.8-435fa9fb" +version = "0.1.8-new-parser" dependencies = [ "bincode", "bitflags", From c85166f3d4dc416f11628f8f0ec81a2f5c5fa537 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 10:19:32 +0000 Subject: [PATCH 63/74] Generated files for new version --- README.md | 17 +++++++++++------ 1 file changed, 11 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 8f73f8c3..d325643a 100644 --- a/README.md +++ b/README.md @@ -4,8 +4,8 @@ Little language made with Rust and LLVM. -Aim to follow the Rust model with enforced safeness with a borrow checker and native performances thanks to LLVM. -It's highly inspired from Livescript, and will borrow (pun intended) some features and syntaxes from Crystal, from functional languages like Haskell, or even from Rust itself. +Aim to follow the enforced safeness of the Rust model with a borrow checker (Soonâ„¢) and achieve high native performances thanks to LLVM. +Rock is highly inspired from Livescript and Rust, and will also borrow (pun intended) some features from Crystal, from functional languages like Haskell, and even from Rust itself. No to be taken seriously (yet) @@ -27,7 +27,7 @@ No to be taken seriously (yet) - Type inference - Custom operators - Typeclass (Traits) -- Parametric Polymorphism by default +- Polymorphism by default - Compile to LLVM IR - REPL (ALPHA) @@ -58,7 +58,7 @@ You will need `llvm-12.0.1` and `clang-12.0.1` somewhere in your $PATH #### With cargo from git ``` sh -cargo install --git https://github.com/Champii/Rock +cargo install --git https://github.com/Champii/Rock --locked rock -V ``` @@ -82,9 +82,9 @@ mkdir -P factorial/src && cd factorial Add some files like this: -- Copy the std lib files from [std](https://github.com/Champii/Rock/blob/master/std/src) into `./src/` +- Copy all the stdlib files from [std/src/\*.rk](https://github.com/Champii/Rock/blob/master/std/src) into `factorial/src/` -- Create a `./src/main.rk` file: +- Create a `factorial/src/main.rk` file: ```haskell mod lib @@ -113,6 +113,8 @@ Should output Take a look at `rock --help` for a quick tour of its flags and arguments +Note that you currently must be at the project root to run the compiler. (i.e. inside the `./factorial/` folder) + ### REPL You can start a REPL session with @@ -146,6 +148,9 @@ Only supports basic expressions for now. Be warned that for a given session, the whole code is re-executed at each entry. This includes I/O of all sorts (Looking at you, open/read/write in loops) +Note that the REPL expects to be run from the project root, and expects some version of the stdlib +to be available in the `./src` folder + ## Showcases ### Polymophic function From 25aae815f17792c7fce8b97890884974e7e8960f Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 12:25:31 +0200 Subject: [PATCH 64/74] Update readme --- .github/templates/README.md | 81 +++++++++++++++++++------------------ 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/.github/templates/README.md b/.github/templates/README.md index f216af74..b7abfbfd 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -16,9 +16,11 @@ No to be taken seriously (yet) - [With cargo from Git]( #with-cargo-from-git ) - [From sources]( #from-sources ) - [Quickstart]( #quickstart ) - - [Basic setup]( #basic-setup ) - - [REPL]( #repl ) - [Showcases]( #showcases ) + - [Polymorphic function]( #polymorphic-function ) + - [Custom infix operator]( #custom-infix-operator ) + - [Trait definition]( #trait-definition ) +- [REPL]( #repl ) - [Development notes]( #development-notes ) ## Features @@ -72,8 +74,6 @@ cargo run -- -V ## Quickstart -### Basic setup - Lets create a new project folder to compute some factorials ``` sh @@ -115,42 +115,6 @@ Take a look at `rock --help` for a quick tour of its flags and arguments Note that you currently must be at the project root to run the compiler. (i.e. inside the `./factorial/` folder) -### REPL - -You can start a REPL session with - -``` sh -rock -r -# OR -rock --repl -``` - -``` sh -Rock: {version} ----- - -Type ':?' for help - -> add a b = a + b -> let x = 30 -30 -> let y = 12 -12 -> add x, y -42 -> :t add -add: (Int64 -> Int64 -> Int64) -> _ -``` - -Only supports basic expressions for now. - -Be warned that for a given session, the whole code is re-executed at each entry. -This includes I/O of all sorts (Looking at you, open/read/write in loops) - -Note that the REPL expects to be run from the project root, and expects some version of the stdlib -to be available in the `./src` folder - ## Showcases ### Polymophic function @@ -266,6 +230,43 @@ rock run Prints `MyName` +## REPL + +Only supports basic expressions for now. +Very unstable, very work in progress. + +Be warned that for a given session, the whole code is re-executed at each entry. +This includes I/O of all sorts (Looking at you, open/read/write in loops) + +Note that the REPL expects to be run from the project root, and expects some version of the stdlib +to be available in the `./src` folder + +You can start a REPL session with + +``` sh +rock -r +# OR +rock --repl +``` + +``` sh +Rock: {version} +---- + +Type ':?' for help + +> add a b = a + b +> let x = 30 +30 +> let y = 12 +12 +> add x, y +42 +> :t add +add: (Int64 -> Int64 -> Int64) +> _ +``` + ## Development notes This project, its syntax and its APIs are subject to change at any moment. From 46acb648f0873f8db6a25cb707d0b5922e3cfa54 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 10:28:16 +0000 Subject: [PATCH 65/74] Generated files for new version --- README.md | 81 ++++++++++++++++++++++++++++--------------------------- 1 file changed, 41 insertions(+), 40 deletions(-) diff --git a/README.md b/README.md index d325643a..576dde58 100644 --- a/README.md +++ b/README.md @@ -16,9 +16,11 @@ No to be taken seriously (yet) - [With cargo from Git]( #with-cargo-from-git ) - [From sources]( #from-sources ) - [Quickstart]( #quickstart ) - - [Basic setup]( #basic-setup ) - - [REPL]( #repl ) - [Showcases]( #showcases ) + - [Polymorphic function]( #polymorphic-function ) + - [Custom infix operator]( #custom-infix-operator ) + - [Trait definition]( #trait-definition ) +- [REPL]( #repl ) - [Development notes]( #development-notes ) ## Features @@ -72,8 +74,6 @@ cargo run -- -V ## Quickstart -### Basic setup - Lets create a new project folder to compute some factorials ``` sh @@ -115,42 +115,6 @@ Take a look at `rock --help` for a quick tour of its flags and arguments Note that you currently must be at the project root to run the compiler. (i.e. inside the `./factorial/` folder) -### REPL - -You can start a REPL session with - -``` sh -rock -r -# OR -rock --repl -``` - -``` sh -Rock: v0.1.8-new-parser ----- - -Type ':?' for help - -> add a b = a + b -> let x = 30 -30 -> let y = 12 -12 -> add x, y -42 -> :t add -add: (Int64 -> Int64 -> Int64) -> _ -``` - -Only supports basic expressions for now. - -Be warned that for a given session, the whole code is re-executed at each entry. -This includes I/O of all sorts (Looking at you, open/read/write in loops) - -Note that the REPL expects to be run from the project root, and expects some version of the stdlib -to be available in the `./src` folder - ## Showcases ### Polymophic function @@ -266,6 +230,43 @@ rock run Prints `MyName` +## REPL + +Only supports basic expressions for now. +Very unstable, very work in progress. + +Be warned that for a given session, the whole code is re-executed at each entry. +This includes I/O of all sorts (Looking at you, open/read/write in loops) + +Note that the REPL expects to be run from the project root, and expects some version of the stdlib +to be available in the `./src` folder + +You can start a REPL session with + +``` sh +rock -r +# OR +rock --repl +``` + +``` sh +Rock: v0.1.8-new-parser +---- + +Type ':?' for help + +> add a b = a + b +> let x = 30 +30 +> let y = 12 +12 +> add x, y +42 +> :t add +add: (Int64 -> Int64 -> Int64) +> _ +``` + ## Development notes This project, its syntax and its APIs are subject to change at any moment. From 540fe33f58050ab79ee626dcd650f7710d3de960 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 12:28:16 +0200 Subject: [PATCH 66/74] Fix typo in readme --- .github/templates/README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/templates/README.md b/.github/templates/README.md index b7abfbfd..6b1a963d 100644 --- a/.github/templates/README.md +++ b/.github/templates/README.md @@ -117,7 +117,7 @@ Note that you currently must be at the project root to run the compiler. (i.e. i ## Showcases -### Polymophic function +### Polymorphic function ``` haskell From e2f5d583cd31c80805bdc9d441ea5157d285afaa Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 10:29:47 +0000 Subject: [PATCH 67/74] Generated files for new version --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 576dde58..9db1138f 100644 --- a/README.md +++ b/README.md @@ -117,7 +117,7 @@ Note that you currently must be at the project root to run the compiler. (i.e. i ## Showcases -### Polymophic function +### Polymorphic function ``` haskell From 2e9f4793f58b73f236360cdc245c38106b2d17b4 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 17:23:31 +0200 Subject: [PATCH 68/74] All tests passed --- src/lib/infer/constraint.rs | 3 +- src/lib/parser2/mod.rs | 45 ++++++++++++++++++++++++--- src/lib/testcases/basic/while/main.rk | 2 -- src/lib/ty/type.rs | 2 +- 4 files changed, 43 insertions(+), 9 deletions(-) diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index cb7e2e1c..14b78f45 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -379,12 +379,13 @@ impl<'a, 'ar> Visitor<'a> for ConstraintContext<'ar> { self.envs .set_type(&p.hir_id, struct_t.defs.get(&p.name.name).unwrap()); }); + // FIXME: should be done in the ast_lowering phase /* s.defs.iter().for_each(|p| { let ty = *struct_t.defs.get(&p.name.name).unwrap().clone(); // FIXME: should not have to do this conversion from trait. let ty = if let Type::Trait(t) = ty.clone() { - // println!("WHAT {:#?}, {:#?}, {:#?}", p, t, self.hir.structs); + println!("WHAT {:#?}, {:#?}, {:#?}", p, t, self.hir.structs); self.hir.structs.get(&ty.get_name()).unwrap().to_type() } else { ty diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs index 37913e65..487cf1cf 100644 --- a/src/lib/parser2/mod.rs +++ b/src/lib/parser2/mod.rs @@ -17,7 +17,7 @@ use crate::ast::tree2::*; use crate::ast::NodeId; use crate::parser::span2::Span; use crate::parser::SourceFile; -use crate::ty::{FuncType, PrimitiveType, Type}; +use crate::ty::{FuncType, PrimitiveType, StructType, Type}; use nom_locate::{position, LocatedSpan}; pub type Parser<'a> = LocatedSpan<&'a str, ParserCtx>; @@ -40,6 +40,7 @@ pub struct ParserCtx { block_indent: usize, first_indent: Option, next_node_id: NodeId, + structs: HashMap, } impl ParserCtx { @@ -52,6 +53,7 @@ impl ParserCtx { block_indent: 0, first_indent: None, next_node_id: 0, + structs: HashMap::new(), } } @@ -65,6 +67,7 @@ impl ParserCtx { block_indent: 0, first_indent: None, next_node_id: 0, + structs: HashMap::new(), } } @@ -81,6 +84,7 @@ impl ParserCtx { block_indent: 0, first_indent: None, next_node_id: self.next_node_id, + structs: HashMap::new(), } } @@ -184,6 +188,12 @@ pub fn parse_comment(input: Parser) -> Res { Ok((input, ())) } +pub fn parse_eol(input: Parser) -> Res { + let (input, _) = tuple((opt(parse_comment), line_ending))(input)?; + + Ok((input, ())) +} + pub fn parse_mod_decl(input: Parser) -> Res { let (mut input, mod_name) = preceded(terminated(tag("mod"), space1), parse_identifier)(input)?; @@ -251,7 +261,7 @@ pub fn parse_impl(input: Parser) -> Res { } pub fn parse_struct_decl(input: Parser) -> Res { - map( + let (mut input, struct_decl) = map( tuple(( terminated(tag("struct"), space1), parse_capitalized_identifier, @@ -262,7 +272,16 @@ pub fn parse_struct_decl(input: Parser) -> Res { )), )), |(tag, name, _, defs)| StructDecl::new(name, defs), - )(input) + )(input)?; + + let struct_t: StructType = struct_decl.clone().into(); + + input + .extra + .structs + .insert(struct_decl.name.name.clone(), struct_t.into()); + + Ok((input, struct_decl)) } pub fn parse_use(input: Parser) -> Res { @@ -336,7 +355,7 @@ pub fn parse_fn(input: Parser) -> Res { node_id, name, body, - signature: FuncType::from_args_nb(arguments.len()), + signature: FuncType::from_args_nb(arguments.len()), // FIXME: Should not generate random signature arguments, }, )(input) @@ -386,7 +405,7 @@ pub fn parse_body(mut input: Parser) -> Res { if opt_eol.is_some() { indent(map( separated_list1( - many1(line_ending), + many1(parse_eol), preceded(parse_block_indent, parse_statement), ), Body::new, @@ -886,12 +905,28 @@ pub fn parse_type(input: Parser) -> Res { )), |t| Type::from(t), ), + map(parse_struct_type, Type::Struct), map(parse_capitalized_text, Type::Trait), ))(input)?; Ok((input, ty)) } +pub fn parse_struct_type(input: Parser) -> Res { + let (input, name) = parse_capitalized_text(input)?; + + let ty = if let Some(struct_t) = input.extra.structs.get(&name) { + struct_t.as_struct_type() + } else { + return Err(nom::Err::Error(ParseError::from_error_kind( + input, + ErrorKind::Tag, + ))); + }; + + Ok((input, ty)) +} + pub fn parse_capitalized_text(input: Parser) -> Res { let (input, parsed) = tuple((satisfy(char::is_uppercase), alphanumeric0))(input)?; diff --git a/src/lib/testcases/basic/while/main.rk b/src/lib/testcases/basic/while/main.rk index 8286a272..392e7206 100644 --- a/src/lib/testcases/basic/while/main.rk +++ b/src/lib/testcases/basic/while/main.rk @@ -7,8 +7,6 @@ infix < 3 main = let i = 0 let x = 42 - # This fails because old parser does not handle while keyword - # Waiting for new parser to be merged while i < x i = i + 1 i diff --git a/src/lib/ty/type.rs b/src/lib/ty/type.rs index 8b0ab68c..301065ed 100644 --- a/src/lib/ty/type.rs +++ b/src/lib/ty/type.rs @@ -151,7 +151,7 @@ impl fmt::Debug for Type { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let s = match self { Self::Func(f) => format!("{:?}", f), - Self::Struct(s) => format!("{{{:?}}}", s), + Self::Struct(s) => format!("{:?}", s), Self::Trait(t) => format!("Trait {:?}", t), Self::ForAll(t) => format!("forall. {:?}", t), Self::Undefined(t) => format!("UNDEFINED {:?}", t), From 83292d252aa0eba229666a96ba9bd394199a04c1 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 17:55:41 +0200 Subject: [PATCH 69/74] First cleanup pass --- src/lib/ast/ast_print.rs | 4 +- src/lib/ast/identity.rs | 39 - src/lib/ast/identity2.rs | 15 - src/lib/ast/mod.rs | 10 +- src/lib/ast/return_placement.rs | 18 +- src/lib/ast/return_placement2.rs | 77 - src/lib/ast/span_collector.rs | 65 - src/lib/ast/tree.rs | 557 +++++-- src/lib/ast/tree2.rs | 924 ------------ src/lib/ast/visit.rs | 64 +- src/lib/ast/visit2.rs | 304 ---- src/lib/ast_lowering/ast_lowering_context.rs | 94 +- src/lib/ast_lowering/hir_map.rs | 12 +- src/lib/ast_lowering/infix_desugar.rs | 14 +- src/lib/ast_lowering/mod.rs | 2 +- src/lib/ast_lowering2/ast_lowering_context.rs | 495 ------- src/lib/ast_lowering2/hir_map.rs | 66 - src/lib/ast_lowering2/infix_desugar.rs | 87 -- src/lib/ast_lowering2/loop_desugar.rs | 63 - src/lib/ast_lowering2/mod.rs | 13 - src/lib/diagnostics/diagnostic.rs | 4 +- src/lib/hir/tree.rs | 4 +- src/lib/infer/constraint.rs | 2 +- src/lib/infer/monomorphize/mod.rs | 2 +- src/lib/infer/monomorphize/monomorphizer.rs | 2 +- src/lib/parser/lexer.rs | 594 -------- src/lib/parser/mod.rs | 1019 ++++++++++++- src/lib/parser/parser_impl.rs | 1312 ----------------- src/lib/parser/parsing_context.rs | 10 +- src/lib/parser/source_file.rs | 2 +- src/lib/parser/span2.rs | 2 +- src/lib/parser/token.rs | 86 -- src/lib/parser2/mod.rs | 985 ------------- src/lib/parser2/tests.rs | 903 ------------ src/lib/resolver/mod.rs | 12 +- src/lib/resolver/resolution_map.rs | 2 +- src/lib/resolver/resolve_ctx.rs | 123 +- src/lib/resolver/unused_collector.rs | 51 +- src/lib/resolver2/mod.rs | 46 - src/lib/resolver2/resolution_map.rs | 57 - src/lib/resolver2/resolve_ctx.rs | 299 ---- src/lib/resolver2/unused_collector.rs | 111 -- src/lib/rock.rs | 16 +- src/lib/ty/struct_type.rs | 20 +- 44 files changed, 1662 insertions(+), 6925 deletions(-) delete mode 100644 src/lib/ast/identity.rs delete mode 100644 src/lib/ast/identity2.rs delete mode 100644 src/lib/ast/return_placement2.rs delete mode 100644 src/lib/ast/span_collector.rs delete mode 100644 src/lib/ast/tree2.rs delete mode 100644 src/lib/ast/visit2.rs delete mode 100644 src/lib/ast_lowering2/ast_lowering_context.rs delete mode 100644 src/lib/ast_lowering2/hir_map.rs delete mode 100644 src/lib/ast_lowering2/infix_desugar.rs delete mode 100644 src/lib/ast_lowering2/loop_desugar.rs delete mode 100644 src/lib/ast_lowering2/mod.rs delete mode 100644 src/lib/parser/lexer.rs delete mode 100644 src/lib/parser/parser_impl.rs delete mode 100644 src/lib/parser/token.rs delete mode 100644 src/lib/parser2/mod.rs delete mode 100644 src/lib/parser2/tests.rs delete mode 100644 src/lib/resolver2/mod.rs delete mode 100644 src/lib/resolver2/resolution_map.rs delete mode 100644 src/lib/resolver2/resolve_ctx.rs delete mode 100644 src/lib/resolver2/unused_collector.rs diff --git a/src/lib/ast/ast_print.rs b/src/lib/ast/ast_print.rs index e91c5027..dbdf59ca 100644 --- a/src/lib/ast/ast_print.rs +++ b/src/lib/ast/ast_print.rs @@ -1,7 +1,7 @@ use std::fmt::Debug; -use crate::ast::tree2::*; -use crate::ast::visit2::*; +use crate::ast::tree::*; +use crate::ast::visit::*; use crate::helpers::*; use crate::ty::*; use paste::paste; diff --git a/src/lib/ast/identity.rs b/src/lib/ast/identity.rs deleted file mode 100644 index 5defa86e..00000000 --- a/src/lib/ast/identity.rs +++ /dev/null @@ -1,39 +0,0 @@ -use std::sync::atomic::{AtomicU64, Ordering}; - -use crate::parser::{Span, TokenId}; - -use crate::ast::NodeId; - -static GLOBAL_NEXT_NODE_ID: AtomicU64 = AtomicU64::new(0); - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct Identity { - pub node_id: NodeId, - pub token_id: TokenId, - pub span: Span, - pub scope_depth: u8, -} - -impl Identity { - pub fn new(token_id: TokenId, span: Span) -> Self { - Self { - span, - node_id: Self::next_node_id(), - token_id, - scope_depth: 0, - } - } - - pub fn new_placeholder() -> Self { - Self { - span: Span::new_placeholder(), - node_id: 0, - token_id: 0, - scope_depth: 0, - } - } - - pub fn next_node_id() -> NodeId { - GLOBAL_NEXT_NODE_ID.fetch_add(1, Ordering::SeqCst) - } -} diff --git a/src/lib/ast/identity2.rs b/src/lib/ast/identity2.rs deleted file mode 100644 index 42030b44..00000000 --- a/src/lib/ast/identity2.rs +++ /dev/null @@ -1,15 +0,0 @@ -use crate::parser::span2::Span; - -use crate::ast::NodeId; - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct Identity { - pub node_id: NodeId, - pub span: Span, -} - -impl Identity { - pub fn new(node_id: NodeId, span: Span) -> Self { - Self { span, node_id } - } -} diff --git a/src/lib/ast/mod.rs b/src/lib/ast/mod.rs index 4d6bb6e4..f040355b 100644 --- a/src/lib/ast/mod.rs +++ b/src/lib/ast/mod.rs @@ -1,20 +1,12 @@ #[macro_use] pub mod ast_print; -mod identity; -pub mod identity2; pub mod return_placement; -pub mod return_placement2; -pub mod span_collector; -mod tree; -pub mod tree2; +pub mod tree; pub mod visit; -pub mod visit2; -pub use identity::*; pub use tree::*; pub use visit::*; -// pub use visit2; // TODO: Make it the same way as HirId and FnBodyId ? pub type NodeId = u64; diff --git a/src/lib/ast/return_placement.rs b/src/lib/ast/return_placement.rs index 0e58d49b..4d879355 100644 --- a/src/lib/ast/return_placement.rs +++ b/src/lib/ast/return_placement.rs @@ -1,4 +1,4 @@ -use crate::ast::*; +use crate::ast::tree::*; pub struct ReturnInserter<'a> { pub body: &'a Body, @@ -36,17 +36,17 @@ impl<'a> ReturnInserter<'a> { fn visit_statement(&mut self, stmt: &mut Statement) { let mut is_assign = None; - match *stmt.kind { - StatementKind::Expression(ref mut e) => { - e.kind = ExpressionKind::Return(e.clone()); + match *stmt { + Statement::Expression(ref mut e) => { + *e = Box::new(Expression::Return(e.clone())); } - StatementKind::If(ref mut i) => { + Statement::If(ref mut i) => { self.visit_if(i); } - StatementKind::Assign(ref mut a) => { + Statement::Assign(ref mut a) => { is_assign = Some(a.value.clone()); } - StatementKind::For(ref mut _fa) => { + Statement::For(ref mut _fa) => { unimplemented!("Cannot have loop in return position"); } } @@ -54,9 +54,7 @@ impl<'a> ReturnInserter<'a> { // FIXME: do this only if a.name is Identifier // or else return the ident if let Some(value) = is_assign { - stmt.kind = Box::new(StatementKind::Expression(Box::new(Expression { - kind: ExpressionKind::Return(Box::new(value)), - }))); + *stmt = Statement::Expression(Box::new(Expression::Return(Box::new(value)))); } } diff --git a/src/lib/ast/return_placement2.rs b/src/lib/ast/return_placement2.rs deleted file mode 100644 index 18069af7..00000000 --- a/src/lib/ast/return_placement2.rs +++ /dev/null @@ -1,77 +0,0 @@ -use crate::ast::tree2::*; - -pub struct ReturnInserter<'a> { - pub body: &'a Body, -} - -impl<'a> ReturnInserter<'a> { - pub fn run(&mut self) -> Body { - let mut body = self.body.clone(); - - self.visit_body(&mut body); - - body.clone() - } - - fn visit_body(&mut self, body: &mut Body) { - // let mut is_assign = None; - - if let Some(stmt) = body.stmts.iter_mut().last() { - // if let StatementKind::Assign(ref mut a) = *stmt.kind.clone() { - // is_assign = Some(a.clone()); - // } - - self.visit_statement(stmt); - } - - // if let Some(a) = is_assign { - // body.stmts.push(Statement { - // kind: Box::new(StatementKind::Expression(Box::new(Expression { - // kind: ExpressionKind::Return(Box::new(a.name.as_expression())), - // }))), - // }); - // } - } - - fn visit_statement(&mut self, stmt: &mut Statement) { - let mut is_assign = None; - - match *stmt { - Statement::Expression(ref mut e) => { - *e = Box::new(Expression::Return(e.clone())); - } - Statement::If(ref mut i) => { - self.visit_if(i); - } - Statement::Assign(ref mut a) => { - is_assign = Some(a.value.clone()); - } - Statement::For(ref mut _fa) => { - unimplemented!("Cannot have loop in return position"); - } - } - - // FIXME: do this only if a.name is Identifier - // or else return the ident - if let Some(value) = is_assign { - *stmt = Statement::Expression(Box::new(Expression::Return(Box::new(value)))); - } - } - - fn visit_if(&mut self, r#if: &mut If) { - self.visit_body(&mut r#if.body); - - if let Some(ref mut r#else) = r#if.else_.as_mut() { - self.visit_else(r#else); - } else { - unimplemented!("Else is not found"); - } - } - - fn visit_else(&mut self, r#else: &mut Else) { - match r#else { - Else::If(i) => self.visit_if(i), - Else::Body(b) => self.visit_body(b), - } - } -} diff --git a/src/lib/ast/span_collector.rs b/src/lib/ast/span_collector.rs deleted file mode 100644 index 627846b8..00000000 --- a/src/lib/ast/span_collector.rs +++ /dev/null @@ -1,65 +0,0 @@ -use paste::paste; -use std::collections::HashMap; - -use crate::ast::visit::*; -use crate::parser::Span; -use crate::{ast::visit::Visitor, ast::*}; - -#[derive(Debug, Default)] -pub struct SpanCollector { - list: HashMap, -} - -impl SpanCollector { - pub fn new() -> Self { - Self { - ..Default::default() - } - } - - pub fn take_list(self) -> HashMap { - self.list - } - - pub fn insert(&mut self, ident: &Identity) { - self.list.insert(ident.node_id, ident.span.clone()); - } -} - -macro_rules! generate_span_collector { - ($($expr:ty)+) => { - impl<'a> Visitor<'a> for SpanCollector { - paste! { - $( - fn [](&mut self, node: &'a $expr) { - self.insert(&node.identity); - - [](self, node); - } - )+ - } - } - }; -} - -generate_span_collector!( - Mod - TopLevel - Prototype - Use - FunctionDecl - Identifier - ArgumentDecl - If - PrimaryExpr - Literal - NativeOperator -); - -pub fn collect_spans(root: &Root) -> HashMap { - let mut span_collector = SpanCollector::new(); - - span_collector.visit_root(root); - - span_collector.take_list() -} diff --git a/src/lib/ast/tree.rs b/src/lib/ast/tree.rs index 34fba438..d3da3e84 100644 --- a/src/lib/ast/tree.rs +++ b/src/lib/ast/tree.rs @@ -1,13 +1,15 @@ use std::collections::HashMap; use crate::{ - ast::{identity::Identity, NodeId}, + ast::NodeId, helpers::*, - parser::{Span, Token}, + parser::span2::Span, resolver::ResolutionMap, - ty::{FuncType, Type}, + ty::{FuncType, StructType, Type}, }; +use super::{ast_print::AstPrintContext, visit::Visitor}; + #[derive(Debug, Clone)] pub struct Root { pub r#mod: Mod, @@ -17,23 +19,53 @@ pub struct Root { pub spans: HashMap, } +/* impl FromStr for Root { + type Err = String; + + fn from_str(s: &str) -> Result { + match parse_root(create_parser(s)).finish() { + Ok((_, root)) => Ok(root), + Err(e) => Err(format!("{:?}", e)), + } + } +} + */ +impl Root { + pub fn new(r#mod: Mod) -> Self { + Self { + r#mod, + resolutions: ResolutionMap::default(), + operators_list: HashMap::new(), + unused: vec![], + spans: HashMap::new(), + } + } + + pub fn print(&self) { + AstPrintContext::new().visit_root(self); + } +} + #[derive(Debug, Clone)] pub struct Mod { - pub tokens: Vec, pub top_levels: Vec, - pub identity: Identity, + // pub node_id: NodeId, // TODO: setup a ModId } -impl Mod {} - -#[derive(Debug, Clone)] -pub struct TopLevel { - pub kind: TopLevelKind, - pub identity: Identity, +impl Mod { + pub fn new(top_levels: Vec) -> Self { + Self { top_levels } + } } +// #[derive(Debug, Clone)] +// pub struct TopLevel { +// pub kind: TopLevelKind, +// // pub node_id: NodeId, +// } + #[derive(Debug, Clone)] -pub enum TopLevelKind { +pub enum TopLevel { Prototype(Prototype), Function(FunctionDecl), Trait(Trait), @@ -41,23 +73,67 @@ pub enum TopLevelKind { Struct(StructDecl), Mod(Identifier, Mod), Use(Use), - Infix(Identifier, u8), + Infix(Operator, u8), +} + +impl TopLevel { + pub fn new_function(f: FunctionDecl) -> Self { + Self::Function(f) + } + + pub fn new_infix(op: Operator, pred: u8) -> Self { + Self::Infix(op, pred) + } + + pub fn new_prototype(proto: Prototype) -> Self { + Self::Prototype(proto) + } + + pub fn new_use(u: Use) -> Self { + Self::Use(u) + } + + pub fn new_struct(s: StructDecl) -> Self { + Self::Struct(s) + } + + pub fn new_trait(t: Trait) -> Self { + Self::Trait(t) + } + + pub fn new_impl(t: Impl) -> Self { + Self::Impl(t) + } + + pub fn new_mod(ident: Identifier, mod_: Mod) -> Self { + Self::Mod(ident, mod_) + } } #[derive(Debug, Clone)] pub struct StructDecl { - pub identity: Identity, - pub name: Type, + pub name: Identifier, pub defs: Vec, } +impl StructDecl { + pub fn new(name: Identifier, defs: Vec) -> Self { + Self { name, defs } + } +} + #[derive(Debug, Clone)] pub struct StructCtor { - pub identity: Identity, - pub name: Type, + pub name: Identifier, pub defs: HashMap, } +impl StructCtor { + pub fn new(name: Identifier, defs: HashMap) -> Self { + Self { name, defs } + } +} + #[derive(Debug, Clone)] pub struct Trait { pub name: Type, @@ -65,6 +141,12 @@ pub struct Trait { pub defs: Vec, } +impl Trait { + pub fn new(name: Type, types: Vec, defs: Vec) -> Self { + Self { name, types, defs } + } +} + #[derive(Debug, Clone)] pub struct Impl { pub name: Type, @@ -72,11 +154,17 @@ pub struct Impl { pub defs: Vec, } +impl Impl { + pub fn new(name: Type, types: Vec, defs: Vec) -> Self { + Self { name, types, defs } + } +} + #[derive(Debug, Clone)] pub struct Prototype { pub name: Identifier, pub signature: FuncType, - pub identity: Identity, + pub node_id: NodeId, } impl Prototype { @@ -88,16 +176,22 @@ impl Prototype { #[derive(Debug, Clone)] pub struct Use { pub path: IdentifierPath, - pub identity: Identity, + pub node_id: NodeId, +} + +impl Use { + pub fn new(path: IdentifierPath, node_id: NodeId) -> Self { + Self { path, node_id } + } } #[derive(Debug, Clone)] pub struct FunctionDecl { pub name: Identifier, // pub mangled_name: Option, - pub arguments: Vec, + pub arguments: Vec, pub body: Body, - pub identity: Identity, + pub node_id: NodeId, pub signature: FuncType, } @@ -115,11 +209,15 @@ pub struct IdentifierPath { } impl IdentifierPath { + pub fn new(path: Vec) -> Self { + Self { path } + } + pub fn new_root() -> Self { Self { path: vec![Identifier { name: "root".to_string(), - identity: Identity::new_placeholder(), + node_id: 42, // FIXME: should have a valid node_id ? }], } } @@ -194,9 +292,21 @@ impl IdentifierPath { #[derive(Debug, Clone, Eq)] pub struct Identifier { pub name: String, - pub identity: Identity, + pub node_id: NodeId, } +impl Identifier { + pub fn new(name: String, node_id: NodeId) -> Self { + Self { name, node_id } + } +} + +// impl Identifier { +// pub fn new(name: ) { + +// } +// } + impl PartialEq for Identifier { fn eq(&self, other: &Self) -> bool { self.name == other.name @@ -211,6 +321,7 @@ impl std::hash::Hash for Identifier { impl std::ops::Deref for Identifier { type Target = String; + fn deref(&self) -> &Self::Target { &self.name } @@ -218,32 +329,56 @@ impl std::ops::Deref for Identifier { generate_has_name!(Identifier); -pub type ArgumentsDecl = Vec; +pub type ArgumentsDecl = Vec; -#[derive(Debug, Clone)] -pub struct ArgumentDecl { - pub name: String, - pub identity: Identity, -} +// #[derive(Debug, Clone)] +// pub struct ArgumentDecl { +// pub name: String, +// pub node_id: NodeId, +// } #[derive(Debug, Clone)] pub struct Body { pub stmts: Vec, } -#[derive(Debug, Clone)] -pub struct Statement { - pub kind: Box, +impl Body { + pub fn new(stmts: Vec) -> Self { + Self { stmts } + } } +// #[derive(Debug, Clone)] +// pub struct Statement { +// pub kind: Box, +// } + #[derive(Debug, Clone)] -pub enum StatementKind { +pub enum Statement { Expression(Box), Assign(Box), If(Box), For(For), } +impl Statement { + pub fn new_expression(expr: Expression) -> Self { + Self::Expression(Box::new(expr)) + } + + pub fn new_if(if_: If) -> Self { + Self::If(Box::new(if_)) + } + + pub fn new_for(for_: For) -> Self { + Self::For(for_) + } + + pub fn new_assign(assign: Assign) -> Self { + Self::Assign(Box::new(assign)) + } +} + #[derive(Debug, Clone)] pub enum For { In(ForIn), @@ -256,6 +391,12 @@ pub struct While { pub body: Body, } +impl While { + pub fn new(predicat: Expression, body: Body) -> Self { + Self { predicat, body } + } +} + #[derive(Debug, Clone)] pub struct ForIn { pub value: Identifier, @@ -263,9 +404,15 @@ pub struct ForIn { pub body: Body, } +impl ForIn { + pub fn new(value: Identifier, expr: Expression, body: Body) -> Self { + Self { value, expr, body } + } +} + #[derive(Debug, Clone)] pub enum AssignLeftSide { - Identifier(Identifier), + Identifier(Expression), Indice(Expression), Dot(Expression), } @@ -273,13 +420,7 @@ pub enum AssignLeftSide { impl AssignLeftSide { pub fn as_expression(&self) -> Expression { match self { - AssignLeftSide::Identifier(i) => Expression { - kind: ExpressionKind::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { - op: Operand::from_identifier(i), - identity: i.identity.clone(), - secondaries: None, - })), - }, + AssignLeftSide::Identifier(i) => i.clone(), AssignLeftSide::Indice(i) => i.clone(), AssignLeftSide::Dot(d) => d.clone(), } @@ -290,7 +431,7 @@ impl AssignLeftSide { // use AssignLeftSide::*; // match self { -// Identifier(id) => id.identity.node_id, +// Identifier(id) => id.node_id.node_id, // Indice(expr) => expr., // } // } @@ -303,84 +444,140 @@ pub struct Assign { pub is_let: bool, } +impl Assign { + pub fn new(name: AssignLeftSide, value: Expression, is_let: bool) -> Self { + Self { + name, + value, + is_let, + } + } +} + #[derive(Debug, Clone)] pub struct If { - pub identity: Identity, + pub node_id: NodeId, pub predicat: Expression, pub body: Body, pub else_: Option>, } +impl If { + pub fn new( + node_id: NodeId, + predicat: Expression, + body: Body, + else_: Option>, + ) -> Self { + Self { + node_id, + predicat, + body, + else_, + } + } +} + #[derive(Debug, Clone)] pub enum Else { If(If), Body(Body), } -#[derive(Debug, Clone)] -pub struct Expression { - pub kind: ExpressionKind, -} +// #[derive(Debug, Clone)] +// pub struct Expression { +// pub kind: ExpressionKind, +// } impl Expression { #[allow(dead_code)] pub fn is_literal(&self) -> bool { - match &self.kind { - ExpressionKind::UnaryExpr(unary) => unary.is_literal(), + match &self { + Expression::UnaryExpr(unary) => unary.is_literal(), _ => false, } } #[allow(dead_code)] pub fn is_identifier(&self) -> bool { - match &self.kind { - ExpressionKind::UnaryExpr(unary) => unary.is_identifier(), + match &self { + Expression::UnaryExpr(unary) => unary.is_identifier(), _ => false, } } #[allow(dead_code)] pub fn is_binop(&self) -> bool { - matches!(&self.kind, ExpressionKind::BinopExpr(_, _, _)) + matches!(&self, Expression::BinopExpr(_, _, _)) } #[allow(dead_code)] pub fn is_indice(&self) -> bool { - match &self.kind { - ExpressionKind::UnaryExpr(unary) => unary.is_indice(), + match &self { + Expression::UnaryExpr(unary) => unary.is_indice(), _ => false, } } #[allow(dead_code)] - pub fn from_unary(unary: &UnaryExpr) -> Expression { - Expression { - kind: ExpressionKind::UnaryExpr(unary.clone()), + pub fn is_dot(&self) -> bool { + match &self { + Expression::UnaryExpr(unary) => unary.is_dot(), + _ => false, } } #[allow(dead_code)] - pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> Expression { - Expression { - kind: ExpressionKind::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { - identity: Identity::new_placeholder(), - op, - secondaries: Some(vec![SecondaryExpr::Arguments(vec![ - Argument { arg: arg1 }, - Argument { arg: arg2 }, - ])]), - })), + pub fn new_unary(unary: UnaryExpr) -> Expression { + Expression::UnaryExpr(unary) + } + + #[allow(dead_code)] + pub fn new_binop(unary: UnaryExpr, operator: Operator, expr: Expression) -> Expression { + Expression::BinopExpr(unary, operator, Box::new(expr)) + } + + pub fn new_struct_ctor(ctor: StructCtor) -> Expression { + Expression::StructCtor(ctor) + } + + pub fn new_native_operator( + operator: NativeOperator, + id1: Identifier, + id2: Identifier, + ) -> Expression { + Expression::NativeOperation(operator, id1, id2) + } + + pub fn as_identifier(&self) -> Option<&Identifier> { + match self { + Expression::UnaryExpr(unary) => unary.as_identifier(), + _ => None, } } + + // #[allow(dead_code)] + // pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> Expression { + // Expression { + // kind: Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { + // node_id: node_id::new_placeholder(), + // op, + // secondaries: Some(vec![SecondaryExpr::Arguments(vec![ + // Argument { arg: arg1 }, + // Argument { arg: arg2 }, + // ])]), + // })), + // } + // } } #[derive(Debug, Clone)] -pub enum ExpressionKind { +pub enum Expression { BinopExpr(UnaryExpr, Operator, Box), UnaryExpr(UnaryExpr), NativeOperation(NativeOperator, Identifier, Identifier), StructCtor(StructCtor), - Return(Box), + Return(Box), // NOTE: Shouldn't that be a statement? } #[derive(Debug, Clone)] @@ -392,14 +589,14 @@ pub enum UnaryExpr { impl UnaryExpr { pub fn is_literal(&self) -> bool { match self { - UnaryExpr::PrimaryExpr(p) => matches!(&p.op.kind, OperandKind::Literal(_)), + UnaryExpr::PrimaryExpr(p) => matches!(&p.op, Operand::Literal(_)), _ => false, } } pub fn is_identifier(&self) -> bool { match self { - UnaryExpr::PrimaryExpr(p) => matches!(&p.op.kind, OperandKind::Identifier(_)), + UnaryExpr::PrimaryExpr(p) => matches!(&p.op, Operand::Identifier(_)), _ => false, } } @@ -411,9 +608,16 @@ impl UnaryExpr { } } + pub fn is_dot(&self) -> bool { + match self { + UnaryExpr::UnaryExpr(_, unary) => unary.is_dot(), + UnaryExpr::PrimaryExpr(prim) => prim.is_dot(), + } + } + pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> UnaryExpr { UnaryExpr::PrimaryExpr(PrimaryExpr { - identity: Identity::new_placeholder(), + node_id: u64::MAX, op, secondaries: Some(vec![SecondaryExpr::Arguments(vec![ Argument { arg: arg1 }, @@ -421,14 +625,25 @@ impl UnaryExpr { ])]), }) } + + pub fn new_primary(primary: PrimaryExpr) -> UnaryExpr { + UnaryExpr::PrimaryExpr(primary) + } + + pub fn as_identifier(&self) -> Option<&Identifier> { + match self { + UnaryExpr::PrimaryExpr(primary) => primary.as_identifier(), + _ => None, + } + } } -#[derive(Debug, Clone)] +#[derive(Debug, Clone, PartialEq)] pub struct Operator(pub Identifier); #[derive(Debug, Clone)] pub struct PrimaryExpr { - pub identity: Identity, + pub node_id: NodeId, pub op: Operand, pub secondaries: Option>, } @@ -446,44 +661,93 @@ impl PrimaryExpr { false } } + + pub fn is_dot(&self) -> bool { + if let Some(secondaries) = &self.secondaries { + secondaries.iter().any(|secondary| secondary.is_dot()) + } else { + false + } + } + + pub fn new_empty(op: Operand) -> PrimaryExpr { + PrimaryExpr { + op, + node_id: u64::MAX, + secondaries: None, + } + } + + pub fn new(node_id: NodeId, op: Operand, secondaries: Vec) -> PrimaryExpr { + PrimaryExpr { + op, + node_id, + secondaries: if secondaries.len() == 0 { + None + } else { + Some(secondaries) + }, + } + } + + pub fn as_identifier(&self) -> Option<&Identifier> { + match &self.op { + Operand::Identifier(id) => Some(id.path.last().unwrap()), + _ => None, + } + } } +// #[derive(Debug, Clone)] +// pub struct Operand { +// pub kind: Operand, +// } + #[derive(Debug, Clone)] -pub struct Operand { - pub kind: OperandKind, +pub enum Operand { + Literal(Literal), + Identifier(IdentifierPath), + Expression(Box), // parenthesis } impl Operand { - pub fn from_identifier(id: &Identifier) -> Self { - Self { - kind: OperandKind::Identifier(IdentifierPath { - path: vec![id.clone()], - }), - } + pub fn new_identifier_path(id: IdentifierPath) -> Self { + Self::Identifier(id) + } + + pub fn new_identifier(id: Identifier) -> Self { + Self::Identifier(IdentifierPath { + path: vec![id.clone()], + }) + } + + pub fn new_expression(expr: Expression) -> Self { + Self::Expression(Box::new(expr)) } #[allow(dead_code)] pub fn is_literal(&self) -> bool { - matches!(&self.kind, OperandKind::Literal(_)) + matches!(&self, Operand::Literal(_)) } #[allow(dead_code)] pub fn is_identifier(&self) -> bool { - matches!(&self.kind, OperandKind::Identifier(_)) + matches!(&self, Operand::Identifier(_)) } -} -#[derive(Debug, Clone)] -pub enum OperandKind { - Literal(Literal), - Identifier(IdentifierPath), - Expression(Box), // parenthesis + pub fn new_literal(lit: Literal) -> Operand { + Operand::Literal(lit) + } + + pub fn from_identifier(id: Identifier) -> Operand { + Operand::new_identifier(id) + } } -impl OperandKind { +impl Operand { #[allow(dead_code)] pub fn to_identifier_path(&self) -> IdentifierPath { - if let OperandKind::Identifier(id) = self { + if let Operand::Identifier(id) = self { id.clone() } else { panic!("Not an identifier path") @@ -497,25 +761,78 @@ pub enum SecondaryExpr { Indice(Box), // Boxing here to keep the enum size low Dot(Identifier), } + impl SecondaryExpr { pub fn is_indice(&self) -> bool { matches!(self, SecondaryExpr::Indice(_)) } + + pub fn is_dot(&self) -> bool { + matches!(self, SecondaryExpr::Dot(_)) + } + + pub fn is_arguments(&self) -> bool { + matches!(self, SecondaryExpr::Arguments(_)) + } } #[derive(Debug, Clone)] pub struct Literal { pub kind: LiteralKind, - pub identity: Identity, + pub node_id: NodeId, +} + +impl Literal { + pub fn new_bool(b: bool, node_id: NodeId) -> Self { + Self { + kind: LiteralKind::Bool(b), + node_id, + } + } + + pub fn new_number(num: i64, node_id: NodeId) -> Self { + Self { + kind: LiteralKind::Number(num), + node_id, + } + } + + pub fn new_float(num: f64, node_id: NodeId) -> Self { + Self { + kind: LiteralKind::Float(num), + node_id, + } + } + + pub fn new_array(arr: Array, node_id: NodeId) -> Self { + Self { + kind: LiteralKind::Array(arr), + node_id, + } + } + + pub fn new_string(str: String, node_id: NodeId) -> Self { + Self { + kind: LiteralKind::String(str), + node_id, + } + } + + pub fn as_i64(&self) -> i64 { + match self.kind { + LiteralKind::Number(n) => n, + _ => panic!("Not a Number"), + } + } } #[derive(Debug, Clone)] pub enum LiteralKind { + Bool(bool), Number(i64), Float(f64), - String(String), - Bool(bool), Array(Array), + String(String), } #[derive(Debug, Clone)] @@ -523,6 +840,12 @@ pub struct Array { pub values: Vec, } +impl Array { + pub fn new(values: Vec) -> Self { + Self { values } + } +} + pub type Arguments = Vec; #[derive(Debug, Clone)] @@ -530,13 +853,25 @@ pub struct Argument { pub arg: UnaryExpr, } +impl Argument { + pub fn new(arg: UnaryExpr) -> Self { + Self { arg } + } +} + #[derive(Debug, Clone)] pub struct NativeOperator { pub kind: NativeOperatorKind, - pub identity: Identity, + pub node_id: NodeId, } -#[derive(Debug, Clone)] +impl NativeOperator { + pub fn new(node_id: NodeId, kind: NativeOperatorKind) -> Self { + Self { kind, node_id } + } +} + +#[derive(Debug, Clone, PartialEq)] pub enum NativeOperatorKind { IAdd, ISub, @@ -559,3 +894,31 @@ pub enum NativeOperatorKind { BEq, Len, } + +impl NativeOperatorKind { + pub fn from_str(s: &str) -> Self { + match s { + "IAdd" => Self::IAdd, + "ISub" => Self::ISub, + "IMul" => Self::IMul, + "IDiv" => Self::IDiv, + "FAdd" => Self::FAdd, + "FSub" => Self::FSub, + "FMul" => Self::FMul, + "FDiv" => Self::FDiv, + "IEq" => Self::IEq, + "Igt" => Self::Igt, + "Ige" => Self::Ige, + "Ilt" => Self::Ilt, + "Ile" => Self::Ile, + "FEq" => Self::FEq, + "Fgt" => Self::Fgt, + "Fge" => Self::Fge, + "Flt" => Self::Flt, + "Fle" => Self::Fle, + "BEq" => Self::BEq, + "Len" => Self::Len, + _ => panic!("Unknown native operator"), + } + } +} diff --git a/src/lib/ast/tree2.rs b/src/lib/ast/tree2.rs deleted file mode 100644 index e906c758..00000000 --- a/src/lib/ast/tree2.rs +++ /dev/null @@ -1,924 +0,0 @@ -use std::collections::HashMap; - -use crate::{ - ast::NodeId, - helpers::*, - parser::span2::Span, - resolver2::ResolutionMap, - ty::{FuncType, StructType, Type}, -}; - -use super::{ast_print::AstPrintContext, visit2::Visitor}; - -#[derive(Debug, Clone)] -pub struct Root { - pub r#mod: Mod, - pub resolutions: ResolutionMap, - pub operators_list: HashMap, - pub unused: Vec, - pub spans: HashMap, -} - -/* impl FromStr for Root { - type Err = String; - - fn from_str(s: &str) -> Result { - match parse_root(create_parser(s)).finish() { - Ok((_, root)) => Ok(root), - Err(e) => Err(format!("{:?}", e)), - } - } -} - */ -impl Root { - pub fn new(r#mod: Mod) -> Self { - Self { - r#mod, - resolutions: ResolutionMap::default(), - operators_list: HashMap::new(), - unused: vec![], - spans: HashMap::new(), - } - } - - pub fn print(&self) { - AstPrintContext::new().visit_root(self); - } -} - -#[derive(Debug, Clone)] -pub struct Mod { - pub top_levels: Vec, - // pub node_id: NodeId, // TODO: setup a ModId -} - -impl Mod { - pub fn new(top_levels: Vec) -> Self { - Self { top_levels } - } -} - -// #[derive(Debug, Clone)] -// pub struct TopLevel { -// pub kind: TopLevelKind, -// // pub node_id: NodeId, -// } - -#[derive(Debug, Clone)] -pub enum TopLevel { - Prototype(Prototype), - Function(FunctionDecl), - Trait(Trait), - Impl(Impl), - Struct(StructDecl), - Mod(Identifier, Mod), - Use(Use), - Infix(Operator, u8), -} - -impl TopLevel { - pub fn new_function(f: FunctionDecl) -> Self { - Self::Function(f) - } - - pub fn new_infix(op: Operator, pred: u8) -> Self { - Self::Infix(op, pred) - } - - pub fn new_prototype(proto: Prototype) -> Self { - Self::Prototype(proto) - } - - pub fn new_use(u: Use) -> Self { - Self::Use(u) - } - - pub fn new_struct(s: StructDecl) -> Self { - Self::Struct(s) - } - - pub fn new_trait(t: Trait) -> Self { - Self::Trait(t) - } - - pub fn new_impl(t: Impl) -> Self { - Self::Impl(t) - } - - pub fn new_mod(ident: Identifier, mod_: Mod) -> Self { - Self::Mod(ident, mod_) - } -} - -#[derive(Debug, Clone)] -pub struct StructDecl { - pub name: Identifier, - pub defs: Vec, -} - -impl StructDecl { - pub fn new(name: Identifier, defs: Vec) -> Self { - Self { name, defs } - } -} - -#[derive(Debug, Clone)] -pub struct StructCtor { - pub name: Identifier, - pub defs: HashMap, -} - -impl StructCtor { - pub fn new(name: Identifier, defs: HashMap) -> Self { - Self { name, defs } - } -} - -#[derive(Debug, Clone)] -pub struct Trait { - pub name: Type, - pub types: Vec, - pub defs: Vec, -} - -impl Trait { - pub fn new(name: Type, types: Vec, defs: Vec) -> Self { - Self { name, types, defs } - } -} - -#[derive(Debug, Clone)] -pub struct Impl { - pub name: Type, - pub types: Vec, - pub defs: Vec, -} - -impl Impl { - pub fn new(name: Type, types: Vec, defs: Vec) -> Self { - Self { name, types, defs } - } -} - -#[derive(Debug, Clone)] -pub struct Prototype { - pub name: Identifier, - pub signature: FuncType, - pub node_id: NodeId, -} - -impl Prototype { - pub fn mangle(&mut self, prefix: String) { - self.name.name = prefix + "_" + &self.name.name; - } -} - -#[derive(Debug, Clone)] -pub struct Use { - pub path: IdentifierPath, - pub node_id: NodeId, -} - -impl Use { - pub fn new(path: IdentifierPath, node_id: NodeId) -> Self { - Self { path, node_id } - } -} - -#[derive(Debug, Clone)] -pub struct FunctionDecl { - pub name: Identifier, - // pub mangled_name: Option, - pub arguments: Vec, - pub body: Body, - pub node_id: NodeId, - pub signature: FuncType, -} - -impl FunctionDecl { - pub fn mangle(&mut self, prefixes: &[String]) { - self.name.name = prefixes.join("_") + "_" + &self.name.name; - } -} - -generate_has_name!(FunctionDecl); - -#[derive(Debug, Clone, Hash, PartialEq, Eq)] -pub struct IdentifierPath { - pub path: Vec, -} - -impl IdentifierPath { - pub fn new(path: Vec) -> Self { - Self { path } - } - - pub fn new_root() -> Self { - Self { - path: vec![Identifier { - name: "root".to_string(), - node_id: 42, // FIXME: should have a valid node_id ? - }], - } - } - - pub fn parent(&self) -> Self { - let mut parent = self.clone(); - - if parent.path.len() > 1 { - parent.path.pop(); - } - - parent - } - - pub fn child(&self, name: Identifier) -> Self { - let mut child = self.clone(); - - child.path.push(name); - - child - } - - pub fn last_segment_ref(&self) -> &Identifier { - self.path.iter().last().unwrap() - } - - pub fn prepend_mod(&self, path: IdentifierPath) -> Self { - let mut path = path; - - path.path.extend::<_>(self.path.clone()); - - path - } - - pub fn resolve_supers(&mut self) { - let to_remove = self - .path - .iter() - .enumerate() - .filter_map( - |(i, name)| { - if name.name == *"super" { - Some(i) - } else { - None - } - }, - ) - .collect::>(); - - let mut to_remove_total = vec![]; - - for id in to_remove { - to_remove_total.extend(vec![id - 1, id]); - } - - self.path = self - .path - .iter() - .enumerate() - .filter_map(|(i, name)| { - if to_remove_total.contains(&i) { - None - } else { - Some(name.clone()) - } - }) - .collect::>(); - } -} - -#[derive(Debug, Clone, Eq)] -pub struct Identifier { - pub name: String, - pub node_id: NodeId, -} - -impl Identifier { - pub fn new(name: String, node_id: NodeId) -> Self { - Self { name, node_id } - } -} - -// impl Identifier { -// pub fn new(name: ) { - -// } -// } - -impl PartialEq for Identifier { - fn eq(&self, other: &Self) -> bool { - self.name == other.name - } -} - -impl std::hash::Hash for Identifier { - fn hash(&self, state: &mut H) { - self.name.hash(state); - } -} - -impl std::ops::Deref for Identifier { - type Target = String; - - fn deref(&self) -> &Self::Target { - &self.name - } -} - -generate_has_name!(Identifier); - -pub type ArgumentsDecl = Vec; - -// #[derive(Debug, Clone)] -// pub struct ArgumentDecl { -// pub name: String, -// pub node_id: NodeId, -// } - -#[derive(Debug, Clone)] -pub struct Body { - pub stmts: Vec, -} - -impl Body { - pub fn new(stmts: Vec) -> Self { - Self { stmts } - } -} - -// #[derive(Debug, Clone)] -// pub struct Statement { -// pub kind: Box, -// } - -#[derive(Debug, Clone)] -pub enum Statement { - Expression(Box), - Assign(Box), - If(Box), - For(For), -} - -impl Statement { - pub fn new_expression(expr: Expression) -> Self { - Self::Expression(Box::new(expr)) - } - - pub fn new_if(if_: If) -> Self { - Self::If(Box::new(if_)) - } - - pub fn new_for(for_: For) -> Self { - Self::For(for_) - } - - pub fn new_assign(assign: Assign) -> Self { - Self::Assign(Box::new(assign)) - } -} - -#[derive(Debug, Clone)] -pub enum For { - In(ForIn), - While(While), -} - -#[derive(Debug, Clone)] -pub struct While { - pub predicat: Expression, - pub body: Body, -} - -impl While { - pub fn new(predicat: Expression, body: Body) -> Self { - Self { predicat, body } - } -} - -#[derive(Debug, Clone)] -pub struct ForIn { - pub value: Identifier, - pub expr: Expression, - pub body: Body, -} - -impl ForIn { - pub fn new(value: Identifier, expr: Expression, body: Body) -> Self { - Self { value, expr, body } - } -} - -#[derive(Debug, Clone)] -pub enum AssignLeftSide { - Identifier(Expression), - Indice(Expression), - Dot(Expression), -} - -impl AssignLeftSide { - pub fn as_expression(&self) -> Expression { - match self { - AssignLeftSide::Identifier(i) => i.clone(), - AssignLeftSide::Indice(i) => i.clone(), - AssignLeftSide::Dot(d) => d.clone(), - } - } -} -// impl AssignLeftSide { -// pub fn get_node_id(&self) -> NodeId { -// use AssignLeftSide::*; - -// match self { -// Identifier(id) => id.node_id.node_id, -// Indice(expr) => expr., -// } -// } -// } - -#[derive(Debug, Clone)] -pub struct Assign { - pub name: AssignLeftSide, - pub value: Expression, - pub is_let: bool, -} - -impl Assign { - pub fn new(name: AssignLeftSide, value: Expression, is_let: bool) -> Self { - Self { - name, - value, - is_let, - } - } -} - -#[derive(Debug, Clone)] -pub struct If { - pub node_id: NodeId, - pub predicat: Expression, - pub body: Body, - pub else_: Option>, -} - -impl If { - pub fn new( - node_id: NodeId, - predicat: Expression, - body: Body, - else_: Option>, - ) -> Self { - Self { - node_id, - predicat, - body, - else_, - } - } -} - -#[derive(Debug, Clone)] -pub enum Else { - If(If), - Body(Body), -} - -// #[derive(Debug, Clone)] -// pub struct Expression { -// pub kind: ExpressionKind, -// } - -impl Expression { - #[allow(dead_code)] - pub fn is_literal(&self) -> bool { - match &self { - Expression::UnaryExpr(unary) => unary.is_literal(), - _ => false, - } - } - - #[allow(dead_code)] - pub fn is_identifier(&self) -> bool { - match &self { - Expression::UnaryExpr(unary) => unary.is_identifier(), - _ => false, - } - } - - #[allow(dead_code)] - pub fn is_binop(&self) -> bool { - matches!(&self, Expression::BinopExpr(_, _, _)) - } - - #[allow(dead_code)] - pub fn is_indice(&self) -> bool { - match &self { - Expression::UnaryExpr(unary) => unary.is_indice(), - _ => false, - } - } - - #[allow(dead_code)] - pub fn is_dot(&self) -> bool { - match &self { - Expression::UnaryExpr(unary) => unary.is_dot(), - _ => false, - } - } - - #[allow(dead_code)] - pub fn new_unary(unary: UnaryExpr) -> Expression { - Expression::UnaryExpr(unary) - } - - #[allow(dead_code)] - pub fn new_binop(unary: UnaryExpr, operator: Operator, expr: Expression) -> Expression { - Expression::BinopExpr(unary, operator, Box::new(expr)) - } - - pub fn new_struct_ctor(ctor: StructCtor) -> Expression { - Expression::StructCtor(ctor) - } - - pub fn new_native_operator( - operator: NativeOperator, - id1: Identifier, - id2: Identifier, - ) -> Expression { - Expression::NativeOperation(operator, id1, id2) - } - - pub fn as_identifier(&self) -> Option<&Identifier> { - match self { - Expression::UnaryExpr(unary) => unary.as_identifier(), - _ => None, - } - } - - // #[allow(dead_code)] - // pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> Expression { - // Expression { - // kind: Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { - // node_id: node_id::new_placeholder(), - // op, - // secondaries: Some(vec![SecondaryExpr::Arguments(vec![ - // Argument { arg: arg1 }, - // Argument { arg: arg2 }, - // ])]), - // })), - // } - // } -} - -#[derive(Debug, Clone)] -pub enum Expression { - BinopExpr(UnaryExpr, Operator, Box), - UnaryExpr(UnaryExpr), - NativeOperation(NativeOperator, Identifier, Identifier), - StructCtor(StructCtor), - Return(Box), // NOTE: Shouldn't that be a statement? -} - -#[derive(Debug, Clone)] -pub enum UnaryExpr { - PrimaryExpr(PrimaryExpr), - UnaryExpr(Operator, Box), -} - -impl UnaryExpr { - pub fn is_literal(&self) -> bool { - match self { - UnaryExpr::PrimaryExpr(p) => matches!(&p.op, Operand::Literal(_)), - _ => false, - } - } - - pub fn is_identifier(&self) -> bool { - match self { - UnaryExpr::PrimaryExpr(p) => matches!(&p.op, Operand::Identifier(_)), - _ => false, - } - } - - pub fn is_indice(&self) -> bool { - match self { - UnaryExpr::UnaryExpr(_, unary) => unary.is_indice(), - UnaryExpr::PrimaryExpr(prim) => prim.is_indice(), - } - } - - pub fn is_dot(&self) -> bool { - match self { - UnaryExpr::UnaryExpr(_, unary) => unary.is_dot(), - UnaryExpr::PrimaryExpr(prim) => prim.is_dot(), - } - } - - pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> UnaryExpr { - UnaryExpr::PrimaryExpr(PrimaryExpr { - node_id: u64::MAX, - op, - secondaries: Some(vec![SecondaryExpr::Arguments(vec![ - Argument { arg: arg1 }, - Argument { arg: arg2 }, - ])]), - }) - } - - pub fn new_primary(primary: PrimaryExpr) -> UnaryExpr { - UnaryExpr::PrimaryExpr(primary) - } - - pub fn as_identifier(&self) -> Option<&Identifier> { - match self { - UnaryExpr::PrimaryExpr(primary) => primary.as_identifier(), - _ => None, - } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub struct Operator(pub Identifier); - -#[derive(Debug, Clone)] -pub struct PrimaryExpr { - pub node_id: NodeId, - pub op: Operand, - pub secondaries: Option>, -} - -impl PrimaryExpr { - #[allow(dead_code)] - pub fn has_secondaries(&self) -> bool { - self.secondaries.is_some() - } - - pub fn is_indice(&self) -> bool { - if let Some(secondaries) = &self.secondaries { - secondaries.iter().any(|secondary| secondary.is_indice()) - } else { - false - } - } - - pub fn is_dot(&self) -> bool { - if let Some(secondaries) = &self.secondaries { - secondaries.iter().any(|secondary| secondary.is_dot()) - } else { - false - } - } - - pub fn new_empty(op: Operand) -> PrimaryExpr { - PrimaryExpr { - op, - node_id: u64::MAX, - secondaries: None, - } - } - - pub fn new(node_id: NodeId, op: Operand, secondaries: Vec) -> PrimaryExpr { - PrimaryExpr { - op, - node_id, - secondaries: if secondaries.len() == 0 { - None - } else { - Some(secondaries) - }, - } - } - - pub fn as_identifier(&self) -> Option<&Identifier> { - match &self.op { - Operand::Identifier(id) => Some(id.path.last().unwrap()), - _ => None, - } - } -} - -// #[derive(Debug, Clone)] -// pub struct Operand { -// pub kind: Operand, -// } - -#[derive(Debug, Clone)] -pub enum Operand { - Literal(Literal), - Identifier(IdentifierPath), - Expression(Box), // parenthesis -} - -impl Operand { - pub fn new_identifier_path(id: IdentifierPath) -> Self { - Self::Identifier(id) - } - - pub fn new_identifier(id: Identifier) -> Self { - Self::Identifier(IdentifierPath { - path: vec![id.clone()], - }) - } - - pub fn new_expression(expr: Expression) -> Self { - Self::Expression(Box::new(expr)) - } - - #[allow(dead_code)] - pub fn is_literal(&self) -> bool { - matches!(&self, Operand::Literal(_)) - } - - #[allow(dead_code)] - pub fn is_identifier(&self) -> bool { - matches!(&self, Operand::Identifier(_)) - } - - pub fn new_literal(lit: Literal) -> Operand { - Operand::Literal(lit) - } - - pub fn from_identifier(id: Identifier) -> Operand { - Operand::new_identifier(id) - } -} - -impl Operand { - #[allow(dead_code)] - pub fn to_identifier_path(&self) -> IdentifierPath { - if let Operand::Identifier(id) = self { - id.clone() - } else { - panic!("Not an identifier path") - } - } -} - -#[derive(Debug, Clone)] -pub enum SecondaryExpr { - Arguments(Vec), - Indice(Box), // Boxing here to keep the enum size low - Dot(Identifier), -} - -impl SecondaryExpr { - pub fn is_indice(&self) -> bool { - matches!(self, SecondaryExpr::Indice(_)) - } - - pub fn is_dot(&self) -> bool { - matches!(self, SecondaryExpr::Dot(_)) - } - - pub fn is_arguments(&self) -> bool { - matches!(self, SecondaryExpr::Arguments(_)) - } -} - -#[derive(Debug, Clone)] -pub struct Literal { - pub kind: LiteralKind, - pub node_id: NodeId, -} - -impl Literal { - pub fn new_bool(b: bool, node_id: NodeId) -> Self { - Self { - kind: LiteralKind::Bool(b), - node_id, - } - } - - pub fn new_number(num: i64, node_id: NodeId) -> Self { - Self { - kind: LiteralKind::Number(num), - node_id, - } - } - - pub fn new_float(num: f64, node_id: NodeId) -> Self { - Self { - kind: LiteralKind::Float(num), - node_id, - } - } - - pub fn new_array(arr: Array, node_id: NodeId) -> Self { - Self { - kind: LiteralKind::Array(arr), - node_id, - } - } - - pub fn new_string(str: String, node_id: NodeId) -> Self { - Self { - kind: LiteralKind::String(str), - node_id, - } - } - - pub fn as_i64(&self) -> i64 { - match self.kind { - LiteralKind::Number(n) => n, - _ => panic!("Not a Number"), - } - } -} - -#[derive(Debug, Clone)] -pub enum LiteralKind { - Bool(bool), - Number(i64), - Float(f64), - Array(Array), - String(String), -} - -#[derive(Debug, Clone)] -pub struct Array { - pub values: Vec, -} - -impl Array { - pub fn new(values: Vec) -> Self { - Self { values } - } -} - -pub type Arguments = Vec; - -#[derive(Debug, Clone)] -pub struct Argument { - pub arg: UnaryExpr, -} - -impl Argument { - pub fn new(arg: UnaryExpr) -> Self { - Self { arg } - } -} - -#[derive(Debug, Clone)] -pub struct NativeOperator { - pub kind: NativeOperatorKind, - pub node_id: NodeId, -} - -impl NativeOperator { - pub fn new(node_id: NodeId, kind: NativeOperatorKind) -> Self { - Self { kind, node_id } - } -} - -#[derive(Debug, Clone, PartialEq)] -pub enum NativeOperatorKind { - IAdd, - ISub, - IMul, - IDiv, - FAdd, - FSub, - FMul, - FDiv, - IEq, - Igt, - Ige, - Ilt, - Ile, - FEq, - Fgt, - Fge, - Flt, - Fle, - BEq, - Len, -} - -impl NativeOperatorKind { - pub fn from_str(s: &str) -> Self { - match s { - "IAdd" => Self::IAdd, - "ISub" => Self::ISub, - "IMul" => Self::IMul, - "IDiv" => Self::IDiv, - "FAdd" => Self::FAdd, - "FSub" => Self::FSub, - "FMul" => Self::FMul, - "FDiv" => Self::FDiv, - "IEq" => Self::IEq, - "Igt" => Self::Igt, - "Ige" => Self::Ige, - "Ilt" => Self::Ilt, - "Ile" => Self::Ile, - "FEq" => Self::FEq, - "Fgt" => Self::Fgt, - "Fge" => Self::Fge, - "Flt" => Self::Flt, - "Fle" => Self::Fle, - "BEq" => Self::BEq, - "Len" => Self::Len, - _ => panic!("Unknown native operator"), - } - } -} diff --git a/src/lib/ast/visit.rs b/src/lib/ast/visit.rs index 26c86a88..94a172f8 100644 --- a/src/lib/ast/visit.rs +++ b/src/lib/ast/visit.rs @@ -1,6 +1,6 @@ use paste::paste; -use crate::ast::*; +use crate::ast::tree::*; use crate::ty::*; macro_rules! generate_visitor_trait { @@ -40,7 +40,7 @@ generate_visitor_trait!( StructDecl Identifier IdentifierPath - ArgumentDecl + // ArgumentDecl Body Statement For @@ -72,23 +72,23 @@ pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, _mod: &'a Mod) { } pub fn walk_top_level<'a, V: Visitor<'a>>(visitor: &mut V, top_level: &'a TopLevel) { - match &top_level.kind { - TopLevelKind::Prototype(p) => visitor.visit_prototype(p), - TopLevelKind::Use(u) => visitor.visit_use(u), - TopLevelKind::Trait(t) => visitor.visit_trait(t), - TopLevelKind::Impl(i) => visitor.visit_impl(i), - TopLevelKind::Struct(i) => visitor.visit_struct_decl(i), - TopLevelKind::Mod(name, m) => { + match &top_level { + TopLevel::Prototype(p) => visitor.visit_prototype(p), + TopLevel::Use(u) => visitor.visit_use(u), + TopLevel::Trait(t) => visitor.visit_trait(t), + TopLevel::Impl(i) => visitor.visit_impl(i), + TopLevel::Struct(i) => visitor.visit_struct_decl(i), + TopLevel::Mod(name, m) => { visitor.visit_identifier(name); visitor.visit_mod(m); } - TopLevelKind::Function(f) => visitor.visit_function_decl(f), - TopLevelKind::Infix(ident, _) => visitor.visit_identifier(ident), + TopLevel::Function(f) => visitor.visit_function_decl(f), + TopLevel::Infix(ident, _) => visitor.visit_operator(ident), }; } pub fn walk_struct_decl<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructDecl) { - visitor.visit_type(&s.name); + visitor.visit_identifier(&s.name); walk_list!(visitor, visit_prototype, &s.defs); } @@ -122,7 +122,7 @@ pub fn walk_use<'a, V: Visitor<'a>>(visitor: &mut V, r#use: &'a Use) { pub fn walk_function_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_decl: &'a FunctionDecl) { visitor.visit_identifier(&function_decl.name); - walk_list!(visitor, visit_argument_decl, &function_decl.arguments); + walk_list!(visitor, visit_identifier, &function_decl.arguments); visitor.visit_body(&function_decl.body); } @@ -138,20 +138,20 @@ pub fn walk_identifier<'a, V: Visitor<'a>>(visitor: &mut V, identifier: &'a Iden visitor.visit_name(&identifier.name); } -pub fn walk_argument_decl<'a, V: Visitor<'a>>(visitor: &mut V, argument: &'a ArgumentDecl) { +/* pub fn walk_argument_decl<'a, V: Visitor<'a>>(visitor: &mut V, argument: &'a ArgumentDecl) { visitor.visit_name(&argument.name); -} +} */ pub fn walk_body<'a, V: Visitor<'a>>(visitor: &mut V, body: &'a Body) { walk_list!(visitor, visit_statement, &body.stmts); } pub fn walk_statement<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Statement) { - match statement.kind.as_ref() { - StatementKind::Expression(expr) => visitor.visit_expression(expr), - StatementKind::Assign(assign) => visitor.visit_assign(assign), - StatementKind::If(expr) => visitor.visit_if(expr), - StatementKind::For(for_loop) => visitor.visit_for(for_loop), + match &statement { + Statement::Expression(expr) => visitor.visit_expression(expr), + Statement::Assign(assign) => visitor.visit_assign(assign), + Statement::If(expr) => visitor.visit_if(expr), + Statement::For(for_loop) => visitor.visit_for(for_loop), } } @@ -175,7 +175,7 @@ pub fn walk_while<'a, V: Visitor<'a>>(visitor: &mut V, while_loop: &'a While) { pub fn walk_assign_left_side<'a, V: Visitor<'a>>(visitor: &mut V, assign_left: &'a AssignLeftSide) { match assign_left { - AssignLeftSide::Identifier(id) => visitor.visit_identifier(id), + AssignLeftSide::Identifier(id) => visitor.visit_expression(id), AssignLeftSide::Indice(expr) => visitor.visit_expression(expr), AssignLeftSide::Dot(expr) => visitor.visit_expression(expr), } @@ -202,27 +202,27 @@ pub fn walk_else<'a, V: Visitor<'a>>(visitor: &mut V, r#else: &'a Else) { } pub fn walk_expression<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a Expression) { - match &expr.kind { - ExpressionKind::BinopExpr(unary, operator, expr) => { + match &expr { + Expression::BinopExpr(unary, operator, expr) => { visitor.visit_unary_expr(unary); visitor.visit_operator(operator); visitor.visit_expression(&*expr); } - ExpressionKind::UnaryExpr(unary) => visitor.visit_unary_expr(unary), - ExpressionKind::StructCtor(ctor) => visitor.visit_struct_ctor(ctor), - ExpressionKind::NativeOperation(op, left, right) => { + Expression::UnaryExpr(unary) => visitor.visit_unary_expr(unary), + Expression::StructCtor(ctor) => visitor.visit_struct_ctor(ctor), + Expression::NativeOperation(op, left, right) => { visitor.visit_identifier(left); visitor.visit_identifier(right); visitor.visit_native_operator(op); } - ExpressionKind::Return(expr) => { + Expression::Return(expr) => { visitor.visit_expression(expr); } } } pub fn walk_struct_ctor<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructCtor) { - visitor.visit_type(&s.name); + visitor.visit_identifier(&s.name); walk_map!(visitor, visit_expression, &s.defs); } @@ -264,10 +264,10 @@ pub fn walk_operator<'a, V: Visitor<'a>>(visitor: &mut V, operator: &'a Operator } pub fn walk_operand<'a, V: Visitor<'a>>(visitor: &mut V, operand: &'a Operand) { - match &operand.kind { - OperandKind::Literal(l) => visitor.visit_literal(l), - OperandKind::Identifier(i) => visitor.visit_identifier_path(i), - OperandKind::Expression(e) => visitor.visit_expression(&*e), + match &operand { + Operand::Literal(l) => visitor.visit_literal(l), + Operand::Identifier(i) => visitor.visit_identifier_path(i), + Operand::Expression(e) => visitor.visit_expression(&*e), } } diff --git a/src/lib/ast/visit2.rs b/src/lib/ast/visit2.rs deleted file mode 100644 index 04953944..00000000 --- a/src/lib/ast/visit2.rs +++ /dev/null @@ -1,304 +0,0 @@ -use paste::paste; - -use crate::ast::tree2::*; -use crate::ty::*; - -macro_rules! generate_visitor_trait { - ($( - $name:ty - )+) => { - pub trait Visitor<'ast>: Sized { - fn visit_name(&mut self, _name: &str) {} - - fn visit_primitive(&mut self, _val: T) - where - T: std::fmt::Debug, - {} - - paste! { - $( - fn [](&mut self, node: &'ast $name) { - [](self, node); - } - )+ - } - } - }; -} - -generate_visitor_trait!( - Root - Mod - TopLevel - Assign - AssignLeftSide - Prototype - Use - Trait - Impl - FunctionDecl - StructDecl - Identifier - IdentifierPath - // ArgumentDecl - Body - Statement - For - ForIn - While - Expression - If - Else - UnaryExpr - Operator - PrimaryExpr - SecondaryExpr - Operand - Argument - Literal - StructCtor - Array - NativeOperator - FuncType - Type -); - -pub fn walk_root<'a, V: Visitor<'a>>(visitor: &mut V, root: &'a Root) { - visitor.visit_mod(&root.r#mod); -} - -pub fn walk_mod<'a, V: Visitor<'a>>(visitor: &mut V, _mod: &'a Mod) { - walk_list!(visitor, visit_top_level, &_mod.top_levels); -} - -pub fn walk_top_level<'a, V: Visitor<'a>>(visitor: &mut V, top_level: &'a TopLevel) { - match &top_level { - TopLevel::Prototype(p) => visitor.visit_prototype(p), - TopLevel::Use(u) => visitor.visit_use(u), - TopLevel::Trait(t) => visitor.visit_trait(t), - TopLevel::Impl(i) => visitor.visit_impl(i), - TopLevel::Struct(i) => visitor.visit_struct_decl(i), - TopLevel::Mod(name, m) => { - visitor.visit_identifier(name); - visitor.visit_mod(m); - } - TopLevel::Function(f) => visitor.visit_function_decl(f), - TopLevel::Infix(ident, _) => visitor.visit_operator(ident), - }; -} - -pub fn walk_struct_decl<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructDecl) { - visitor.visit_identifier(&s.name); - - walk_list!(visitor, visit_prototype, &s.defs); -} - -pub fn walk_trait<'a, V: Visitor<'a>>(visitor: &mut V, t: &'a Trait) { - visitor.visit_type(&t.name); - - walk_list!(visitor, visit_type, &t.types); - - walk_list!(visitor, visit_prototype, &t.defs); -} - -pub fn walk_impl<'a, V: Visitor<'a>>(visitor: &mut V, i: &'a Impl) { - visitor.visit_type(&i.name); - - walk_list!(visitor, visit_type, &i.types); - - walk_list!(visitor, visit_function_decl, &i.defs); -} - -pub fn walk_prototype<'a, V: Visitor<'a>>(visitor: &mut V, prototype: &'a Prototype) { - visitor.visit_identifier(&prototype.name); - - visitor.visit_func_type(&prototype.signature); -} - -pub fn walk_use<'a, V: Visitor<'a>>(visitor: &mut V, r#use: &'a Use) { - visitor.visit_identifier_path(&r#use.path); -} - -pub fn walk_function_decl<'a, V: Visitor<'a>>(visitor: &mut V, function_decl: &'a FunctionDecl) { - visitor.visit_identifier(&function_decl.name); - - walk_list!(visitor, visit_identifier, &function_decl.arguments); - - visitor.visit_body(&function_decl.body); -} - -pub fn walk_identifier_path<'a, V: Visitor<'a>>( - visitor: &mut V, - identifier_path: &'a IdentifierPath, -) { - walk_list!(visitor, visit_identifier, &identifier_path.path); -} - -pub fn walk_identifier<'a, V: Visitor<'a>>(visitor: &mut V, identifier: &'a Identifier) { - visitor.visit_name(&identifier.name); -} - -/* pub fn walk_argument_decl<'a, V: Visitor<'a>>(visitor: &mut V, argument: &'a ArgumentDecl) { - visitor.visit_name(&argument.name); -} */ - -pub fn walk_body<'a, V: Visitor<'a>>(visitor: &mut V, body: &'a Body) { - walk_list!(visitor, visit_statement, &body.stmts); -} - -pub fn walk_statement<'a, V: Visitor<'a>>(visitor: &mut V, statement: &'a Statement) { - match &statement { - Statement::Expression(expr) => visitor.visit_expression(expr), - Statement::Assign(assign) => visitor.visit_assign(assign), - Statement::If(expr) => visitor.visit_if(expr), - Statement::For(for_loop) => visitor.visit_for(for_loop), - } -} - -pub fn walk_for<'a, V: Visitor<'a>>(visitor: &mut V, for_loop: &'a For) { - match for_loop { - For::In(for_in) => visitor.visit_for_in(for_in), - For::While(while_loop) => visitor.visit_while(while_loop), - } -} - -pub fn walk_for_in<'a, V: Visitor<'a>>(visitor: &mut V, for_in: &'a ForIn) { - visitor.visit_identifier(&for_in.value); - visitor.visit_expression(&for_in.expr); - visitor.visit_body(&for_in.body); -} - -pub fn walk_while<'a, V: Visitor<'a>>(visitor: &mut V, while_loop: &'a While) { - visitor.visit_expression(&while_loop.predicat); - visitor.visit_body(&while_loop.body); -} - -pub fn walk_assign_left_side<'a, V: Visitor<'a>>(visitor: &mut V, assign_left: &'a AssignLeftSide) { - match assign_left { - AssignLeftSide::Identifier(id) => visitor.visit_expression(id), - AssignLeftSide::Indice(expr) => visitor.visit_expression(expr), - AssignLeftSide::Dot(expr) => visitor.visit_expression(expr), - } -} - -pub fn walk_assign<'a, V: Visitor<'a>>(visitor: &mut V, assign: &'a Assign) { - visitor.visit_assign_left_side(&assign.name); - visitor.visit_expression(&assign.value); -} - -pub fn walk_if<'a, V: Visitor<'a>>(visitor: &mut V, r#if: &'a If) { - visitor.visit_expression(&r#if.predicat); - visitor.visit_body(&r#if.body); - if let Some(r#else) = &r#if.else_ { - visitor.visit_else(r#else); - } -} - -pub fn walk_else<'a, V: Visitor<'a>>(visitor: &mut V, r#else: &'a Else) { - match r#else { - Else::If(expr) => visitor.visit_if(expr), - Else::Body(expr) => visitor.visit_body(expr), - } -} - -pub fn walk_expression<'a, V: Visitor<'a>>(visitor: &mut V, expr: &'a Expression) { - match &expr { - Expression::BinopExpr(unary, operator, expr) => { - visitor.visit_unary_expr(unary); - visitor.visit_operator(operator); - visitor.visit_expression(&*expr); - } - Expression::UnaryExpr(unary) => visitor.visit_unary_expr(unary), - Expression::StructCtor(ctor) => visitor.visit_struct_ctor(ctor), - Expression::NativeOperation(op, left, right) => { - visitor.visit_identifier(left); - visitor.visit_identifier(right); - visitor.visit_native_operator(op); - } - Expression::Return(expr) => { - visitor.visit_expression(expr); - } - } -} - -pub fn walk_struct_ctor<'a, V: Visitor<'a>>(visitor: &mut V, s: &'a StructCtor) { - visitor.visit_identifier(&s.name); - - walk_map!(visitor, visit_expression, &s.defs); -} - -pub fn walk_unary_expr<'a, V: Visitor<'a>>(visitor: &mut V, unary: &'a UnaryExpr) { - match unary { - UnaryExpr::PrimaryExpr(primary) => visitor.visit_primary_expr(primary), - UnaryExpr::UnaryExpr(op, unary) => { - visitor.visit_operator(op); - visitor.visit_unary_expr(&*unary); - } - } -} - -pub fn walk_primary_expr<'a, V: Visitor<'a>>(visitor: &mut V, primary: &'a PrimaryExpr) { - visitor.visit_operand(&primary.op); - - if let Some(secondaries) = &primary.secondaries { - walk_list!(visitor, visit_secondary_expr, secondaries); - } -} - -pub fn walk_secondary_expr<'a, V: Visitor<'a>>(visitor: &mut V, secondary: &'a SecondaryExpr) { - match secondary { - SecondaryExpr::Arguments(args) => { - walk_list!(visitor, visit_argument, args); - } - SecondaryExpr::Indice(expr) => { - visitor.visit_expression(expr); - } - SecondaryExpr::Dot(expr) => { - visitor.visit_identifier(expr); - } - } -} - -pub fn walk_operator<'a, V: Visitor<'a>>(visitor: &mut V, operator: &'a Operator) { - visitor.visit_identifier(&operator.0) -} - -pub fn walk_operand<'a, V: Visitor<'a>>(visitor: &mut V, operand: &'a Operand) { - match &operand { - Operand::Literal(l) => visitor.visit_literal(l), - Operand::Identifier(i) => visitor.visit_identifier_path(i), - Operand::Expression(e) => visitor.visit_expression(&*e), - } -} - -pub fn walk_argument<'a, V: Visitor<'a>>(visitor: &mut V, argument: &'a Argument) { - visitor.visit_unary_expr(&argument.arg); -} - -pub fn walk_literal<'a, V: Visitor<'a>>(visitor: &mut V, literal: &'a Literal) { - match &literal.kind { - LiteralKind::Number(n) => visitor.visit_primitive(n), - LiteralKind::Float(f) => visitor.visit_primitive(f), - LiteralKind::String(s) => visitor.visit_primitive(s), - LiteralKind::Bool(b) => visitor.visit_primitive(b), - LiteralKind::Array(arr) => visitor.visit_array(arr), - } -} - -pub fn walk_array<'a, V: Visitor<'a>>(visitor: &mut V, arr: &'a Array) { - walk_list!(visitor, visit_expression, &arr.values); -} - -pub fn walk_native_operator<'a, V: Visitor<'a>>(_visitor: &mut V, _operator: &'a NativeOperator) { - // Nothing to do -} - -pub fn walk_func_type<'a, V: Visitor<'a>>(visitor: &mut V, signature: &'a FuncType) { - walk_list!(visitor, visit_type, &signature.arguments); - - visitor.visit_type(&signature.ret); -} - -pub fn walk_type<'a, V: Visitor<'a>>(_visitor: &mut V, _t: &'a Type) { - // Nothing to do -} diff --git a/src/lib/ast_lowering/ast_lowering_context.rs b/src/lib/ast_lowering/ast_lowering_context.rs index 7f9907ce..3da79b20 100644 --- a/src/lib/ast_lowering/ast_lowering_context.rs +++ b/src/lib/ast_lowering/ast_lowering_context.rs @@ -1,7 +1,7 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ - ast::{return_placement::ReturnInserter, *}, + ast::{return_placement::ReturnInserter, tree::*, NodeId}, hir::{self, Arena, FnBodyId, HirId}, infer::Envs, ty::*, @@ -62,40 +62,40 @@ impl AstLoweringContext { } pub fn lower_top_level(&mut self, top_level: &TopLevel) { - match &top_level.kind { - TopLevelKind::Prototype(p) => { + match &top_level { + TopLevel::Prototype(p) => { let top_level = hir::TopLevel { kind: hir::TopLevelKind::Prototype(self.lower_prototype(p)), }; self.top_levels.push(top_level); } - TopLevelKind::Function(f) => { + TopLevel::Function(f) => { let top_level = hir::TopLevel { kind: hir::TopLevelKind::Function(self.lower_function_decl(f)), }; self.top_levels.push(top_level); } - TopLevelKind::Trait(t) => { + TopLevel::Trait(t) => { self.lower_trait(t); } - TopLevelKind::Struct(s) => { + TopLevel::Struct(s) => { self.lower_struct_decl(s); } - TopLevelKind::Impl(i) => { + TopLevel::Impl(i) => { self.lower_impl(i); } - TopLevelKind::Mod(_name, mod_) => self.lower_mod(mod_), - TopLevelKind::Infix(_, _) => (), - TopLevelKind::Use(_u) => (), + TopLevel::Mod(_name, mod_) => self.lower_mod(mod_), + TopLevel::Infix(_, _) => (), + TopLevel::Use(_u) => (), }; } pub fn lower_struct_decl(&mut self, s: &StructDecl) -> hir::StructDecl { let hir_t = hir::StructDecl { - hir_id: self.hir_map.next_hir_id(s.identity.clone()), - name: s.name.clone(), + // hir_id: self.hir_map.next_hir_id(s.name.node_id), + name: self.lower_identifier(&s.name), defs: s .defs .iter() @@ -103,7 +103,7 @@ impl AstLoweringContext { .collect(), }; - self.structs.insert(s.name.get_name(), hir_t.clone()); + self.structs.insert(s.name.to_string(), hir_t.clone()); hir_t } @@ -153,14 +153,14 @@ impl AstLoweringContext { .entry(hir_f.name.name.clone()) .or_insert_with(HashMap::new); - let _hir_id = self.hir_map.next_hir_id(f.identity.clone()); + let _hir_id = self.hir_map.next_hir_id(f.node_id); (*fn_decls).insert(type_sig, hir_f); } } pub fn lower_prototype(&mut self, p: &Prototype) -> hir::Prototype { - let id = self.hir_map.next_hir_id(p.identity.clone()); + let id = self.hir_map.next_hir_id(p.node_id); let ident = self.lower_identifier(&p.name); hir::Prototype { @@ -172,7 +172,7 @@ impl AstLoweringContext { pub fn lower_function_decl(&mut self, f: &FunctionDecl) -> hir::FunctionDecl { let body_id = self.hir_map.next_body_id(); - let id = self.hir_map.next_hir_id(f.identity.clone()); + let id = self.hir_map.next_hir_id(f.node_id); let ident = self.lower_identifier(&f.name); let body = self.lower_fn_body(&f.body, ident.clone(), body_id.clone(), id.clone()); @@ -193,13 +193,13 @@ impl AstLoweringContext { } } - pub fn lower_argument_decl(&mut self, argument: &ArgumentDecl) -> hir::ArgumentDecl { - let id = self.hir_map.next_hir_id(argument.identity.clone()); + pub fn lower_argument_decl(&mut self, identifier: &Identifier) -> hir::ArgumentDecl { + let id = self.hir_map.next_hir_id(identifier.node_id); hir::ArgumentDecl { name: hir::Identifier { hir_id: id, - name: argument.name.clone(), + name: identifier.name.clone(), }, } } @@ -236,15 +236,13 @@ impl AstLoweringContext { pub fn lower_statement(&mut self, stmt: &Statement) -> hir::Statement { hir::Statement { - kind: match &*stmt.kind { - StatementKind::Expression(e) => { + kind: match &*stmt { + Statement::Expression(e) => { Box::new(hir::StatementKind::Expression(self.lower_expression(e))) } - StatementKind::If(e) => Box::new(hir::StatementKind::If(self.lower_if(e))), - StatementKind::Assign(a) => { - Box::new(hir::StatementKind::Assign(self.lower_assign(a))) - } - StatementKind::For(f) => Box::new(hir::StatementKind::For(self.lower_for(f))), + Statement::If(e) => Box::new(hir::StatementKind::If(self.lower_if(e))), + Statement::Assign(a) => Box::new(hir::StatementKind::Assign(self.lower_assign(a))), + Statement::For(f) => Box::new(hir::StatementKind::For(self.lower_for(f))), }, } } @@ -274,7 +272,7 @@ impl AstLoweringContext { pub fn lower_assign_left_side(&mut self, assign_left: &AssignLeftSide) -> hir::AssignLeftSide { match assign_left { AssignLeftSide::Identifier(id) => { - hir::AssignLeftSide::Identifier(self.lower_identifier(id)) + hir::AssignLeftSide::Identifier(self.lower_identifier(id.as_identifier().unwrap())) } AssignLeftSide::Indice(indice) => { let expr_hir = self.lower_expression(indice); @@ -310,18 +308,18 @@ impl AstLoweringContext { } pub fn lower_expression(&mut self, expr: &Expression) -> hir::Expression { - match &expr.kind { - ExpressionKind::UnaryExpr(unary) => self.lower_unary(unary), - ExpressionKind::StructCtor(s) => self.lower_struct_ctor(s), - ExpressionKind::NativeOperation(op, left, right) => { + match &expr { + Expression::UnaryExpr(unary) => self.lower_unary(unary), + Expression::StructCtor(s) => self.lower_struct_ctor(s), + Expression::NativeOperation(op, left, right) => { self.lower_native_operation(op, left, right) } - ExpressionKind::BinopExpr(_unary, _op, _expr22) => { + Expression::BinopExpr(_unary, _op, _expr22) => { let mut infix = InfixDesugar::new(self.operators_list.clone()); self.lower_expression(&infix.desugar(expr)) } - ExpressionKind::Return(expr) => hir::Expression { + Expression::Return(expr) => hir::Expression { kind: Box::new(hir::ExpressionKind::Return(self.lower_expression(&*expr))), }, } @@ -329,8 +327,8 @@ impl AstLoweringContext { pub fn lower_struct_ctor(&mut self, s: &StructCtor) -> hir::Expression { hir::Expression::new_struct_ctor(hir::StructCtor { - hir_id: self.hir_map.next_hir_id(s.identity.clone()), - name: s.name.clone(), + // hir_id: self.hir_map.next_hir_id(s.node_id), + name: self.lower_identifier(&s.name), defs: s .defs .iter() @@ -341,7 +339,7 @@ impl AstLoweringContext { pub fn lower_if(&mut self, r#if: &If) -> hir::If { hir::If { - hir_id: self.hir_map.next_hir_id(r#if.identity.clone()), + hir_id: self.hir_map.next_hir_id(r#if.node_id), predicat: self.lower_expression(&r#if.predicat), body: self.lower_body(&r#if.body), else_: r#if.else_.as_ref().map(|e| Box::new(self.lower_else(e))), @@ -370,19 +368,19 @@ impl AstLoweringContext { let mut expr = self.lower_operand(&primary.op); for secondary in &primary.secondaries.clone().unwrap() { - expr = self.lower_secondary(expr, secondary, &primary.identity.clone()); + expr = self.lower_secondary(expr, secondary, primary.node_id); } expr } pub fn lower_operand(&mut self, operand: &Operand) -> hir::Expression { - match &operand.kind { - OperandKind::Literal(l) => hir::Expression::new_literal(self.lower_literal(l)), - OperandKind::Identifier(i) => { + match &operand { + Operand::Literal(l) => hir::Expression::new_literal(self.lower_literal(l)), + Operand::Identifier(i) => { hir::Expression::new_identifier_path(self.lower_identifier_path(i)) } - OperandKind::Expression(e) => self.lower_expression(&**e), + Operand::Expression(e) => self.lower_expression(&**e), } } @@ -390,23 +388,23 @@ impl AstLoweringContext { &mut self, op: hir::Expression, secondary: &SecondaryExpr, - identity: &Identity, + node_id: NodeId, ) -> hir::Expression { match secondary { SecondaryExpr::Arguments(args) => { hir::Expression::new_function_call(hir::FunctionCall { - hir_id: self.hir_map.next_hir_id(identity.clone()), + hir_id: self.hir_map.next_hir_id(node_id.clone()), op, args: args.iter().map(|arg| self.lower_unary(&arg.arg)).collect(), }) } SecondaryExpr::Indice(expr) => hir::Expression::new_indice(hir::Indice { - hir_id: self.hir_map.next_hir_id(identity.clone()), + hir_id: self.hir_map.next_hir_id(node_id.clone()), op, value: self.lower_expression(expr), }), SecondaryExpr::Dot(expr) => hir::Expression::new_dot(hir::Dot { - hir_id: self.hir_map.next_hir_id(identity.clone()), + hir_id: self.hir_map.next_hir_id(node_id.clone()), op, value: self.lower_identifier(expr), }), @@ -414,7 +412,7 @@ impl AstLoweringContext { } pub fn lower_literal(&mut self, lit: &Literal) -> hir::Literal { - let hir_id = self.hir_map.next_hir_id(lit.identity.clone()); + let hir_id = self.hir_map.next_hir_id(lit.node_id); hir::Literal { hir_id, @@ -445,7 +443,7 @@ impl AstLoweringContext { } pub fn lower_identifier(&mut self, id: &Identifier) -> hir::Identifier { - let hir_id = self.hir_map.next_hir_id(id.identity.clone()); + let hir_id = self.hir_map.next_hir_id(id.node_id); hir::Identifier { hir_id, @@ -467,7 +465,7 @@ impl AstLoweringContext { } pub fn lower_native_operator(&mut self, op: &NativeOperator) -> hir::NativeOperator { - let hir_id = self.hir_map.next_hir_id(op.identity.clone()); + let hir_id = self.hir_map.next_hir_id(op.node_id); let kind = match op.kind { NativeOperatorKind::IAdd => hir::NativeOperatorKind::IAdd, diff --git a/src/lib/ast_lowering/hir_map.rs b/src/lib/ast_lowering/hir_map.rs index 74930e7a..5425b785 100644 --- a/src/lib/ast_lowering/hir_map.rs +++ b/src/lib/ast_lowering/hir_map.rs @@ -1,7 +1,7 @@ use std::collections::HashMap; use crate::{ - ast::*, + ast::NodeId, hir::{FnBodyId, HirId}, }; @@ -18,12 +18,12 @@ impl HirMap { Self::default() } - pub fn next_hir_id(&mut self, identity: Identity) -> HirId { + pub fn next_hir_id(&mut self, node_id: NodeId) -> HirId { let hir_id = HirId(self.hir_id_next); self.hir_id_next += 1; - self.add_hir_mapping(hir_id.clone(), identity.node_id); + self.add_hir_mapping(hir_id.clone(), node_id); hir_id } @@ -53,11 +53,11 @@ impl HirMap { pub fn duplicate_hir_mapping(&mut self, hir_id: HirId) -> Option { let node_id = self.get_node_id(&hir_id)?; - let mut fake_ident = Identity::new_placeholder(); + /* let mut fake_ident = Identity::new_placeholder(); - fake_ident.node_id = node_id; + fake_ident.node_id = node_id; */ - let new_id = self.next_hir_id(fake_ident); + let new_id = self.next_hir_id(node_id); self.add_hir_mapping(new_id.clone(), node_id); diff --git a/src/lib/ast_lowering/infix_desugar.rs b/src/lib/ast_lowering/infix_desugar.rs index df009e9c..6d1f79cb 100644 --- a/src/lib/ast_lowering/infix_desugar.rs +++ b/src/lib/ast_lowering/infix_desugar.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::ast::{Expression, ExpressionKind, Identifier, Operand, UnaryExpr}; +use crate::ast::tree::{Expression, Identifier, Operand, UnaryExpr}; #[derive(Debug)] pub enum ExprOrIdentifier { @@ -42,7 +42,7 @@ impl InfixDesugar { let left = stack.pop().unwrap(); stack.push(UnaryExpr::create_2_args_func_call( - Operand::from_identifier(id), + Operand::from_identifier(id.clone()), left.clone(), right.clone(), )); @@ -50,12 +50,12 @@ impl InfixDesugar { } } - Expression::from_unary(&stack.pop().unwrap()) + Expression::new_unary(stack.pop().unwrap()) } pub fn populate_rec(&mut self, expr: &Expression) { - match &expr.kind { - ExpressionKind::BinopExpr(unary, op, expr2) => { + match &expr { + Expression::BinopExpr(unary, op, expr2) => { self.output.push(ExprOrIdentifier::Expr(unary.clone())); self.pop_higher_operators( @@ -66,9 +66,7 @@ impl InfixDesugar { self.desugar(expr2); } - ExpressionKind::UnaryExpr(unary) => { - self.output.push(ExprOrIdentifier::Expr(unary.clone())) - } + Expression::UnaryExpr(unary) => self.output.push(ExprOrIdentifier::Expr(unary.clone())), _ => unimplemented!(), } } diff --git a/src/lib/ast_lowering/mod.rs b/src/lib/ast_lowering/mod.rs index a54e80b7..7560bdc4 100644 --- a/src/lib/ast_lowering/mod.rs +++ b/src/lib/ast_lowering/mod.rs @@ -1,4 +1,4 @@ -use crate::{ast::Root, hir}; +use crate::{ast::tree::Root, hir}; mod ast_lowering_context; mod hir_map; diff --git a/src/lib/ast_lowering2/ast_lowering_context.rs b/src/lib/ast_lowering2/ast_lowering_context.rs deleted file mode 100644 index 7652f93f..00000000 --- a/src/lib/ast_lowering2/ast_lowering_context.rs +++ /dev/null @@ -1,495 +0,0 @@ -use std::collections::{BTreeMap, HashMap}; - -use crate::{ - ast::{return_placement2::ReturnInserter, tree2::*, NodeId}, - hir::{self, Arena, FnBodyId, HirId}, - infer::Envs, - ty::*, -}; - -use super::{hir_map::HirMap, InfixDesugar}; - -pub struct AstLoweringContext { - hir_map: HirMap, - top_levels: Vec, - bodies: BTreeMap, - operators_list: HashMap, - traits: HashMap, - trait_methods: HashMap>, - structs: HashMap, -} - -impl AstLoweringContext { - pub fn new(operators_list: HashMap) -> Self { - Self { - hir_map: HirMap::new(), - top_levels: Vec::new(), - bodies: BTreeMap::new(), - traits: HashMap::new(), - trait_methods: HashMap::new(), - structs: HashMap::new(), - operators_list, - } - } - - pub fn lower_root(&mut self, root: &Root) -> hir::Root { - self.lower_mod(&root.r#mod); - - let mut hir = hir::Root { - arena: Arena::new(), - hir_map: self.hir_map.clone(), - resolutions: root.resolutions.lower_resolution_map(&self.hir_map), - type_envs: Envs::default(), - node_types: BTreeMap::new(), - top_levels: self.top_levels.clone(), - bodies: self.bodies.clone(), - traits: self.traits.clone(), - trait_methods: self.trait_methods.clone(), - spans: root.spans.clone(), - structs: self.structs.clone(), - }; - - hir.arena = hir::collect_arena(&hir); - - hir - } - - pub fn lower_mod(&mut self, r#mod: &Mod) { - r#mod - .top_levels - .iter() - .for_each(|t| self.lower_top_level(t)); - } - - pub fn lower_top_level(&mut self, top_level: &TopLevel) { - match &top_level { - TopLevel::Prototype(p) => { - let top_level = hir::TopLevel { - kind: hir::TopLevelKind::Prototype(self.lower_prototype(p)), - }; - - self.top_levels.push(top_level); - } - TopLevel::Function(f) => { - let top_level = hir::TopLevel { - kind: hir::TopLevelKind::Function(self.lower_function_decl(f)), - }; - - self.top_levels.push(top_level); - } - TopLevel::Trait(t) => { - self.lower_trait(t); - } - TopLevel::Struct(s) => { - self.lower_struct_decl(s); - } - TopLevel::Impl(i) => { - self.lower_impl(i); - } - TopLevel::Mod(_name, mod_) => self.lower_mod(mod_), - TopLevel::Infix(_, _) => (), - TopLevel::Use(_u) => (), - }; - } - - pub fn lower_struct_decl(&mut self, s: &StructDecl) -> hir::StructDecl { - let hir_t = hir::StructDecl { - // hir_id: self.hir_map.next_hir_id(s.name.node_id), - name: self.lower_identifier(&s.name), - defs: s - .defs - .iter() - .map(|proto| self.lower_prototype(proto)) - .collect(), - }; - - self.structs.insert(s.name.to_string(), hir_t.clone()); - - hir_t - } - - pub fn lower_trait(&mut self, t: &Trait) -> hir::Trait { - let hir_t = hir::Trait { - name: t.name.clone(), - types: t.types.clone(), - defs: t - .defs - .iter() - .map(|proto| self.lower_prototype(proto)) - .collect(), - }; - - self.traits.insert(t.name.clone(), hir_t.clone()); - - hir_t - } - - pub fn lower_impl(&mut self, i: &Impl) { - for f in &i.defs { - let mut hir_f = self.lower_function_decl(f); - - let mut types = vec![i.name.get_name()]; - types.extend(i.types.iter().map(|t| t.get_name())); - - let body = self.bodies.get_mut(&hir_f.body_id).unwrap(); - body.mangle(&types); - - let r#trait = self.traits.get(&i.name).unwrap(); - - let type_sig = r#trait - .defs - .iter() - .find(|proto| *proto.name == *hir_f.name) - .unwrap() - .signature - .clone(); - - let type_sig = type_sig.apply_forall_types(&r#trait.types, &i.types); - - hir_f.signature = type_sig.clone(); - - let fn_decls = self - .trait_methods - .entry(hir_f.name.name.clone()) - .or_insert_with(HashMap::new); - - let _hir_id = self.hir_map.next_hir_id(f.node_id); - - (*fn_decls).insert(type_sig, hir_f); - } - } - - pub fn lower_prototype(&mut self, p: &Prototype) -> hir::Prototype { - let id = self.hir_map.next_hir_id(p.node_id); - let ident = self.lower_identifier(&p.name); - - hir::Prototype { - name: ident, - signature: p.signature.clone(), - hir_id: id, - } - } - - pub fn lower_function_decl(&mut self, f: &FunctionDecl) -> hir::FunctionDecl { - let body_id = self.hir_map.next_body_id(); - let id = self.hir_map.next_hir_id(f.node_id); - let ident = self.lower_identifier(&f.name); - - let body = self.lower_fn_body(&f.body, ident.clone(), body_id.clone(), id.clone()); - - self.bodies.insert(body_id.clone(), body); - - hir::FunctionDecl { - name: ident, - mangled_name: None, - arguments: f - .arguments - .iter() - .map(|arg| self.lower_argument_decl(arg)) - .collect(), - body_id, - signature: f.signature.clone(), - hir_id: id, - } - } - - pub fn lower_argument_decl(&mut self, identifier: &Identifier) -> hir::ArgumentDecl { - let id = self.hir_map.next_hir_id(identifier.node_id); - - hir::ArgumentDecl { - name: hir::Identifier { - hir_id: id, - name: identifier.name.clone(), - }, - } - } - - pub fn lower_fn_body( - &mut self, - fn_body: &Body, - name: hir::Identifier, - body_id: FnBodyId, - fn_id: HirId, - ) -> hir::FnBody { - let body = ReturnInserter { body: fn_body }.run(); - - let body = self.lower_body(&body); - - hir::FnBody { - id: body_id, - fn_id, - name, - mangled_name: None, - body, - } - } - - pub fn lower_body(&mut self, body: &Body) -> hir::Body { - hir::Body { - stmts: body - .stmts - .iter() - .map(|stmt| self.lower_statement(stmt)) - .collect(), - } - } - - pub fn lower_statement(&mut self, stmt: &Statement) -> hir::Statement { - hir::Statement { - kind: match &*stmt { - Statement::Expression(e) => { - Box::new(hir::StatementKind::Expression(self.lower_expression(e))) - } - Statement::If(e) => Box::new(hir::StatementKind::If(self.lower_if(e))), - Statement::Assign(a) => Box::new(hir::StatementKind::Assign(self.lower_assign(a))), - Statement::For(f) => Box::new(hir::StatementKind::For(self.lower_for(f))), - }, - } - } - - pub fn lower_for(&mut self, for_loop: &For) -> hir::For { - match for_loop { - For::In(i) => hir::For::In(self.lower_for_in(i)), - For::While(w) => hir::For::While(self.lower_while(w)), - } - } - - pub fn lower_for_in(&mut self, for_in: &ForIn) -> hir::ForIn { - hir::ForIn { - value: self.lower_identifier(&for_in.value), - expr: self.lower_expression(&for_in.expr), - body: self.lower_body(&for_in.body), - } - } - - pub fn lower_while(&mut self, while_loop: &While) -> hir::While { - hir::While { - predicat: self.lower_expression(&while_loop.predicat), - body: self.lower_body(&while_loop.body), - } - } - - pub fn lower_assign_left_side(&mut self, assign_left: &AssignLeftSide) -> hir::AssignLeftSide { - match assign_left { - AssignLeftSide::Identifier(id) => { - hir::AssignLeftSide::Identifier(self.lower_identifier(id.as_identifier().unwrap())) - } - AssignLeftSide::Indice(indice) => { - let expr_hir = self.lower_expression(indice); - let indice = match &*expr_hir.kind { - hir::ExpressionKind::Indice(indice) => indice, - _ => unimplemented!( - "Assign left hand side can be Identifiers, Indices or dot notation" - ), - }; - - hir::AssignLeftSide::Indice(indice.clone()) - } - AssignLeftSide::Dot(dot) => { - let expr_hir = self.lower_expression(dot); - let dot = match &*expr_hir.kind { - hir::ExpressionKind::Dot(dot) => dot, - _ => unimplemented!( - "Assign left hand side can be Identifiers, Indices or dot notation" - ), - }; - - hir::AssignLeftSide::Dot(dot.clone()) - } - } - } - - pub fn lower_assign(&mut self, assign: &Assign) -> hir::Assign { - hir::Assign { - name: self.lower_assign_left_side(&assign.name), - value: self.lower_expression(&assign.value), - is_let: assign.is_let, - } - } - - pub fn lower_expression(&mut self, expr: &Expression) -> hir::Expression { - match &expr { - Expression::UnaryExpr(unary) => self.lower_unary(unary), - Expression::StructCtor(s) => self.lower_struct_ctor(s), - Expression::NativeOperation(op, left, right) => { - self.lower_native_operation(op, left, right) - } - Expression::BinopExpr(_unary, _op, _expr22) => { - let mut infix = InfixDesugar::new(self.operators_list.clone()); - - self.lower_expression(&infix.desugar(expr)) - } - Expression::Return(expr) => hir::Expression { - kind: Box::new(hir::ExpressionKind::Return(self.lower_expression(&*expr))), - }, - } - } - - pub fn lower_struct_ctor(&mut self, s: &StructCtor) -> hir::Expression { - hir::Expression::new_struct_ctor(hir::StructCtor { - // hir_id: self.hir_map.next_hir_id(s.node_id), - name: self.lower_identifier(&s.name), - defs: s - .defs - .iter() - .map(|(k, expr)| (self.lower_identifier(k), self.lower_expression(expr))) - .collect(), - }) - } - - pub fn lower_if(&mut self, r#if: &If) -> hir::If { - hir::If { - hir_id: self.hir_map.next_hir_id(r#if.node_id), - predicat: self.lower_expression(&r#if.predicat), - body: self.lower_body(&r#if.body), - else_: r#if.else_.as_ref().map(|e| Box::new(self.lower_else(e))), - } - } - - pub fn lower_else(&mut self, r#else: &Else) -> hir::Else { - match r#else { - Else::If(e) => hir::Else::If(self.lower_if(e)), - Else::Body(b) => hir::Else::Body(self.lower_body(b)), - } - } - - pub fn lower_unary(&mut self, unary: &UnaryExpr) -> hir::Expression { - match &unary { - UnaryExpr::PrimaryExpr(primary) => self.lower_primary(primary), - _ => unimplemented!(), - } - } - - pub fn lower_primary(&mut self, primary: &PrimaryExpr) -> hir::Expression { - if primary.secondaries.is_none() { - return self.lower_operand(&primary.op); - } - - let mut expr = self.lower_operand(&primary.op); - - for secondary in &primary.secondaries.clone().unwrap() { - expr = self.lower_secondary(expr, secondary, primary.node_id); - } - - expr - } - - pub fn lower_operand(&mut self, operand: &Operand) -> hir::Expression { - match &operand { - Operand::Literal(l) => hir::Expression::new_literal(self.lower_literal(l)), - Operand::Identifier(i) => { - hir::Expression::new_identifier_path(self.lower_identifier_path(i)) - } - Operand::Expression(e) => self.lower_expression(&**e), - } - } - - pub fn lower_secondary( - &mut self, - op: hir::Expression, - secondary: &SecondaryExpr, - node_id: NodeId, - ) -> hir::Expression { - match secondary { - SecondaryExpr::Arguments(args) => { - hir::Expression::new_function_call(hir::FunctionCall { - hir_id: self.hir_map.next_hir_id(node_id.clone()), - op, - args: args.iter().map(|arg| self.lower_unary(&arg.arg)).collect(), - }) - } - SecondaryExpr::Indice(expr) => hir::Expression::new_indice(hir::Indice { - hir_id: self.hir_map.next_hir_id(node_id.clone()), - op, - value: self.lower_expression(expr), - }), - SecondaryExpr::Dot(expr) => hir::Expression::new_dot(hir::Dot { - hir_id: self.hir_map.next_hir_id(node_id.clone()), - op, - value: self.lower_identifier(expr), - }), - } - } - - pub fn lower_literal(&mut self, lit: &Literal) -> hir::Literal { - let hir_id = self.hir_map.next_hir_id(lit.node_id); - - hir::Literal { - hir_id, - kind: match &lit.kind { - LiteralKind::Number(n) => hir::LiteralKind::Number(*n), - LiteralKind::Float(f) => hir::LiteralKind::Float(*f), - LiteralKind::String(s) => hir::LiteralKind::String(s.clone()), - LiteralKind::Bool(b) => hir::LiteralKind::Bool(*b), - LiteralKind::Array(arr) => hir::LiteralKind::Array(self.lower_array(arr)), - }, - } - } - - pub fn lower_array(&mut self, arr: &Array) -> hir::Array { - hir::Array { - values: arr - .values - .iter() - .map(|expr| self.lower_expression(expr)) - .collect(), - } - } - - pub fn lower_identifier_path(&mut self, path: &IdentifierPath) -> hir::IdentifierPath { - hir::IdentifierPath { - path: path.path.iter().map(|i| self.lower_identifier(i)).collect(), - } - } - - pub fn lower_identifier(&mut self, id: &Identifier) -> hir::Identifier { - let hir_id = self.hir_map.next_hir_id(id.node_id); - - hir::Identifier { - hir_id, - name: id.name.clone(), - } - } - - pub fn lower_native_operation( - &mut self, - op: &NativeOperator, - left: &Identifier, - right: &Identifier, - ) -> hir::Expression { - hir::Expression::new_native_operation( - self.lower_native_operator(op), - self.lower_identifier(left), - self.lower_identifier(right), - ) - } - - pub fn lower_native_operator(&mut self, op: &NativeOperator) -> hir::NativeOperator { - let hir_id = self.hir_map.next_hir_id(op.node_id); - - let kind = match op.kind { - NativeOperatorKind::IAdd => hir::NativeOperatorKind::IAdd, - NativeOperatorKind::ISub => hir::NativeOperatorKind::ISub, - NativeOperatorKind::IMul => hir::NativeOperatorKind::IMul, - NativeOperatorKind::IDiv => hir::NativeOperatorKind::IDiv, - NativeOperatorKind::FAdd => hir::NativeOperatorKind::FAdd, - NativeOperatorKind::FSub => hir::NativeOperatorKind::FSub, - NativeOperatorKind::FMul => hir::NativeOperatorKind::FMul, - NativeOperatorKind::FDiv => hir::NativeOperatorKind::FDiv, - NativeOperatorKind::IEq => hir::NativeOperatorKind::IEq, - NativeOperatorKind::Igt => hir::NativeOperatorKind::Igt, - NativeOperatorKind::Ige => hir::NativeOperatorKind::Ige, - NativeOperatorKind::Ilt => hir::NativeOperatorKind::Ilt, - NativeOperatorKind::Ile => hir::NativeOperatorKind::Ile, - NativeOperatorKind::FEq => hir::NativeOperatorKind::FEq, - NativeOperatorKind::Fgt => hir::NativeOperatorKind::Fgt, - NativeOperatorKind::Fge => hir::NativeOperatorKind::Fge, - NativeOperatorKind::Flt => hir::NativeOperatorKind::Flt, - NativeOperatorKind::Fle => hir::NativeOperatorKind::Fle, - NativeOperatorKind::BEq => hir::NativeOperatorKind::BEq, - NativeOperatorKind::Len => hir::NativeOperatorKind::Len, - }; - - hir::NativeOperator { hir_id, kind } - } -} diff --git a/src/lib/ast_lowering2/hir_map.rs b/src/lib/ast_lowering2/hir_map.rs deleted file mode 100644 index 5425b785..00000000 --- a/src/lib/ast_lowering2/hir_map.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::collections::HashMap; - -use crate::{ - ast::NodeId, - hir::{FnBodyId, HirId}, -}; - -#[derive(Clone, Debug, Default, Serialize, Deserialize)] -pub struct HirMap { - map: HashMap, - rev_map: HashMap, - pub hir_id_next: u64, - pub body_id_next: u64, -} - -impl HirMap { - pub fn new() -> Self { - Self::default() - } - - pub fn next_hir_id(&mut self, node_id: NodeId) -> HirId { - let hir_id = HirId(self.hir_id_next); - - self.hir_id_next += 1; - - self.add_hir_mapping(hir_id.clone(), node_id); - - hir_id - } - - pub fn next_body_id(&mut self) -> FnBodyId { - let body_id = FnBodyId(self.body_id_next); - - self.body_id_next += 1; - - body_id - } - - pub fn get_hir_id(&self, node_id: NodeId) -> Option { - self.rev_map.get(&node_id).cloned() - } - - pub fn get_node_id(&self, hir_id: &HirId) -> Option { - self.map.get(hir_id).cloned() - } - - fn add_hir_mapping(&mut self, hir_id: HirId, node_id: NodeId) { - self.map.insert(hir_id.clone(), node_id); - - self.rev_map.insert(node_id, hir_id); - } - - pub fn duplicate_hir_mapping(&mut self, hir_id: HirId) -> Option { - let node_id = self.get_node_id(&hir_id)?; - - /* let mut fake_ident = Identity::new_placeholder(); - - fake_ident.node_id = node_id; */ - - let new_id = self.next_hir_id(node_id); - - self.add_hir_mapping(new_id.clone(), node_id); - - Some(new_id) - } -} diff --git a/src/lib/ast_lowering2/infix_desugar.rs b/src/lib/ast_lowering2/infix_desugar.rs deleted file mode 100644 index c2060535..00000000 --- a/src/lib/ast_lowering2/infix_desugar.rs +++ /dev/null @@ -1,87 +0,0 @@ -use std::collections::HashMap; - -use crate::ast::tree2::{Expression, Identifier, Operand, UnaryExpr}; - -#[derive(Debug)] -pub enum ExprOrIdentifier { - Expr(UnaryExpr), - Identifier(Identifier), -} - -#[derive(Debug)] -pub struct InfixDesugar { - pub opstack: Vec, - pub output: Vec, - pub operators_list: HashMap, -} - -impl InfixDesugar { - pub fn new(operators_list: HashMap) -> Self { - InfixDesugar { - opstack: vec![], - output: vec![], - operators_list, - } - } - - pub fn desugar(&mut self, expr: &Expression) -> Expression { - self.populate_rec(expr); - - self.pop_higher_operators(0); - - self.generate_calls() - } - - pub fn generate_calls(&self) -> Expression { - let mut stack = vec![]; - for item in &self.output { - match item { - ExprOrIdentifier::Expr(expr) => stack.push(expr.clone()), - ExprOrIdentifier::Identifier(id) => { - let right = stack.pop().unwrap(); - let left = stack.pop().unwrap(); - - stack.push(UnaryExpr::create_2_args_func_call( - Operand::from_identifier(id.clone()), - left.clone(), - right.clone(), - )); - } - } - } - - Expression::new_unary(stack.pop().unwrap()) - } - - pub fn populate_rec(&mut self, expr: &Expression) { - match &expr { - Expression::BinopExpr(unary, op, expr2) => { - self.output.push(ExprOrIdentifier::Expr(unary.clone())); - - self.pop_higher_operators( - *self.operators_list.get(&op.0.name.to_string()).unwrap(), - ); - - self.opstack.push(op.0.clone()); - - self.desugar(expr2); - } - Expression::UnaryExpr(unary) => self.output.push(ExprOrIdentifier::Expr(unary.clone())), - _ => unimplemented!(), - } - } - - pub fn pop_higher_operators(&mut self, precedence: u8) { - for op in self.opstack.clone().iter().rev() { - let item_precedence = self.operators_list.get(&op.name.to_string()).unwrap(); - - if precedence <= *item_precedence { - self.opstack.pop(); - - self.output.push(ExprOrIdentifier::Identifier(op.clone())); - } else { - break; - } - } - } -} diff --git a/src/lib/ast_lowering2/loop_desugar.rs b/src/lib/ast_lowering2/loop_desugar.rs deleted file mode 100644 index f0c7ba8f..00000000 --- a/src/lib/ast_lowering2/loop_desugar.rs +++ /dev/null @@ -1,63 +0,0 @@ -use std::collections::HashMap; - -use crate::ast::{Expression, ExpressionKind, Identifier, Operand, Statement, UnaryExpr}; - -pub struct Loop { - pre_loop: Vec, - predicat: Expression, - pre_body: Vec, - body: Body, - post_body: Vec, -} - -#[derive(Debug)] -pub struct LoopDesugar {} - -impl LoopDesugar { - pub fn new() -> Self { - LoopDesugar {} - } - - pub fn desugar(&mut self, for_loop: &For) -> Loop { - match for_loop { - For::In(for_in) => self.desugar_for_in(&for_in), - For::While(while_loop) => self.desugar_while(&while_loop), - } - } - - // for item in arr - // do item - // - // --- becomes - // - // let i = 0 - // let arr_len = ~Len arr - // for i < arr_len - // let item = arr[i] // pre_body - // do item - // i = i + 1 // post_body - - - - fn desugar_for_in(&mut self, for_in: &ForIn) -> Loop { - let i_var = Statement::new_assign() - - Loop { - pre_loop: vec![], - predicat: (), - pre_body: vec![], - body: for_in.body.clone(), - post_body: vec![], - } - } - - fn desugar_while(&mut self, while_loop: &While) -> Loop { - Loop { - pre_loop: vec![], - predicat: while_loop.predicat.clone(), - pre_body: vec![], - body: while_loop.body.clone(), - post_body: vec![], - } - } -} diff --git a/src/lib/ast_lowering2/mod.rs b/src/lib/ast_lowering2/mod.rs deleted file mode 100644 index 6e67c787..00000000 --- a/src/lib/ast_lowering2/mod.rs +++ /dev/null @@ -1,13 +0,0 @@ -use crate::{ast::tree2::Root, hir}; - -mod ast_lowering_context; -mod hir_map; -mod infix_desugar; - -use ast_lowering_context::AstLoweringContext; -pub use hir_map::*; -pub use infix_desugar::*; - -pub fn lower_crate(root: &Root) -> hir::Root { - AstLoweringContext::new(root.operators_list.clone()).lower_root(root) -} diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index fd3713dc..8f827dca 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -1,7 +1,7 @@ use std::fmt::Display; -use crate::parser2::Parser; -use crate::{diagnostics::DiagnosticType, parser::span2::Span as Span2, parser::Span}; +use crate::parser::Parser; +use crate::{diagnostics::DiagnosticType, parser::span::Span, parser::span2::Span as Span2}; use crate::{ hir::HirId, parser::SourceFile, diff --git a/src/lib/hir/tree.rs b/src/lib/hir/tree.rs index 899ae34f..4e75a536 100644 --- a/src/lib/hir/tree.rs +++ b/src/lib/hir/tree.rs @@ -2,11 +2,11 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ ast::NodeId, - ast_lowering2::HirMap, + ast_lowering::HirMap, hir::hir_id::*, infer::Envs, parser::span2::Span, - resolver2::ResolutionMap, + resolver::ResolutionMap, ty::{FuncType, StructType, Type}, }; diff --git a/src/lib/infer/constraint.rs b/src/lib/infer/constraint.rs index 14b78f45..1548ab92 100644 --- a/src/lib/infer/constraint.rs +++ b/src/lib/infer/constraint.rs @@ -5,7 +5,7 @@ use crate::{ hir::visit::*, hir::*, infer::Envs, - resolver2::ResolutionMap, + resolver::ResolutionMap, ty::{FuncType, PrimitiveType, Type}, }; diff --git a/src/lib/infer/monomorphize/mod.rs b/src/lib/infer/monomorphize/mod.rs index 0a0b9b5e..758e512f 100644 --- a/src/lib/infer/monomorphize/mod.rs +++ b/src/lib/infer/monomorphize/mod.rs @@ -2,7 +2,7 @@ use std::collections::{BTreeMap, HashMap}; use crate::{ hir::{HirId, Root}, - resolver2::ResolutionMap, + resolver::ResolutionMap, }; use self::monomorphizer::Monomorphizer; diff --git a/src/lib/infer/monomorphize/monomorphizer.rs b/src/lib/infer/monomorphize/monomorphizer.rs index a9c5126e..44b8d3b4 100644 --- a/src/lib/infer/monomorphize/monomorphizer.rs +++ b/src/lib/infer/monomorphize/monomorphizer.rs @@ -4,7 +4,7 @@ use crate::{ hir::visit_mut::*, hir::*, infer::Env, - resolver2::ResolutionMap, + resolver::ResolutionMap, ty::{FuncType, Type}, }; diff --git a/src/lib/parser/lexer.rs b/src/lib/parser/lexer.rs deleted file mode 100644 index a3716bfc..00000000 --- a/src/lib/parser/lexer.rs +++ /dev/null @@ -1,594 +0,0 @@ -use crate::diagnostics::Diagnostic; - -use super::{ParsingCtx, Token, TokenType}; - -bitflags! { - struct Sep: u32 { - const WS = 0b00000001; - const EOL = 0b00000010; - const NOTALPHANUM = 0b00000100; - } -} - -macro_rules! closure_vec { - ($($m:path),*,) => { - { - vec![ - $(Box::new($m as for<'r> fn(&'r mut Lexer<'a>) -> Option),)* - ] - } - }; -} - -pub struct Lexer<'a> { - ctx: &'a mut ParsingCtx, - pub input: Vec, - cur_idx: usize, - last_char: char, - cur_line: usize, - end: bool, - base_indent: u8, - accepted_operator_chars: Vec, -} - -impl<'a> Lexer<'a> { - pub fn new(ctx: &'a mut ParsingCtx) -> Lexer { - let mut input: Vec = ctx.get_current_file().content.chars().collect(); - - input.push('\0'); - - Lexer { - ctx, - last_char: input[0], - input, - cur_idx: 0, - cur_line: 1, - end: false, - base_indent: 0, - accepted_operator_chars: super::accepted_operator_chars(), - } - } - - pub fn next(&mut self) -> Token { - if self.end { - return self.new_token(TokenType::Eof, self.cur_idx, "".to_string()); - } - - if let Some(t) = self.try_indent() { - return t; - } - - while self.last_char == ' ' { - self.forward(1); - } - - self.discard_comment(); - - let v = closure_vec![ - Self::try_fn_keyword, - Self::try_let_keyword, - Self::try_mod_keyword, - Self::try_extern_keyword, - Self::try_if_keyword, - Self::try_else_keyword, - Self::try_then_keyword, - Self::try_for_keyword, - Self::try_in_keyword, - Self::try_struct_keyword, - Self::try_infix_keyword, - Self::try_use_keyword, - Self::try_trait_keyword, - Self::try_impl_keyword, - Self::try_parens, - Self::try_braces, - Self::try_array, - Self::try_type, - Self::try_array_decl, - Self::try_bool, - Self::try_ident, - Self::try_arrow, - Self::try_operator_ident, - Self::try_native_operator, - Self::try_digit, - Self::try_coma, - Self::try_dot, - Self::try_double_semi_colon, - Self::try_semi_colon, - Self::try_equal, - Self::try_this, - Self::try_string, - Self::try_end_of, - ]; - - for method in v { - if let Some(t) = method(self) { - return t; - } - } - - if self.cur_idx >= self.input.len() - 1 { - return self.new_token(TokenType::Eof, self.cur_idx, "".to_string()); - } - - self.ctx - .diagnostics - .push_error(Diagnostic::new_unexpected_token( - self.ctx.new_span(self.cur_idx, self.cur_idx).into(), - )); - - self.end = true; - - self.new_token(TokenType::Eof, self.cur_idx, "".to_string()) - } - - fn has_separator(&self, token_len: usize, sep: Sep) -> bool { - if sep == Sep::empty() { - return true; - } - - let mut seps = vec![]; - - if sep & Sep::WS == Sep::WS { - seps.push(' '); - } - - if sep & Sep::EOL == Sep::EOL { - seps.push('\n'); - } - - if sep & Sep::NOTALPHANUM == Sep::NOTALPHANUM - && !self.input[self.cur_idx + token_len].is_alphanumeric() - { - seps.push(self.input[self.cur_idx + token_len]); - } - - seps.contains(&self.input[self.cur_idx + token_len]) - } - - fn discard_comment(&mut self) { - if self.last_char == '#' { - while self.last_char != '\n' && self.last_char != '\0' { - self.forward(1); - } - } - } - - fn forward(&mut self, n: usize) { - self.cur_idx += n; - - if self.cur_idx >= self.input.len() { - self.end = true; - - self.cur_idx = self.input.len() - 1; - - self.last_char = '\0'; - } else { - self.last_char = self.input[self.cur_idx]; - } - } - - fn new_token(&self, t: TokenType, start: usize, txt: String) -> Token { - Token { - t, - span: self.ctx.new_span(start, self.cur_idx - 1).into(), - txt, - } - } - - fn match_consume(&mut self, s: &str, t: TokenType, end: Sep) -> Option { - // TODO: optimisation: test the first letter first with last_char - - if self - .input - .iter() - .skip(self.cur_idx) - .take(s.len()) - .collect::() - == *s - { - if !self.has_separator(s.len(), end) { - return None; - } - - let start = self.cur_idx; - - self.forward(s.len()); - - return Some(self.new_token(t, start, s.to_string())); - } - - None - } - - // Actual lexer methods - - fn try_arrow(&mut self) -> Option { - self.match_consume("->", TokenType::Arrow, Sep::empty()) - } - - fn try_fn_keyword(&mut self) -> Option { - self.match_consume("fn", TokenType::Fn, Sep::WS) - } - - fn try_let_keyword(&mut self) -> Option { - self.match_consume("let", TokenType::Let, Sep::WS) - } - - fn try_mod_keyword(&mut self) -> Option { - self.match_consume("mod", TokenType::Mod, Sep::WS) - } - - fn try_extern_keyword(&mut self) -> Option { - self.match_consume("extern", TokenType::Extern, Sep::WS) - } - - fn try_if_keyword(&mut self) -> Option { - self.match_consume("if", TokenType::If, Sep::WS) - } - - fn try_else_keyword(&mut self) -> Option { - self.match_consume("else", TokenType::Else, Sep::WS | Sep::EOL) - } - - fn try_for_keyword(&mut self) -> Option { - self.match_consume("for", TokenType::For, Sep::WS | Sep::EOL) - } - - fn try_in_keyword(&mut self) -> Option { - self.match_consume("in", TokenType::In, Sep::WS | Sep::EOL) - } - - fn try_struct_keyword(&mut self) -> Option { - self.match_consume("struct", TokenType::Struct, Sep::WS) - } - - fn try_then_keyword(&mut self) -> Option { - if self.last_char == 't' { - self.match_consume("then", TokenType::Then, Sep::WS) - } else if self.last_char == '=' { - self.match_consume("=>", TokenType::Then, Sep::empty()) - } else { - None - } - } - - fn try_infix_keyword(&mut self) -> Option { - self.match_consume("infix", TokenType::Infix, Sep::WS) - } - - fn try_use_keyword(&mut self) -> Option { - self.match_consume("use", TokenType::Use, Sep::WS) - } - - fn try_trait_keyword(&mut self) -> Option { - self.match_consume("trait", TokenType::Trait, Sep::WS) - } - - fn try_impl_keyword(&mut self) -> Option { - self.match_consume("impl", TokenType::Impl, Sep::WS) - } - - fn try_bool(&mut self) -> Option { - if self.last_char == 't' { - self.match_consume("true", TokenType::Bool(true), Sep::NOTALPHANUM) - } else if self.last_char == 'f' { - self.match_consume("false", TokenType::Bool(false), Sep::NOTALPHANUM) - } else { - None - } - } - - fn try_ident(&mut self) -> Option { - let start = self.cur_idx; - - if self.last_char.is_alphabetic() || self.last_char == '_' { - let mut identifier = vec![]; - - while self.last_char.is_alphanumeric() || self.last_char == '_' { - identifier.push(self.last_char); - - self.forward(1); - } - - // if is_keyword, return None - - return Some(self.new_token( - TokenType::Identifier(identifier.iter().collect()), - start, - identifier.iter().collect(), - )); - } - - None - } - - fn try_parens(&mut self) -> Option { - if self.last_char == '(' { - self.match_consume("(", TokenType::OpenParens, Sep::empty()) - } else if self.last_char == ')' { - self.match_consume(")", TokenType::CloseParens, Sep::empty()) - } else { - None - } - } - - fn try_braces(&mut self) -> Option { - if self.last_char == '{' { - self.match_consume("{", TokenType::OpenBrace, Sep::empty()) - } else if self.last_char == '}' { - self.match_consume("}", TokenType::CloseBrace, Sep::empty()) - } else { - None - } - } - - fn try_array(&mut self) -> Option { - if self.last_char == '[' { - self.match_consume("[", TokenType::OpenArray, Sep::empty()) - } else if self.last_char == ']' { - self.match_consume("]", TokenType::CloseArray, Sep::empty()) - } else { - None - } - } - - fn try_array_decl(&mut self) -> Option { - self.match_consume("[]", TokenType::ArrayType, Sep::empty()) - } - - fn try_coma(&mut self) -> Option { - self.match_consume(",", TokenType::Coma, Sep::empty()) - } - - fn try_dot(&mut self) -> Option { - self.match_consume(".", TokenType::Dot, Sep::empty()) - } - - fn try_double_semi_colon(&mut self) -> Option { - self.match_consume("::", TokenType::DoubleSemiColon, Sep::empty()) - } - - fn try_semi_colon(&mut self) -> Option { - self.match_consume(":", TokenType::SemiColon, Sep::empty()) - } - - fn try_equal(&mut self) -> Option { - self.match_consume("=", TokenType::Equal, Sep::empty()) - } - - fn try_this(&mut self) -> Option { - if self.last_char == '@' { - self.forward(1); - - let res = self.new_token( - TokenType::Identifier("this".to_string()), - self.cur_idx, - "this".to_string(), - ); - - return Some(res); - } - - None - } - - fn try_digit(&mut self) -> Option { - let start = self.cur_idx; - let mut is_neg = false; - - if self.last_char == '-' { - is_neg = true; - - self.forward(1); - } - - let mut is_float = false; - - if self.last_char.is_digit(10) { - let mut number = vec![]; - - while self.last_char.is_digit(10) || self.last_char == '.' { - if self.last_char == '.' { - is_float = true; - } - - number.push(self.last_char); - - self.forward(1); - } - - let mut nb_str: String = number.iter().collect(); - - if is_neg { - nb_str.insert(0, '-'); - } - - let nb = if is_float { - TokenType::Float(nb_str.parse::().unwrap()) - } else { - TokenType::Number(nb_str.parse::().unwrap()) - }; - - // if is_keyword, return None - - return Some(self.new_token(nb, start, nb_str)); - } - - None - } - - fn try_operator_ident(&mut self) -> Option { - let start = self.cur_idx; - - let mut identifier = vec![]; - - if self - .accepted_operator_chars - .iter() - .any(|c| *c == self.last_char) - { - while self - .accepted_operator_chars - .iter() - .any(|c| *c == self.last_char) - { - identifier.push(self.last_char); - - self.forward(1); - } - - // if is_keyword, return None - - return Some(self.new_token( - TokenType::Operator(identifier.iter().collect()), - start, - identifier.iter().collect(), - )); - } - - None - } - - fn try_native_operator(&mut self) -> Option { - if self.last_char == '~' { - let mut res = None; - let ops = vec![ - "~IAdd", "~ISub", "~IMul", "~IDiv", "~FAdd", "~FSub", "~FMul", "~FDiv", "~IEq", - "~Igt", "~Ige", "~Ilt", "~Ile", "~FEq", "~Fgt", "~Fge", "~Flt", "~Fle", "~BEq", - "~Len", - ]; - - for op in ops { - res = self.match_consume(op, TokenType::NativeOperator(op.to_string()), Sep::WS); - - if res.is_some() { - break; - } - } - - res - } else { - None - } - } - - fn try_end_of(&mut self) -> Option { - if self.last_char == '\n' { - let res = Some(Token { - t: TokenType::Eol, - span: self.ctx.new_span(self.cur_idx, self.cur_idx).into(), - txt: "\n".to_string(), - }); - - self.forward(1); - - self.cur_line += 1; - - return res; - } - - None - } - - fn try_indent(&mut self) -> Option { - let save = self.cur_idx; - - if self.cur_idx > 0 && self.input[self.cur_idx - 1] == '\n' { - let mut indent = 0; - - while self.input[self.cur_idx] == ' ' { - let mut count = 0; - - while self.input[self.cur_idx] == ' ' - && (count < self.base_indent || self.base_indent == 0) - { - self.forward(1); - - count += 1; - } - - if self.base_indent == 0 { - self.base_indent = count; - } - - if count == self.base_indent { - indent += 1; - } - } - - if indent > 0 { - return Some(self.new_token(TokenType::Indent(indent), save, " ".to_string())); - } - - self.cur_idx = save; - } - - None - } - - fn try_string(&mut self) -> Option { - let start = self.cur_idx; - - if self.last_char == '"' { - let mut s = vec![]; - - self.forward(1); - - while self.last_char != '"' { - s.push(self.last_char); - - self.forward(1); - } - - self.forward(1); - - let res: String = s.iter().collect(); - - return Some(self.new_token(TokenType::String(res.clone()), start, res)); - } - - None - } - - fn try_type(&mut self) -> Option { - let start = self.cur_idx; - - if self.last_char.is_alphabetic() && self.last_char.is_uppercase() { - let mut identifier = vec![]; - - while self.last_char.is_alphanumeric() { - identifier.push(self.last_char); - - self.forward(1); - } - - // if is_keyword, return None - - return Some(self.new_token( - TokenType::Type(identifier.iter().collect()), - start, - identifier.iter().collect(), - )); - } - - None - } - - // - - pub fn collect(&mut self) -> Vec { - let mut res = vec![]; - - loop { - let next = self.next(); - - res.push(next.clone()); - - if next.t == TokenType::Eof { - break; - } - } - - res - } -} diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index bff13535..21088883 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -1,86 +1,999 @@ -use colored::*; +use std::collections::{BTreeMap, HashMap}; -mod lexer; -mod parser_impl; -mod parsing_context; -mod source_file; -mod span; +use std::path::PathBuf; + +use nom::branch::alt; +use nom::bytes::complete::{tag, take_while}; +use nom::character::complete::{alphanumeric0, char, line_ending, one_of, satisfy, space0, space1}; +use nom::combinator::{eof, map, opt, peek, recognize}; +use nom::error::{make_error, ErrorKind, VerboseError}; +use nom::error_position; +use nom::multi::{many0, many1, separated_list0, separated_list1}; +use nom::sequence::{delimited, preceded, terminated, tuple}; +use nom::{error::ParseError, Err, IResult}; + +// use crate::ast::identity2::Identity; +use crate::ast::tree::*; +use crate::ast::NodeId; +/* use crate::parser::span2::Span; +use crate::parser::SourceFile; */ +use crate::ty::{FuncType, PrimitiveType, StructType, Type}; + +use nom_locate::{position, LocatedSpan}; +pub type Parser<'a> = LocatedSpan<&'a str, ParserCtx>; + +type Res = IResult>; + +pub mod parsing_context; +pub mod source_file; +pub mod span; pub mod span2; -mod token; -pub use lexer::*; -pub use parser_impl::*; -pub use parsing_context::*; -pub use source_file::*; -pub use span::*; -pub use token::*; +pub use parsing_context::ParsingCtx; +pub use source_file::SourceFile; +pub use span::Span as OldSpan; +pub use span2::Span; -// use crate::ast::visit::*; -// use crate::{ast::ast_print::AstPrintContext, diagnostics::Diagnostic}; -/* -fn parse_generic(ctx: &mut ParsingCtx, mut f: F) -> Result<(R, Vec), Diagnostic> +#[cfg(test)] +mod tests; + +// TODO: +// - add support for escaped string +// - fix typing (check every types) + +pub fn accepted_operator_chars() -> Vec { + return vec!['+', '-', '/', '*', '|', '<', '>', '=', '!', '$', '@', '&']; +} + +#[derive(Debug, Clone)] +pub struct ParserCtx { + files: HashMap, + cur_file_path: PathBuf, + identities: BTreeMap, + operators_list: HashMap, + block_indent: usize, + first_indent: Option, + next_node_id: NodeId, + structs: HashMap, +} + +impl ParserCtx { + pub fn new(file_path: PathBuf) -> Self { + Self { + files: HashMap::new(), + cur_file_path: file_path, + identities: BTreeMap::new(), + operators_list: HashMap::new(), + block_indent: 0, + first_indent: None, + next_node_id: 0, + structs: HashMap::new(), + } + } + + #[cfg(test)] + pub fn new_with_operators(file_path: PathBuf, operators: HashMap) -> Self { + Self { + files: HashMap::new(), + cur_file_path: file_path, + identities: BTreeMap::new(), + operators_list: operators, + block_indent: 0, + first_indent: None, + next_node_id: 0, + structs: HashMap::new(), + } + } + + pub fn new_from(&self, name: &str) -> Self { + Self { + files: HashMap::new(), + cur_file_path: self + .cur_file_path + .parent() + .unwrap() + .join(name.to_owned() + ".rk"), + identities: BTreeMap::new(), + operators_list: HashMap::new(), + block_indent: 0, + first_indent: None, + next_node_id: self.next_node_id, + structs: HashMap::new(), + } + } + + pub fn new_identity(&mut self, span: Span) -> NodeId { + let node_id = self.next_node_id; + + self.next_node_id += 1; + + self.identities.insert(node_id, span); + + node_id + } + + pub fn current_file_path(&self) -> &PathBuf { + &self.cur_file_path + } + + // pub fn identities(&self) -> &Vec { + // &self.identities + // } + + pub fn operators(&self) -> &HashMap { + &self.operators_list + } + + pub fn add_operator(&mut self, op: String, prec: u8) { + self.operators_list.insert(op, prec); + } + + /* pub fn resolve_new_mod(&mut self, name: &str) -> Self { + let mut new = Self::new( + self.cur_file_path + .parent() + .unwrap() + .join(name.to_owned() + ".rk"), + ); + + new.identities = self.identities.clone(); + + new + } */ + + pub fn identities(&self) -> BTreeMap { + self.identities.clone() + /* .iter() + .map(|identity| (identity.node_id, identity.clone())) + .collect() */ + } + + pub fn operators_list(&self) -> HashMap { + self.operators_list.clone() + } + + pub fn files(&self) -> HashMap { + self.files.clone() + } +} + +pub fn create_parser(s: &str) -> Parser<'_> { + LocatedSpan::new_extra(s, ParserCtx::new(PathBuf::from(""))) +} + +pub fn create_parser_with_filename(s: &str, path: PathBuf) -> Parser<'_> { + LocatedSpan::new_extra(s, ParserCtx::new(path)) +} + +pub fn parse_root(input: Parser) -> Res { + // TODO: move eof check in parse_mod + map(terminated(parse_mod, eof), Root::new)(input) +} + +pub fn parse_mod(input: Parser) -> Res { + map( + many1(terminated( + parse_top_level, + many1(preceded(opt(parse_comment), line_ending)), + )), + Mod::new, + )(input) +} + +pub fn parse_top_level(input: Parser) -> Res { + alt(( + preceded( + terminated(tag("extern"), space1), + map(parse_prototype, TopLevel::new_prototype), + ), + parse_infix, + map(parse_use, TopLevel::new_use), + map(parse_struct_decl, TopLevel::new_struct), + map(parse_trait, TopLevel::new_trait), + map(parse_impl, TopLevel::new_impl), + map(parse_fn, TopLevel::new_function), + map(parse_mod_decl, |(name, mod_)| TopLevel::new_mod(name, mod_)), + ))(input) +} + +pub fn parse_comment(input: Parser) -> Res { + let (input, _) = tuple((tag("#"), many0(satisfy(|c: char| c != '\n'))))(input)?; + + Ok((input, ())) +} + +pub fn parse_eol(input: Parser) -> Res { + let (input, _) = tuple((opt(parse_comment), line_ending))(input)?; + + Ok((input, ())) +} + +pub fn parse_mod_decl(input: Parser) -> Res { + let (mut input, mod_name) = preceded(terminated(tag("mod"), space1), parse_identifier)(input)?; + + let mut new_ctx = input.extra.new_from(&mod_name.name); + let file_path = new_ctx.current_file_path().to_str().unwrap().to_string(); + + let file = SourceFile::from_file(file_path).unwrap(); // FIXME: ERRORS ARE swallowed HERE + new_ctx + .files + .insert(new_ctx.current_file_path().clone(), file); + + let content = std::fs::read_to_string(&new_ctx.current_file_path()).unwrap(); + + let mut new_parser = Parser::new_extra(&content, new_ctx); + + use nom::Finish; + // FIXME: Errors are swallowed here + let (input2, mod_) = parse_mod(new_parser).finish().unwrap(); + + // hydrate `input` with the new parser's operators + // TODO: handle duplicate operators + input + .extra + .operators_list + .extend(input2.extra.operators_list); + + // extend identities + input.extra.identities.extend(input2.extra.identities); + input.extra.next_node_id = input2.extra.next_node_id; + input.extra.files.extend(input2.extra.files); + + Ok((input, (mod_name, mod_))) +} + +pub fn parse_trait(input: Parser) -> Res { + map( + tuple(( + terminated(tag("trait"), space1), + parse_type, + many0(delimited(space1, parse_type, space0)), + many0(line_ending), + indent(separated_list1( + line_ending, + preceded(parse_block_indent, parse_prototype), + )), + )), + |(_, name, types, _, defs)| Trait::new(name, types, defs), + )(input) +} + +pub fn parse_impl(input: Parser) -> Res { + map( + tuple(( + terminated(tag("impl"), space1), + parse_type, + many0(delimited(space1, parse_type, space0)), + many0(line_ending), + indent(separated_list1( + line_ending, + preceded(parse_block_indent, parse_fn), + )), + )), + |(_, name, types, _, defs)| Impl::new(name, types, defs), + )(input) +} + +pub fn parse_struct_decl(input: Parser) -> Res { + let (mut input, struct_decl) = map( + tuple(( + terminated(tag("struct"), space1), + parse_capitalized_identifier, + many0(line_ending), + indent(separated_list0( + line_ending, + preceded(parse_block_indent, parse_prototype), + )), + )), + |(tag, name, _, defs)| StructDecl::new(name, defs), + )(input)?; + + let struct_t: StructType = struct_decl.clone().into(); + + input + .extra + .structs + .insert(struct_decl.name.name.clone(), struct_t.into()); + + Ok((input, struct_decl)) +} + +pub fn parse_use(input: Parser) -> Res { + preceded( + terminated(tag("use"), space1), + map( + tuple((parse_identity, parse_identifier_path)), + |(node_id, ident)| Use::new(ident, node_id), + ), + )(input) +} + +pub fn parse_infix(input: Parser) -> Res { + let (mut input, (parsed_op, pred)) = preceded( + terminated(tag("infix"), space1), + tuple(( + terminated(many1(allowed_operator_chars), space1), + parse_number, + )), + )(input)?; + + let (input, pos) = position(input)?; + + let (mut input, node_id) = new_identity(input, &pos); + + let op = parsed_op.join(""); + + input.extra.add_operator(op.clone(), pred.as_i64() as u8); + + let op = Operator(Identifier { name: op, node_id }); + + Ok((input, TopLevel::new_infix(op, pred.as_i64() as u8))) +} + +pub fn parse_identifier_or_operator(input: Parser) -> Res { + alt((parse_identifier, map(parse_operator, |op| op.0)))(input) +} + +pub fn parse_prototype(input: Parser) -> Res { + map( + tuple(( + parse_identity, + terminated( + parse_identifier_or_operator, + delimited(space0, tag("::"), space0), + ), + parse_signature, + )), + |(node_id, name, signature)| Prototype { + node_id, + name, + signature, + }, + )(input) +} + +pub fn parse_fn(input: Parser) -> Res { + map( + tuple(( + parse_identity, + terminated( + tuple(( + parse_identifier_or_operator, + many0(preceded(space1, parse_identifier)), + )), + delimited(space0, char('='), space0), + ), + parse_body, + )), + |(node_id, (name, arguments), body)| FunctionDecl { + node_id, + name, + body, + signature: FuncType::from_args_nb(arguments.len()), // FIXME: Should not generate random signature + arguments, + }, + )(input) +} + +fn indent<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> IResult, O, E> where - F: FnMut(&mut Parser) -> Result, + F: nom::Parser, O, E>, { - let tokens = Lexer::new(ctx).collect(); + move |mut input: Parser<'a>| { + if let Some(indent) = input.extra.first_indent { + input.extra.block_indent += indent; + } + + let (mut input, output) = parser.parse(input)?; + + if let Some(indent) = input.extra.first_indent { + input.extra.block_indent -= indent; + } - // Debug tokens - if ctx.config.show_tokens { - println!("TOKENS {:#?}", tokens); + Ok((input, output)) } +} - ctx.return_if_error()?; +pub fn parse_block_indent(input: Parser) -> Res { + let (mut input, indent) = space1(input)?; + let indent_len = indent.fragment().len(); - let mut parser = Parser::new(tokens.clone(), ctx); + if input.extra.first_indent == None { + input.extra.first_indent = Some(indent_len); + input.extra.block_indent = indent_len; + } - let ast = match f(&mut parser) { - Ok(ast) => ast, - Err(e) => { - ctx.return_if_error()?; + if indent_len == input.extra.block_indent { + Ok((input, indent_len)) + } else { + Err(nom::Err::Error(ParseError::from_error_kind( + input, + ErrorKind::Tag, + ))) + } +} - return Err(e); - } +pub fn parse_body(mut input: Parser) -> Res { + let (input, opt_eol) = opt(line_ending)(input)?; // NOTE: should not fail + + if opt_eol.is_some() { + indent(map( + separated_list1( + many1(parse_eol), + preceded(parse_block_indent, parse_statement), + ), + Body::new, + ))(input) + } else { + map(parse_statement, |stmt| Body::new(vec![stmt]))(input) + } +} + +pub fn parse_statement(input: Parser) -> Res { + alt(( + map(parse_if, Statement::new_if), + map(parse_for, Statement::new_for), + map(parse_assign, Statement::new_assign), + map(parse_expression, Statement::new_expression), + ))(input) +} + +pub fn parse_if(input: Parser) -> Res { + map( + tuple(( + parse_identity, + terminated(tag("if"), space1), + terminated(parse_expression, space0), + many1(line_ending), + parse_then, + parse_body, + opt(tuple((line_ending, parse_else))), + )), + |(node_id, if_, cond, _, _, body, else_)| { + If::new(node_id, cond, body, else_.map(|(_, else_)| Box::new(else_))) + }, + )(input.clone()) +} + +pub fn parse_then(input: Parser) -> Res { + // NOTE: This is a tweek for then block that are at indent 0 (i.e. in the test files) + let (input, indent) = if input.extra.first_indent.is_some() && input.extra.block_indent > 0 { + parse_block_indent(input)? + } else { + (input, 0) }; - Ok((ast, tokens)) + if indent == input.extra.block_indent { + let (input, _) = terminated(tag("then"), space0)(input)?; + + Ok((input, ())) + } else { + Err(nom::Err::Error(ParseError::from_error_kind( + input, + ErrorKind::Tag, + ))) + } } -pub fn parse_root(ctx: &mut ParsingCtx) -> Result { - if ctx.config.verbose { - println!(" -> Compiling {}", "root".green()); +pub fn parse_else(input: Parser) -> Res { + // NOTE: This is a tweek for else block that are at indent 0 (i.e. in the test files) + let (input, indent) = if input.extra.first_indent.is_some() && input.extra.block_indent > 0 { + parse_block_indent(input)? + } else { + (input, 0) + }; + + if indent == input.extra.block_indent { + alt(( + map( + tuple(( + terminated(tag("else"), space1), + terminated(parse_if, space0), + )), + |(_, if_)| Else::If(if_), + ), + map( + tuple(( + terminated(tag("else"), space0), + terminated(parse_body, space0), + )), + |(_, body)| Else::Body(body), + ), + ))(input) + } else { + Err(nom::Err::Error(ParseError::from_error_kind( + input, + ErrorKind::Tag, + ))) } +} - debug!(" -> Parsing Root"); +pub fn parse_for(input: Parser) -> Res { + alt((map(parse_for_in, For::In), map(parse_while, For::While)))(input) +} - let (mut ast, tokens) = parse_generic(ctx, |p| p.run_root())?; +pub fn parse_for_in(input: Parser) -> Res { + map( + tuple(( + terminated(tag("for"), space1), + terminated(parse_identifier, space0), + terminated(tag("in"), space0), + terminated(parse_expression, space0), + parse_body, + )), + |(_, var, _, expr, body)| ForIn::new(var, expr, body), + )(input) +} - ast.r#mod.tokens = tokens; +pub fn parse_while(input: Parser) -> Res { + map( + tuple(( + terminated(tag("while"), space1), + terminated(parse_expression, space0), + parse_body, + )), + |(_, cond, body)| While::new(cond, body), + )(input) +} - // Debug ast - if ctx.config.show_ast { - AstPrintContext::new().visit_root(&ast); - } +pub fn parse_assign(input: Parser) -> Res { + map( + tuple(( + opt(terminated(tag("let"), space1)), + terminated(parse_assign_left_side, space0), + terminated(tag("="), space0), + terminated(parse_expression, space0), + )), + |(opt_let, var, _, expr)| Assign::new(var, expr, opt_let.is_some()), + )(input) +} - Ok(ast) +pub fn parse_assign_left_side(input: Parser) -> Res { + let (input, expr) = parse_expression(input)?; + + let res = if expr.is_dot() { + AssignLeftSide::Dot(expr) + } else if expr.is_indice() { + AssignLeftSide::Indice(expr) + } else if expr.is_identifier() { + AssignLeftSide::Identifier(expr) + } else { + return Err(nom::Err::Error(ParseError::from_error_kind( + input, + ErrorKind::Tag, + ))); + }; + + Ok((input, res)) } -pub fn parse_mod(name: String, ctx: &mut ParsingCtx) -> Result { - debug!(" -> Parsing Mod {}", name); +pub fn parse_expression(input: Parser) -> Res { + alt(( + map( + tuple(( + parse_unary, + delimited(space0, parse_operator, space0), + parse_expression, + )), + |(l, op, r)| Expression::new_binop(l, op, r), + ), + map(parse_unary, Expression::new_unary), + map(parse_struct_ctor, Expression::new_struct_ctor), + map(parse_native_operator, |(op, id1, id2)| { + Expression::new_native_operator(op, id1, id2) + }), + // TODO: Return + ))(input) +} - let current_file = ctx.get_current_file(); +pub fn parse_native_operator( + input: Parser, +) -> Res { + map( + tuple(( + preceded( + tag("~"), + alt(( + tag("IAdd"), + tag("ISub"), + tag("IMul"), + tag("IDiv"), + tag("FAdd"), + tag("FSub"), + tag("FMul"), + tag("FDiv"), + tag("IEq"), + tag("Igt"), + tag("Ige"), + tag("Ilt"), + tag("Ile"), + tag("FEq"), + tag("Fgt"), + tag("Fge"), + tag("Flt"), + tag("Fle"), + tag("BEq"), + tag("Len"), + )), + ), + preceded(space1, parse_identifier), + preceded(space1, parse_identifier), + )), + |(tag, id1, id2)| { + let (input, node_id) = new_identity(input.clone(), &tag); + ( + NativeOperator::new(node_id, NativeOperatorKind::from_str(tag.fragment())), + id1, + id2, + ) + }, + )(input.clone()) +} - ctx.resolve_and_add_file(name)?; +pub fn parse_struct_ctor(input: Parser) -> Res { + map( + tuple(( + // parse_identity, + terminated(parse_capitalized_identifier, line_ending), + indent(separated_list0( + line_ending, + preceded( + parse_block_indent, + tuple(( + terminated(parse_identifier, delimited(space0, tag(":"), space0)), + parse_expression, + )), + ), + )), + )), + |(name, decls)| StructCtor::new(name, decls.into_iter().collect()), + )(input) +} - let (mut ast, tokens) = parse_generic(ctx, |p| p.run_mod())?; +pub fn parse_unary(input: Parser) -> Res { + map(parse_primary, UnaryExpr::new_primary)(input) +} - ctx.current_file = Some(current_file.file_path); +pub fn parse_primary(input: Parser) -> Res { + map( + tuple((parse_identity, parse_operand, many0(parse_secondary))), + |(node_id, op, secs)| PrimaryExpr::new(node_id, op, secs), + )(input) +} + +pub fn parse_secondary(input: Parser) -> Res { + alt(( + map(parse_indice, SecondaryExpr::Indice), + map(parse_dot, SecondaryExpr::Dot), + map(parse_arguments, SecondaryExpr::Arguments), + ))(input) +} - ast.tokens = tokens; +pub fn parse_arguments(input: Parser) -> Res { + alt(( + map( + tuple(( + terminated(tag("("), space0), + separated_list0(tuple((space0, tag(","), space0)), parse_argument), + terminated(tag(")"), space0), + )), + |(_, args, _)| args, + ), + map( + tuple(( + space1, + separated_list1( + tuple((space0, terminated(tag(","), space0), space0)), + parse_argument, + ), + )), + |(_, args)| args, + ), + ))(input) +} + +pub fn parse_argument(input: Parser) -> Res { + map(parse_unary, Argument::new)(input) +} - // Debug ast - if ctx.config.show_ast { - AstPrintContext::new().visit_mod(&ast); +pub fn parse_indice(input: Parser) -> Res> { + map( + tuple(( + terminated(tag("["), space0), + terminated(parse_expression, space0), + terminated(tag("]"), space0), + )), + |(_, index, _)| Box::new(index), + )(input) +} + +pub fn parse_dot(input: Parser) -> Res { + map( + tuple(( + terminated(tag("."), space0), + terminated(parse_identifier, space0), + )), + |(_, ident)| ident, + )(input) +} + +pub fn parse_operand(input: Parser) -> Res { + alt(( + map(parse_literal, Operand::new_literal), + map(parse_identifier_path, Operand::new_identifier_path), + map( + delimited( + terminated(tag("("), space0), + parse_expression, + terminated(space0, tag(")")), + ), + Operand::new_expression, + ), + ))(input) +} + +pub fn parse_identifier_path(input: Parser) -> Res { + map( + separated_list1( + tag("::"), + alt(( + map(tuple((parse_identity, tag("(*)"))), |(node_id, _)| { + Identifier::new("(*)".to_string(), node_id) + }), + parse_identifier, + // map(parse_operator, |op| op.0), + )), + ), + IdentifierPath::new, + )(input) +} + +pub fn parse_capitalized_identifier(input: Parser) -> Res { + let (input, (node_id, txt)) = tuple((parse_identity, parse_capitalized_text))(input)?; + + Ok(( + input, + Identifier { + name: txt.to_string(), + node_id, + }, + )) +} + +pub fn parse_identifier(input: Parser) -> Res { + let (input, ident_parsed) = + recognize(many1(one_of("abcdefghijklmnopqrstuvwxyz_0123456789")))(input)?; + + let (input, node_id) = new_identity(input, &ident_parsed); + + Ok(( + input, + Identifier { + name: ident_parsed.to_string(), + node_id, + }, + )) +} + +pub fn parse_operator(input: Parser) -> Res { + let (input, parsed_op) = recognize(many1(one_of(LocatedSpan::new( + // We parse any accepted operators chars here, and then check if it is a valid operator later + crate::parser::accepted_operator_chars() + .iter() + .cloned() + .collect::() + .as_str(), + ))))(input)?; + + if parsed_op.to_string() == "=" { + return Err(Err::Error(error_position!(input, ErrorKind::Eof))); } - Ok(ast) + let (input, pos) = position(input)?; + + let (input, node_id) = new_identity(input, &pos); + + Ok(( + input, + Operator(Identifier { + name: parsed_op.to_string(), + node_id, + }), + )) +} + +pub fn parse_literal(input: Parser) -> Res { + alt(( + parse_bool, + parse_float, + parse_number, + parse_array, + parse_string, + ))(input) +} + +pub fn parse_string(input: Parser) -> Res { + map( + tuple(( + parse_identity, + terminated(tag("\""), space0), + recognize(take_while(|c: char| c != '"')), + terminated(tag("\""), space0), + )), + |(node_id, _, s, _)| Literal::new_string(String::from(*s.fragment()), node_id), + )(input) +} + +pub fn parse_array(input: Parser) -> Res { + map( + tuple(( + parse_identity, + terminated(tag("["), space0), + separated_list0( + tuple((space0, terminated(tag(","), space0), space0)), + parse_expression, + ), + terminated(tag("]"), space0), + )), + |(node_id, _, elements, _)| { + Literal::new_array(Array::new(elements.into_iter().collect()), node_id) + }, + )(input) +} + +pub fn parse_bool(input: Parser) -> Res { + let (input, bool_parsed) = alt((tag("true"), tag("false")))(input)?; + + let num: bool = bool_parsed + .parse() + .map_err(|_| Err::Error(make_error(input.clone(), ErrorKind::Alpha)))?; + + let (input, node_id) = new_identity(input, &bool_parsed); + + Ok((input, Literal::new_bool(num, node_id))) +} + +pub fn parse_float(input: Parser) -> Res { + let (input, float_parsed) = + recognize(tuple((parse_number, char('.'), opt(parse_number))))(input)?; + + let num: f64 = float_parsed + .parse() + .map_err(|_| Err::Error(make_error(input.clone(), ErrorKind::Digit)))?; + + let (input, node_id) = new_identity(input, &float_parsed); + + Ok((input, Literal::new_float(num, node_id))) +} + +pub fn parse_number(input: Parser) -> Res { + let (input, parsed) = take_while(is_digit)(input)?; + + let num: i64 = parsed + .parse() + .map_err(|_| Err::Error(make_error(input.clone(), ErrorKind::Digit)))?; + + let (input, node_id) = new_identity(input, &parsed); + + Ok((input, Literal::new_number(num, node_id))) +} + +// Types + +pub fn parse_signature(input: Parser) -> Res { + let (input, parsed) = tuple(( + parse_type, + many0(preceded(delimited(space0, tag("->"), space0), parse_type)), + ))(input)?; + + let mut types = vec![parsed.0]; + + types.extend(parsed.1); + + let ret = types.pop().unwrap(); + + Ok((input, FuncType::new(types, ret))) +} + +pub fn parse_type(input: Parser) -> Res { + let (input, ty) = alt(( + map( + terminated( + one_of("abcdefghijklmnopqrstuvwxyz"), + peek(alt((space1, line_ending, eof))), + ), + |c| Type::ForAll(String::from(c)), + ), + map(delimited(tag("["), parse_type, tag("]")), |t| { + Type::Primitive(PrimitiveType::Array( + Box::new(t), + 0, // FIXME + )) + }), + map( + alt(( + map(tag("Bool"), |_| PrimitiveType::Bool), + map(tag("Int64"), |_| PrimitiveType::Int64), + map(tag("Float64"), |_| PrimitiveType::Float64), + map(tag("String"), |_| PrimitiveType::String), + )), + |t| Type::from(t), + ), + map(parse_struct_type, Type::Struct), + map(parse_capitalized_text, Type::Trait), + ))(input)?; + + Ok((input, ty)) +} + +pub fn parse_struct_type(input: Parser) -> Res { + let (input, name) = parse_capitalized_text(input)?; + + let ty = if let Some(struct_t) = input.extra.structs.get(&name) { + struct_t.as_struct_type() + } else { + return Err(nom::Err::Error(ParseError::from_error_kind( + input, + ErrorKind::Tag, + ))); + }; + + Ok((input, ty)) +} + +pub fn parse_capitalized_text(input: Parser) -> Res { + let (input, parsed) = tuple((satisfy(char::is_uppercase), alphanumeric0))(input)?; + + let txt = + format!("{}", parsed.0) + &String::from_utf8(parsed.1.bytes().collect::>()).unwrap(); + + Ok((input, txt)) +} + +// Helpers + +fn is_digit(c: char) -> bool { + c.is_numeric() +} + +fn new_identity<'a>(mut input: Parser<'a>, parsed: &Parser<'a>) -> (Parser<'a>, NodeId) { + let node_id = input.extra.new_identity(Span::from(parsed.clone())); + + (input, node_id) +} + +fn parse_identity(input: Parser) -> Res { + let (input, pos) = position(input)?; + + let (input, node_id) = new_identity(input, &pos); + + Ok((input, node_id)) +} +/* +fn parse_identity2<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> Res, O, E> +where + F: nom::Parser, O, E>, +{ + move |mut input: Parser<'a>| { + let (input, pos) = position(input)?; + + let (mut input, output) = parser.parse(input)?; + + let (input, node_id) = new_identity(input, &output); + + Ok(()) + } } */ + +pub fn allowed_operator_chars(input: Parser) -> Res { + let (input, c) = one_of(LocatedSpan::new( + crate::parser::accepted_operator_chars() + .iter() + .map(|c| c.to_string()) + .collect::>() + .join("") + .as_str(), + ))(input)?; + + Ok((input, c.to_string())) +} diff --git a/src/lib/parser/parser_impl.rs b/src/lib/parser/parser_impl.rs deleted file mode 100644 index 0acdfa78..00000000 --- a/src/lib/parser/parser_impl.rs +++ /dev/null @@ -1,1312 +0,0 @@ -/* use std::{collections::HashMap, convert::TryInto}; - -use crate::{ast::*, diagnostics::Diagnostic, parser::*, resolver::ResolutionMap, ty::*}; -type Error = Diagnostic; - -macro_rules! expect { - ($tok:expr, $self:expr) => { - if $tok != $self.cur_tok().t { - error_expect!($tok, $self); - } else { - let cur_tok = $self.cur_tok(); - - $self.consume(); - - cur_tok - } - }; -} - -macro_rules! expect_or_restore { - ($tok:expr, $self:expr) => { - if $self.cur_tok().t != $tok { - $self.restore(); - - error_expect!($tok, $self); - } else { - let cur_tok = $self.cur_tok(); - - $self.consume(); - - cur_tok - } - }; -} - -macro_rules! error_expect { - ($expected:expr, $self:expr) => { - trace!( - "Error expect: want {:?} got {:?}", - $expected, - $self.cur_tok().t - ); - - // This is not the error! macro from env_logger, see below - error!( - format!("Expected {:?} but got {:?}", $expected, $self.cur_tok().t), - $self - ); - }; -} - -macro_rules! error { - ($msg:expr, $self:expr) => { - return Err(Diagnostic::new_syntax_error( - $self.cur_tok().span.clone(), - $msg, - )) - }; -} - -macro_rules! try_or_restore { - ($expr:expr, $self:expr) => { - match $expr { - Ok(t) => t, - Err(e) => { - $self.restore(); - - return Err(e); - } - } - }; -} - -macro_rules! try_or_restore_and { - ($expr:expr, $and:expr, $self:expr) => { - match $expr { - Ok(t) => t, - Err(_e) => { - $self.restore(); - - #[allow(unreachable_code)] - return $and; - } - } - }; -} - -pub trait Parse { - fn parse(ctx: &mut Parser) -> Result - where - Self: Sized; -} - -// TODO: Create getters and setters instead of exposing publicly -pub struct Parser<'a> { - ctx: &'a mut ParsingCtx, - pub input: Vec, - pub tokens: Vec, - pub cur_tok_id: TokenId, - save: Vec, - pub block_indent: u8, - func_sigs: HashMap, - pub struct_types: HashMap, -} - -impl<'a> Parser<'a> { - pub fn new(tokens: Vec, ctx: &'a mut ParsingCtx) -> Parser { - let input: Vec = ctx.get_current_file().content.chars().collect(); - - Parser { - ctx, - input, - tokens, - save: vec![0], - cur_tok_id: 0, - block_indent: 0, - func_sigs: HashMap::new(), - struct_types: HashMap::new(), - } - } - - pub fn run_root(&mut self) -> Result { - Root::parse(self) - } - - pub fn run_mod(&mut self) -> Result { - Mod::parse(self) - } - - pub fn cur_tok(&self) -> Token { - match self.tokens.get(self.cur_tok_id as usize) { - Some(a) => a.clone(), - _ => Token::eof(), - } - } - - pub fn consume(&mut self) { - trace!("Consume token {:?}", self.cur_tok()); - - self.cur_tok_id += 1; - } - - pub fn save(&mut self) { - trace!("Save()"); - - self.save.push(self.cur_tok_id); - } - - pub fn save_pop(&mut self) { - trace!("Save_pop()"); - - self.save.pop().unwrap(); - } - - pub fn restore(&mut self) { - trace!("Restore()"); - - let save = self.save.pop().unwrap(); - - self.cur_tok_id = save; - } - - pub fn seek(&self, distance: usize) -> Token { - match self.tokens.get(self.cur_tok_id as usize + distance) { - Some(a) => a.clone(), - _ => Token::eof(), - } - } - - pub fn add_func_sig(&mut self, name: String, sig: FuncType) { - self.func_sigs.insert(name, sig); - } - - pub fn add_struct_type(&mut self, s: &StructDecl) { - self.struct_types.insert(s.name.get_name(), s.clone()); - } -} - -impl Parse for Root { - fn parse(ctx: &mut Parser) -> Result { - let r#mod = Mod::parse(ctx)?; - - r#mod - .top_levels - .iter() - .find(|top| match &top.kind { - TopLevelKind::Function(f) => f.name.name == "main", - _ => false, - }) - .ok_or_else(Diagnostic::new_no_main)?; - - Ok(Root { - spans: HashMap::new(), - unused: vec![], - resolutions: ResolutionMap::default(), - operators_list: ctx.ctx.operators_list.clone(), - r#mod, - }) - } -} - -impl Parse for Mod { - fn parse(ctx: &mut Parser) -> Result { - let mut res = vec![]; - - while TokenType::Eof != ctx.cur_tok().t { - match TopLevel::parse(ctx) { - Ok(top) => res.push(top), - Err(e) => { - ctx.ctx.diagnostics.push_error(e.clone()); - - return Err(e); - } - }; - } - - expect!(TokenType::Eof, ctx); - - Ok(Mod { - tokens: ctx.tokens.clone(), - identity: Identity::new(0, ctx.ctx.new_span(0, 0)), - top_levels: res, - }) - } -} - -impl Parse for TopLevel { - fn parse(ctx: &mut Parser) -> Result { - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - let kind = match ctx.cur_tok().t { - TokenType::Extern => { - ctx.consume(); // extern keyword - - TopLevelKind::Prototype(Prototype::parse(ctx)?) - } - TokenType::Trait => { - ctx.consume(); - - TopLevelKind::Trait(Trait::parse(ctx)?) - } - TokenType::Impl => { - ctx.consume(); - - TopLevelKind::Impl(Impl::parse(ctx)?) - } - TokenType::Struct => { - ctx.consume(); - - TopLevelKind::Struct(StructDecl::parse(ctx)?) - } - TokenType::Mod => { - ctx.consume(); // mod keyword - - let name = Identifier::parse(ctx)?; - - let mod_node = super::parse_mod(name.name.clone(), ctx.ctx) - .map_err(|diag| Diagnostic::new(name.identity.span.clone(), diag.get_kind()))?; - - TopLevelKind::Mod(name, mod_node) - } - TokenType::Use => { - ctx.consume(); // use keyword - - TopLevelKind::Use(Use::parse(ctx)?) - } - TokenType::Infix => { - ctx.consume(); // infix keyword - - let identifier = Identifier::parse(ctx)?; - - let precedence = if let TokenType::Number(num) = ctx.cur_tok().t { - ctx.consume(); - - num - } else { - panic!("Bad infix syntax"); - }; - - ctx.ctx - .add_operator(&identifier, precedence.try_into().unwrap())?; - - TopLevelKind::Infix(identifier, precedence as u8) - } - _ => { - // ctx.save(); - if let Ok(proto) = Prototype::parse(ctx) { - ctx.add_func_sig(proto.name.name.clone(), proto.signature.clone()); - - TopLevelKind::Prototype(proto) - } else { - let mut f = FunctionDecl::parse(ctx)?; - - let mut has_applied = false; - - if let Some(sig) = ctx.func_sigs.get(&f.name.name) { - f.signature = sig.clone(); - - has_applied = true; - } - if has_applied { - ctx.func_sigs.remove(&f.name.name); - } - - TopLevelKind::Function(f) - } - } - }; - - while ctx.cur_tok().t == TokenType::Eol { - ctx.consume(); - } - - Ok(TopLevel { - kind, - identity: Identity::new(token_id, token.span), - }) - } -} - -impl Parse for StructDecl { - fn parse(ctx: &mut Parser) -> Result { - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - let mut defs = vec![]; - - ctx.save(); - - let name = try_or_restore!(Type::parse(ctx), ctx); - - // TODO: resolve type here ? else it is infered as Trait(name) - - ctx.consume(); // Eol - - while let TokenType::Indent(_) = ctx.cur_tok().t { - ctx.consume(); // indent - - defs.push(Prototype::parse(ctx)?); - - expect!(TokenType::Eol, ctx); - } - - ctx.save_pop(); - - let struct_decl = StructDecl { - identity: Identity::new(token_id, token.span), - name, - defs, - }; - - ctx.add_struct_type(&struct_decl); - - Ok(struct_decl) - } -} - -impl Parse for Trait { - fn parse(ctx: &mut Parser) -> Result { - let mut types = vec![]; - let mut defs = vec![]; - - ctx.save(); - - let name = try_or_restore!(Type::parse(ctx), ctx); - - while ctx.cur_tok().t != TokenType::Eol { - types.push(Type::parse(ctx)?); - } - - ctx.consume(); // Eol - - while let TokenType::Indent(_) = ctx.cur_tok().t { - ctx.consume(); // indent - - defs.push(Prototype::parse(ctx)?); - - expect!(TokenType::Eol, ctx); - } - - ctx.save_pop(); - - Ok(Trait { name, types, defs }) - } -} - -impl Parse for Impl { - fn parse(ctx: &mut Parser) -> Result { - let mut types = vec![]; - let mut defs = vec![]; - - ctx.save(); - - let name = try_or_restore!(Type::parse(ctx), ctx); - - while ctx.cur_tok().t != TokenType::Eol { - types.push(Type::parse(ctx)?); - } - - ctx.consume(); // Eol - - ctx.block_indent += 1; - - while let TokenType::Indent(_) = ctx.cur_tok().t { - ctx.consume(); // indent - - defs.push(FunctionDecl::parse(ctx)?); - - expect!(TokenType::Eol, ctx); - } - - ctx.block_indent -= 1; - - ctx.save_pop(); - - Ok(Impl { name, types, defs }) - } -} - -impl Parse for Prototype { - fn parse(ctx: &mut Parser) -> Result { - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - ctx.save(); - - let name = try_or_restore!(Identifier::parse(ctx), ctx); - - expect_or_restore!(TokenType::DoubleSemiColon, ctx); - - let signature = try_or_restore!(FuncType::parse(ctx), ctx); - - ctx.save_pop(); - - Ok(Prototype { - name, - signature, - identity: Identity::new(token_id, token.span), - }) - } -} - -impl Parse for Use { - fn parse(ctx: &mut Parser) -> Result { - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - Ok(Use { - path: IdentifierPath::parse(ctx)?, - identity: Identity::new(token_id, token.span), - }) - } -} - -impl Parse for FunctionDecl { - fn parse(ctx: &mut Parser) -> Result { - let mut arguments = vec![]; - - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - ctx.save(); - - let name = try_or_restore!(Identifier::parse(ctx), ctx); - - if TokenType::OpenParens == ctx.cur_tok().t - || TokenType::Identifier(ctx.cur_tok().txt) == ctx.cur_tok().t - { - // manage error and restore here - arguments = ArgumentsDecl::parse(ctx)?; - } - - expect_or_restore!(TokenType::Operator("=".to_string()), ctx); - - let body = try_or_restore!(Body::parse(ctx), ctx); - - ctx.save_pop(); - - Ok(FunctionDecl { - name, - signature: FuncType::from_args_nb(arguments.len()), - arguments, - body, - identity: Identity::new(token_id, token.span), - }) - } -} - -impl Parse for ArgumentsDecl { - fn parse(ctx: &mut Parser) -> Result { - let mut res = vec![]; - - ctx.save(); - - loop { - let arg = try_or_restore!(ArgumentDecl::parse(ctx), ctx); - - res.push(arg); - - match ctx.cur_tok().t { - TokenType::Identifier(_) => {} - _ => break, - } - } - - ctx.save_pop(); - - Ok(res) - } -} - -impl Parse for ArgumentDecl { - fn parse(ctx: &mut Parser) -> Result { - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - expect!(TokenType::Identifier(ctx.cur_tok().txt), ctx); - - Ok(ArgumentDecl { - name: token.txt.clone(), - identity: Identity::new(token_id, token.span), - }) - } -} - -impl Parse for Body { - fn parse(ctx: &mut Parser) -> Result { - let mut multi = false; - - if ctx.cur_tok().t == TokenType::Eol { - multi = true; - - ctx.block_indent += 1; - } - - let mut stmts = vec![]; - - if multi { - loop { - ctx.save(); - - if ctx.cur_tok().t == TokenType::Eol { - while ctx.cur_tok().t == TokenType::Eol { - ctx.consume(); - } - } else { - // Deactivated because of struct last EOF - // ctx.restore(); - // break; - } - - if ctx.cur_tok().t != TokenType::Indent(ctx.block_indent) { - ctx.restore(); - break; - } else { - ctx.save_pop(); - ctx.consume(); - } - - ctx.save(); - let stmt = match Statement::parse(ctx) { - Ok(stmt) => stmt, - Err(_) => { - ctx.restore(); - break; - } - }; - - ctx.save_pop(); - - stmts.push(stmt); - } - } else { - stmts.push(Statement::parse(ctx)?) - } - - if multi { - ctx.block_indent -= 1; - } - - Ok(Body { stmts }) - } -} - -impl Parse for Statement { - fn parse(ctx: &mut Parser) -> Result { - let kind = if ctx.cur_tok().t == TokenType::If { - match If::parse(ctx) { - Ok(expr) => StatementKind::If(Box::new(expr)), - Err(_e) => error!("Expected if".to_string(), ctx), - } - } else if let Ok(assign) = Assign::parse(ctx) { - StatementKind::Assign(Box::new(assign)) - } else if let Ok(for_loop) = For::parse(ctx) { - StatementKind::For(for_loop) - } else { - match Expression::parse(ctx) { - Ok(expr) => StatementKind::Expression(Box::new(expr)), - Err(_e) => error!("Expected expression".to_string(), ctx), - } - }; - - Ok(Statement { - kind: Box::new(kind), - }) - } -} - -impl Parse for For { - fn parse(ctx: &mut Parser) -> Result { - expect!(TokenType::For, ctx); - - ctx.save(); - - let res = if let Ok(forin) = ForIn::parse(ctx) { - For::In(forin) - } else if let Ok(while_) = While::parse(ctx) { - For::While(while_) - } else { - ctx.restore(); - - error!("Bad for".to_string(), ctx); - }; - - ctx.save_pop(); - - Ok(res) - } -} - -impl Parse for ForIn { - fn parse(ctx: &mut Parser) -> Result { - ctx.save(); - - let value = try_or_restore!(Identifier::parse(ctx), ctx); - - expect_or_restore!(TokenType::In, ctx); - - let expr = try_or_restore!(Expression::parse(ctx), ctx); - - let body = try_or_restore!(Body::parse(ctx), ctx); - - ctx.save_pop(); - - Ok(ForIn { value, expr, body }) - } -} - -impl Parse for While { - fn parse(ctx: &mut Parser) -> Result { - ctx.save(); - - let predicat = try_or_restore!(Expression::parse(ctx), ctx); - - let body = try_or_restore!(Body::parse(ctx), ctx); - - ctx.save_pop(); - - Ok(While { predicat, body }) - } -} - -impl Parse for AssignLeftSide { - fn parse(ctx: &mut Parser) -> Result { - if ctx.seek(1).t == TokenType::OpenArray { - if let Ok(expr) = PrimaryExpr::parse(ctx) { - // TODO: - // if expr.is_indice() { - - return Ok(AssignLeftSide::Indice(Expression::from_unary( - &UnaryExpr::PrimaryExpr(expr), - ))); - // } - } - } - if ctx.seek(1).t == TokenType::Dot { - if let Ok(expr) = PrimaryExpr::parse(ctx) { - // TODO: - // if expr.is_indice() { - - return Ok(AssignLeftSide::Dot(Expression::from_unary( - &UnaryExpr::PrimaryExpr(expr), - ))); - // } - } - } - - if let Ok(id) = Identifier::parse(ctx) { - return Ok(AssignLeftSide::Identifier(id)); - } - - error!( - "Expected Identifier or Indice as assignation left side".to_string(), - ctx - ) - } -} - -impl Parse for Assign { - fn parse(ctx: &mut Parser) -> Result { - ctx.save(); - - let (is_let, name) = if TokenType::Let == ctx.cur_tok().t { - expect!(TokenType::Let, ctx); - - let name = AssignLeftSide::Identifier(try_or_restore!(Identifier::parse(ctx), ctx)); - - (true, name) - } else { - let name = try_or_restore!(AssignLeftSide::parse(ctx), ctx); - - (false, name) - }; - - expect_or_restore!(TokenType::Operator("=".to_string()), ctx); - - let mut multi = false; - - if matches!(ctx.cur_tok().t, TokenType::Eol) { - ctx.consume(); // Eol - ctx.consume(); // Indent - - multi = true; - - ctx.block_indent += 1; - } - - let value = try_or_restore!(Expression::parse(ctx), ctx); - - if multi { - ctx.block_indent -= 1; - } - - ctx.save_pop(); - - Ok(Assign { - name, - value, - is_let, - }) - } -} - -impl Parse for If { - fn parse(ctx: &mut Parser) -> Result { - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - ctx.save(); - - expect_or_restore!(TokenType::If, ctx); - - let expr = try_or_restore!(Expression::parse(ctx), ctx); - - expect_or_restore!(TokenType::Eol, ctx); - expect_or_restore!(TokenType::Indent(ctx.block_indent), ctx); - expect_or_restore!(TokenType::Then, ctx); - - let body = try_or_restore!(Body::parse(ctx), ctx); - // in case of single line body - if ctx.cur_tok().t == TokenType::Eol { - expect!(TokenType::Eol, ctx); - // expect_or_restore!(TokenType::Indent(ctx.block_indent + 2), ctx); - } - - let next = ctx.seek(1); - - if next.t != TokenType::Else { - ctx.save_pop(); - - return Ok(If { - predicat: expr, - body, - else_: None, - identity: Identity::new(token_id, token.span), - }); - } - - expect_or_restore!(TokenType::Indent(ctx.block_indent), ctx); - - expect_or_restore!(TokenType::Else, ctx); - - let else_ = try_or_restore!(Else::parse(ctx), ctx); - - ctx.save_pop(); - - Ok(If { - predicat: expr, - body, - else_: Some(Box::new(else_)), - identity: Identity::new(token_id, token.span), - }) - } -} - -impl Parse for Expression { - fn parse(ctx: &mut Parser) -> Result { - if ctx.cur_tok().t == TokenType::NativeOperator(ctx.cur_tok().txt) { - ctx.save(); - - let op = NativeOperator::parse(ctx)?; - let left = Identifier::parse(ctx)?; - let right = Identifier::parse(ctx)?; - - ctx.save_pop(); - - return Ok(Expression { - kind: ExpressionKind::NativeOperation(op, left, right), - }); - } - - if let TokenType::Type(_) = ctx.cur_tok().t { - if let Ok(s) = StructCtor::parse(ctx) { - return Ok(Expression { - kind: ExpressionKind::StructCtor(s), - }); - } else { - println!("NOT A CTOR"); - } - } - - let left = UnaryExpr::parse(ctx)?; - - let mut res = Expression { - kind: ExpressionKind::UnaryExpr(left.clone()), - }; - - // FIXME - match ctx.cur_tok().t { - TokenType::Operator(_) => (), - _ => return Ok(res), - }; - - ctx.save(); - - let op = try_or_restore_and!(Operator::parse(ctx), Ok(res), ctx); - - let right = try_or_restore_and!(Expression::parse(ctx), Ok(res), ctx); - - ctx.save_pop(); - - res.kind = ExpressionKind::BinopExpr(left, op, Box::new(right)); - - Ok(res) - } -} - -impl Parse for StructCtor { - fn parse(ctx: &mut Parser) -> Result { - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - let mut defs = HashMap::new(); - - ctx.save(); - - let name = try_or_restore!(Type::parse(ctx), ctx); - - ctx.consume(); // Eol - - ctx.block_indent += 1; - - while let TokenType::Indent(i) = ctx.cur_tok().t { - if i != ctx.block_indent { - break; - } - - ctx.consume(); // indent - - let def_name = try_or_restore!(Identifier::parse(ctx), ctx); - - expect_or_restore!(TokenType::SemiColon, ctx); - - let mut multi = false; - - if matches!(ctx.cur_tok().t, TokenType::Eol) { - ctx.consume(); // Eol - ctx.consume(); // Indent - - multi = true; - - ctx.block_indent += 1; - } - - let expr = try_or_restore!(Expression::parse(ctx), ctx); - - if multi { - ctx.block_indent -= 1; - } - - defs.insert(def_name, expr); - - if matches!(ctx.cur_tok().t, TokenType::Eol) { - ctx.consume(); - } - // expect!(TokenType::Eol, ctx); - } - - ctx.block_indent -= 1; - - ctx.save_pop(); - - Ok(StructCtor { - identity: Identity::new(token_id, token.span), - name, - defs, - }) - } -} - -impl Parse for Else { - fn parse(ctx: &mut Parser) -> Result { - Ok(match ctx.cur_tok().t { - TokenType::If => Else::If(If::parse(ctx)?), - _ => Else::Body(Body::parse(ctx)?), - }) - } -} - -impl Parse for UnaryExpr { - fn parse(ctx: &mut Parser) -> Result { - if ctx.cur_tok().t == TokenType::Operator(ctx.cur_tok().txt) { - ctx.save(); - - let op = try_or_restore!(Operator::parse(ctx), ctx); - - let unary = try_or_restore!(UnaryExpr::parse(ctx), ctx); - - ctx.save_pop(); - - return Ok(UnaryExpr::UnaryExpr(op, Box::new(unary))); - } - - Ok(UnaryExpr::PrimaryExpr(PrimaryExpr::parse(ctx)?)) - } -} - -impl Parse for Operator { - fn parse(ctx: &mut Parser) -> Result { - Ok(Operator(Identifier::parse(ctx)?)) - } -} - -impl Parse for PrimaryExpr { - fn parse(ctx: &mut Parser) -> Result { - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - let operand = Operand::parse(ctx)?; - - let mut secondaries = vec![]; - - if ctx.cur_tok().t == TokenType::Operator(ctx.cur_tok().txt) - || ctx.cur_tok().t == TokenType::Equal - { - return Ok(PrimaryExpr { - identity: Identity::new(token_id, token.span), - op: operand, - secondaries: None, - }); - } - - while let Ok(second) = SecondaryExpr::parse(ctx) { - secondaries.push(second); - - if ctx.cur_tok().t == TokenType::Operator(ctx.cur_tok().txt.clone()) - || ctx.cur_tok().t == TokenType::Equal - { - break; - } - } - - let secondaries = if secondaries.is_empty() { - None - } else { - Some(secondaries) - }; - - Ok(PrimaryExpr { - identity: Identity::new(token_id, token.span), - op: operand, - secondaries, - }) - } -} - -impl Parse for Operand { - fn parse(ctx: &mut Parser) -> Result { - let kind = if let Ok(lit) = Literal::parse(ctx) { - OperandKind::Literal(lit) - } else if let Ok(ident) = IdentifierPath::parse(ctx) { - OperandKind::Identifier(ident) - } else if ctx.cur_tok().t == TokenType::OpenParens { - ctx.save(); - - expect_or_restore!(TokenType::OpenParens, ctx); - - let expr = try_or_restore!(Expression::parse(ctx), ctx); - - expect_or_restore!(TokenType::CloseParens, ctx); - - ctx.save_pop(); - - OperandKind::Expression(Box::new(expr)) - } else { - error!("Expected operand".to_string(), ctx); - }; - - Ok(Operand { kind }) - } -} - -impl Parse for SecondaryExpr { - fn parse(ctx: &mut Parser) -> Result { - if TokenType::OpenArray == ctx.cur_tok().t { - ctx.save(); - - ctx.consume(); - - if let Ok(expr) = Expression::parse(ctx) { - expect_or_restore!(TokenType::CloseArray, ctx); - - ctx.save_pop(); - - return Ok(SecondaryExpr::Indice(Box::new(expr))); - } - } else if TokenType::Dot == ctx.cur_tok().t { - ctx.save(); - - ctx.consume(); - - if let Ok(expr) = Identifier::parse(ctx) { - ctx.save_pop(); - - return Ok(SecondaryExpr::Dot(expr)); - } - } else if let Ok(args) = Arguments::parse(ctx) { - return Ok(SecondaryExpr::Arguments(args)); - } - - error!("Expected secondary".to_string(), ctx); - } -} - -impl Parse for Literal { - fn parse(ctx: &mut Parser) -> Result { - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - Ok(Self { - kind: LiteralKind::parse(ctx)?, - identity: Identity::new(token_id, token.span), - }) - } -} - -impl Parse for LiteralKind { - fn parse(ctx: &mut Parser) -> Result { - if let TokenType::Number(num) = ctx.cur_tok().t { - ctx.consume(); - - return Ok(LiteralKind::Number(num)); - } - - if let TokenType::Float(float) = ctx.cur_tok().t { - ctx.consume(); - - return Ok(LiteralKind::Float(float)); - } - - if let TokenType::Bool(b) = ctx.cur_tok().t { - ctx.consume(); - - let v = b; - - return Ok(LiteralKind::Bool(v)); - } - - if let TokenType::String(s) = ctx.cur_tok().t { - ctx.consume(); - - return Ok(LiteralKind::String(s)); - } - - if TokenType::OpenArray == ctx.cur_tok().t { - return Ok(LiteralKind::Array(Array::parse(ctx)?)); - } - - error!("Expected literal".to_string(), ctx); - } -} - -impl Parse for Array { - fn parse(ctx: &mut Parser) -> Result { - expect!(TokenType::OpenArray, ctx); - - let mut values = vec![]; - - if TokenType::CloseArray == ctx.cur_tok().t { - ctx.consume(); - } else { - loop { - values.push(Expression::parse(ctx)?); - - if TokenType::CloseArray == ctx.cur_tok().t { - ctx.consume(); - - break; - } else { - expect!(TokenType::Coma, ctx); - } - } - } - Ok(Array { values }) - } -} - -impl Parse for IdentifierPath { - fn parse(ctx: &mut Parser) -> Result { - let mut path = vec![]; - - ctx.save(); - - loop { - let tok = try_or_restore!(Identifier::parse(ctx), ctx); - - path.push(tok.clone()); - - if TokenType::DoubleSemiColon != ctx.cur_tok().t { - break; - } - - expect!(TokenType::DoubleSemiColon, ctx); - } - - ctx.save_pop(); - - Ok(Self { path }) - } -} - -impl Parse for Identifier { - fn parse(ctx: &mut Parser) -> Result { - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - let txt = match ctx.cur_tok().t { - TokenType::Identifier(id) => id, - TokenType::Operator(op) => op, - _ => error!("Not an operator".to_string(), ctx), - }; - - ctx.consume(); - - Ok(Self { - name: txt, - identity: Identity::new(token_id, token.span), - }) - } -} - -impl Parse for Arguments { - fn parse(ctx: &mut Parser) -> Result { - let mut res = vec![]; - - ctx.save(); - - // TODO: factorise this with a match! macro ? - if TokenType::OpenParens == ctx.cur_tok().t && TokenType::CloseParens == ctx.seek(1).t { - ctx.consume(); - ctx.consume(); - - ctx.save_pop(); - - return Ok(res); - } - - loop { - let arg = try_or_restore!(Argument::parse(ctx), ctx); - - res.push(arg); - - if TokenType::Coma != ctx.cur_tok().t { - break; - } - - ctx.consume(); - } - - ctx.save_pop(); - - Ok(res) - } -} - -impl Parse for Argument { - fn parse(ctx: &mut Parser) -> Result { - Ok(Argument { - arg: UnaryExpr::parse(ctx)?, - }) - } -} - -impl Parse for NativeOperator { - fn parse(ctx: &mut Parser) -> Result { - let token_id = ctx.cur_tok_id; - let token = ctx.cur_tok(); - - let op = match ctx.cur_tok().t { - TokenType::NativeOperator(op) => op, - _ => error!("Expected native operator".to_string(), ctx), - }; - - let kind = match op.as_ref() { - "~IAdd" => NativeOperatorKind::IAdd, - "~ISub" => NativeOperatorKind::ISub, - "~IMul" => NativeOperatorKind::IMul, - "~IDiv" => NativeOperatorKind::IDiv, - "~FAdd" => NativeOperatorKind::FAdd, - "~FSub" => NativeOperatorKind::FSub, - "~FMul" => NativeOperatorKind::FMul, - "~FDiv" => NativeOperatorKind::FDiv, - "~IEq" => NativeOperatorKind::IEq, - "~Igt" => NativeOperatorKind::Igt, - "~Ige" => NativeOperatorKind::Ige, - "~Ilt" => NativeOperatorKind::Ilt, - "~Ile" => NativeOperatorKind::Ile, - "~FEq" => NativeOperatorKind::FEq, - "~Fgt" => NativeOperatorKind::Fgt, - "~Fge" => NativeOperatorKind::Fge, - "~Flt" => NativeOperatorKind::Flt, - "~Fle" => NativeOperatorKind::Fle, - "~BEq" => NativeOperatorKind::BEq, - "~Len" => NativeOperatorKind::Len, - _ => error!("Unknown native operator".to_string(), ctx), - }; - - ctx.consume(); - - Ok(NativeOperator { - kind, - identity: Identity::new(token_id, token.span), - }) - } -} - -impl Parse for Type { - fn parse(ctx: &mut Parser) -> Result { - let token = ctx.cur_tok(); - - if let TokenType::Type(_t) = token.t { - ctx.consume(); - - if let Some(prim) = PrimitiveType::from_name(&token.txt) { - Ok(Type::Primitive(prim)) - } else { - if let Some(s) = ctx.struct_types.get(&token.txt) { - return Ok(s.into()); - } - Ok(Type::Trait(token.txt)) - } - } else if token.txt.len() == 1 && token.txt.chars().next().unwrap().is_lowercase() { - ctx.consume(); - - Ok(Type::ForAll(token.txt)) - } else if TokenType::OpenArray == token.t { - ctx.consume(); - - let inner_t = Type::parse(ctx)?; - - // FIXME: FIXED ARRAY SIZE OF 1KB ! - let t = Type::Primitive(PrimitiveType::Array(Box::new(inner_t), 2)); - - expect!(TokenType::CloseArray, ctx); - - Ok(t) - } else if TokenType::OpenParens == token.t { - ctx.consume(); - - let t = Type::Func(FuncType::parse(ctx)?); - - expect!(TokenType::CloseParens, ctx); - - Ok(t) - } else { - panic!("Not a type"); - } - } -} - -impl Parse for FuncType { - fn parse(ctx: &mut Parser) -> Result { - let mut arguments = vec![]; - - loop { - let t = Type::parse(ctx)?; - - arguments.push(t); - - if ctx.cur_tok().t != TokenType::Arrow { - break; - } - - ctx.consume(); - } - - let ret = Box::new(arguments.pop().unwrap()); - - Ok(FuncType { arguments, ret }) - } -} */ diff --git a/src/lib/parser/parsing_context.rs b/src/lib/parser/parsing_context.rs index 509051eb..17c93471 100644 --- a/src/lib/parser/parsing_context.rs +++ b/src/lib/parser/parsing_context.rs @@ -6,7 +6,7 @@ use std::{ use colored::*; use crate::{ - ast::{ast_print::AstPrintContext, tree2, Identifier, NodeId, Root}, + ast::{ast_print::AstPrintContext, tree, Identifier, NodeId, Root}, diagnostics::{Diagnostic, DiagnosticType, Diagnostics}, parser::span2::Span, Config, @@ -175,7 +175,7 @@ impl ParsingCtx { Ok(new_file) } - pub fn add_operator(&mut self, name: &Identifier, precedence: u8) -> Result<(), Diagnostic> { + /* pub fn add_operator(&mut self, name: &Identifier, precedence: u8) -> Result<(), Diagnostic> { if self.operator_exists(name) { return Err(Diagnostic::new_duplicated_operator( name.identity.span.clone(), @@ -185,15 +185,15 @@ impl ParsingCtx { self.operators_list.insert(name.name.clone(), precedence); Ok(()) - } + } */ pub fn operator_exists(&self, name: &Identifier) -> bool { self.operators_list.contains_key(&name.name) } #[allow(dead_code)] - pub fn print_ast(&self, ast: &tree2::Root) { - use crate::ast::visit2::Visitor; + pub fn print_ast(&self, ast: &tree::Root) { + use crate::ast::visit::Visitor; AstPrintContext::new().visit_root(ast); } diff --git a/src/lib/parser/source_file.rs b/src/lib/parser/source_file.rs index 4bab9df1..4d55c9cd 100644 --- a/src/lib/parser/source_file.rs +++ b/src/lib/parser/source_file.rs @@ -5,7 +5,7 @@ use std::{ use crate::diagnostics::Diagnostic; -use super::Span; +use super::span::Span; #[derive(Default, Debug, Clone)] pub struct SourceFile { diff --git a/src/lib/parser/span2.rs b/src/lib/parser/span2.rs index deaa5f80..c4ea839b 100644 --- a/src/lib/parser/span2.rs +++ b/src/lib/parser/span2.rs @@ -1,6 +1,6 @@ use std::path::PathBuf; -use crate::parser2::Parser; +use crate::parser::Parser; // TODO: merge spans diff --git a/src/lib/parser/token.rs b/src/lib/parser/token.rs deleted file mode 100644 index 1c79f51c..00000000 --- a/src/lib/parser/token.rs +++ /dev/null @@ -1,86 +0,0 @@ -use super::Span; - -pub fn accepted_operator_chars() -> Vec { - return vec!['+', '-', '/', '*', '|', '<', '>', '=', '!', '$', '@', '&']; -} - -#[derive(Clone, Debug, PartialEq)] -pub enum TokenType { - // keywords - Fn, - Let, - Mod, - Use, - Extern, - If, - Then, - Else, - For, - In, - While, - Struct, - Infix, - Trait, - Impl, - - // punct - Arrow, - Coma, - Dot, - SemiColon, - DoubleSemiColon, - Equal, - ArrayType, - // EqualEqual, // == - // DashEqual, // != - OpenParens, - CloseParens, - OpenArray, - CloseArray, - OpenBrace, - CloseBrace, - - //Operator - Operator(String), - NativeOperator(String), - - // primitives - Identifier(String), - Number(i64), - Float(f64), - String(String), - Bool(bool), - Type(String), - - // indent - Indent(u8), - - // whitespaces - Eol, - Eof, -} - -impl Default for TokenType { - fn default() -> TokenType { - TokenType::Eof - } -} - -#[derive(Clone, Debug)] -pub struct Token { - pub t: TokenType, - pub span: Span, - pub txt: String, -} - -pub type TokenId = usize; - -impl Token { - pub fn eof() -> Self { - Token { - t: TokenType::Eof, - span: Span::new_placeholder(), - txt: "".to_string(), - } - } -} diff --git a/src/lib/parser2/mod.rs b/src/lib/parser2/mod.rs deleted file mode 100644 index 487cf1cf..00000000 --- a/src/lib/parser2/mod.rs +++ /dev/null @@ -1,985 +0,0 @@ -use std::collections::{BTreeMap, HashMap}; - -use std::path::PathBuf; - -use nom::branch::alt; -use nom::bytes::complete::{tag, take_while}; -use nom::character::complete::{alphanumeric0, char, line_ending, one_of, satisfy, space0, space1}; -use nom::combinator::{eof, map, opt, peek, recognize}; -use nom::error::{make_error, ErrorKind, VerboseError}; -use nom::error_position; -use nom::multi::{many0, many1, separated_list0, separated_list1}; -use nom::sequence::{delimited, preceded, terminated, tuple}; -use nom::{error::ParseError, Err, IResult}; - -use crate::ast::identity2::Identity; -use crate::ast::tree2::*; -use crate::ast::NodeId; -use crate::parser::span2::Span; -use crate::parser::SourceFile; -use crate::ty::{FuncType, PrimitiveType, StructType, Type}; - -use nom_locate::{position, LocatedSpan}; -pub type Parser<'a> = LocatedSpan<&'a str, ParserCtx>; - -type Res = IResult>; - -#[cfg(test)] -mod tests; - -// TODO: -// - add support for escaped string -// - fix typing (check every types) - -#[derive(Debug, Clone)] -pub struct ParserCtx { - files: HashMap, - cur_file_path: PathBuf, - identities: BTreeMap, - operators_list: HashMap, - block_indent: usize, - first_indent: Option, - next_node_id: NodeId, - structs: HashMap, -} - -impl ParserCtx { - pub fn new(file_path: PathBuf) -> Self { - Self { - files: HashMap::new(), - cur_file_path: file_path, - identities: BTreeMap::new(), - operators_list: HashMap::new(), - block_indent: 0, - first_indent: None, - next_node_id: 0, - structs: HashMap::new(), - } - } - - #[cfg(test)] - pub fn new_with_operators(file_path: PathBuf, operators: HashMap) -> Self { - Self { - files: HashMap::new(), - cur_file_path: file_path, - identities: BTreeMap::new(), - operators_list: operators, - block_indent: 0, - first_indent: None, - next_node_id: 0, - structs: HashMap::new(), - } - } - - pub fn new_from(&self, name: &str) -> Self { - Self { - files: HashMap::new(), - cur_file_path: self - .cur_file_path - .parent() - .unwrap() - .join(name.to_owned() + ".rk"), - identities: BTreeMap::new(), - operators_list: HashMap::new(), - block_indent: 0, - first_indent: None, - next_node_id: self.next_node_id, - structs: HashMap::new(), - } - } - - pub fn new_identity(&mut self, span: Span) -> NodeId { - let node_id = self.next_node_id; - - self.next_node_id += 1; - - self.identities.insert(node_id, span); - - node_id - } - - pub fn current_file_path(&self) -> &PathBuf { - &self.cur_file_path - } - - // pub fn identities(&self) -> &Vec { - // &self.identities - // } - - pub fn operators(&self) -> &HashMap { - &self.operators_list - } - - pub fn add_operator(&mut self, op: String, prec: u8) { - self.operators_list.insert(op, prec); - } - - /* pub fn resolve_new_mod(&mut self, name: &str) -> Self { - let mut new = Self::new( - self.cur_file_path - .parent() - .unwrap() - .join(name.to_owned() + ".rk"), - ); - - new.identities = self.identities.clone(); - - new - } */ - - pub fn identities(&self) -> BTreeMap { - self.identities.clone() - /* .iter() - .map(|identity| (identity.node_id, identity.clone())) - .collect() */ - } - - pub fn operators_list(&self) -> HashMap { - self.operators_list.clone() - } - - pub fn files(&self) -> HashMap { - self.files.clone() - } -} - -pub fn create_parser(s: &str) -> Parser<'_> { - LocatedSpan::new_extra(s, ParserCtx::new(PathBuf::from(""))) -} - -pub fn create_parser_with_filename(s: &str, path: PathBuf) -> Parser<'_> { - LocatedSpan::new_extra(s, ParserCtx::new(path)) -} - -pub fn parse_root(input: Parser) -> Res { - // TODO: move eof check in parse_mod - map(terminated(parse_mod, eof), Root::new)(input) -} - -pub fn parse_mod(input: Parser) -> Res { - map( - many1(terminated( - parse_top_level, - many1(preceded(opt(parse_comment), line_ending)), - )), - Mod::new, - )(input) -} - -pub fn parse_top_level(input: Parser) -> Res { - alt(( - preceded( - terminated(tag("extern"), space1), - map(parse_prototype, TopLevel::new_prototype), - ), - parse_infix, - map(parse_use, TopLevel::new_use), - map(parse_struct_decl, TopLevel::new_struct), - map(parse_trait, TopLevel::new_trait), - map(parse_impl, TopLevel::new_impl), - map(parse_fn, TopLevel::new_function), - map(parse_mod_decl, |(name, mod_)| TopLevel::new_mod(name, mod_)), - ))(input) -} - -pub fn parse_comment(input: Parser) -> Res { - let (input, _) = tuple((tag("#"), many0(satisfy(|c: char| c != '\n'))))(input)?; - - Ok((input, ())) -} - -pub fn parse_eol(input: Parser) -> Res { - let (input, _) = tuple((opt(parse_comment), line_ending))(input)?; - - Ok((input, ())) -} - -pub fn parse_mod_decl(input: Parser) -> Res { - let (mut input, mod_name) = preceded(terminated(tag("mod"), space1), parse_identifier)(input)?; - - let mut new_ctx = input.extra.new_from(&mod_name.name); - let file_path = new_ctx.current_file_path().to_str().unwrap().to_string(); - - let file = SourceFile::from_file(file_path).unwrap(); // FIXME: ERRORS ARE swallowed HERE - new_ctx - .files - .insert(new_ctx.current_file_path().clone(), file); - - let content = std::fs::read_to_string(&new_ctx.current_file_path()).unwrap(); - - let mut new_parser = Parser::new_extra(&content, new_ctx); - - use nom::Finish; - // FIXME: Errors are swallowed here - let (input2, mod_) = parse_mod(new_parser).finish().unwrap(); - - // hydrate `input` with the new parser's operators - // TODO: handle duplicate operators - input - .extra - .operators_list - .extend(input2.extra.operators_list); - - // extend identities - input.extra.identities.extend(input2.extra.identities); - input.extra.next_node_id = input2.extra.next_node_id; - input.extra.files.extend(input2.extra.files); - - Ok((input, (mod_name, mod_))) -} - -pub fn parse_trait(input: Parser) -> Res { - map( - tuple(( - terminated(tag("trait"), space1), - parse_type, - many0(delimited(space1, parse_type, space0)), - many0(line_ending), - indent(separated_list1( - line_ending, - preceded(parse_block_indent, parse_prototype), - )), - )), - |(_, name, types, _, defs)| Trait::new(name, types, defs), - )(input) -} - -pub fn parse_impl(input: Parser) -> Res { - map( - tuple(( - terminated(tag("impl"), space1), - parse_type, - many0(delimited(space1, parse_type, space0)), - many0(line_ending), - indent(separated_list1( - line_ending, - preceded(parse_block_indent, parse_fn), - )), - )), - |(_, name, types, _, defs)| Impl::new(name, types, defs), - )(input) -} - -pub fn parse_struct_decl(input: Parser) -> Res { - let (mut input, struct_decl) = map( - tuple(( - terminated(tag("struct"), space1), - parse_capitalized_identifier, - many0(line_ending), - indent(separated_list0( - line_ending, - preceded(parse_block_indent, parse_prototype), - )), - )), - |(tag, name, _, defs)| StructDecl::new(name, defs), - )(input)?; - - let struct_t: StructType = struct_decl.clone().into(); - - input - .extra - .structs - .insert(struct_decl.name.name.clone(), struct_t.into()); - - Ok((input, struct_decl)) -} - -pub fn parse_use(input: Parser) -> Res { - preceded( - terminated(tag("use"), space1), - map( - tuple((parse_identity, parse_identifier_path)), - |(node_id, ident)| Use::new(ident, node_id), - ), - )(input) -} - -pub fn parse_infix(input: Parser) -> Res { - let (mut input, (parsed_op, pred)) = preceded( - terminated(tag("infix"), space1), - tuple(( - terminated(many1(allowed_operator_chars), space1), - parse_number, - )), - )(input)?; - - let (input, pos) = position(input)?; - - let (mut input, node_id) = new_identity(input, &pos); - - let op = parsed_op.join(""); - - input.extra.add_operator(op.clone(), pred.as_i64() as u8); - - let op = Operator(Identifier { name: op, node_id }); - - Ok((input, TopLevel::new_infix(op, pred.as_i64() as u8))) -} - -pub fn parse_identifier_or_operator(input: Parser) -> Res { - alt((parse_identifier, map(parse_operator, |op| op.0)))(input) -} - -pub fn parse_prototype(input: Parser) -> Res { - map( - tuple(( - parse_identity, - terminated( - parse_identifier_or_operator, - delimited(space0, tag("::"), space0), - ), - parse_signature, - )), - |(node_id, name, signature)| Prototype { - node_id, - name, - signature, - }, - )(input) -} - -pub fn parse_fn(input: Parser) -> Res { - map( - tuple(( - parse_identity, - terminated( - tuple(( - parse_identifier_or_operator, - many0(preceded(space1, parse_identifier)), - )), - delimited(space0, char('='), space0), - ), - parse_body, - )), - |(node_id, (name, arguments), body)| FunctionDecl { - node_id, - name, - body, - signature: FuncType::from_args_nb(arguments.len()), // FIXME: Should not generate random signature - arguments, - }, - )(input) -} - -fn indent<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> IResult, O, E> -where - F: nom::Parser, O, E>, -{ - move |mut input: Parser<'a>| { - if let Some(indent) = input.extra.first_indent { - input.extra.block_indent += indent; - } - - let (mut input, output) = parser.parse(input)?; - - if let Some(indent) = input.extra.first_indent { - input.extra.block_indent -= indent; - } - - Ok((input, output)) - } -} - -pub fn parse_block_indent(input: Parser) -> Res { - let (mut input, indent) = space1(input)?; - let indent_len = indent.fragment().len(); - - if input.extra.first_indent == None { - input.extra.first_indent = Some(indent_len); - input.extra.block_indent = indent_len; - } - - if indent_len == input.extra.block_indent { - Ok((input, indent_len)) - } else { - Err(nom::Err::Error(ParseError::from_error_kind( - input, - ErrorKind::Tag, - ))) - } -} - -pub fn parse_body(mut input: Parser) -> Res { - let (input, opt_eol) = opt(line_ending)(input)?; // NOTE: should not fail - - if opt_eol.is_some() { - indent(map( - separated_list1( - many1(parse_eol), - preceded(parse_block_indent, parse_statement), - ), - Body::new, - ))(input) - } else { - map(parse_statement, |stmt| Body::new(vec![stmt]))(input) - } -} - -pub fn parse_statement(input: Parser) -> Res { - alt(( - map(parse_if, Statement::new_if), - map(parse_for, Statement::new_for), - map(parse_assign, Statement::new_assign), - map(parse_expression, Statement::new_expression), - ))(input) -} - -pub fn parse_if(input: Parser) -> Res { - map( - tuple(( - parse_identity, - terminated(tag("if"), space1), - terminated(parse_expression, space0), - many1(line_ending), - parse_then, - parse_body, - opt(tuple((line_ending, parse_else))), - )), - |(node_id, if_, cond, _, _, body, else_)| { - If::new(node_id, cond, body, else_.map(|(_, else_)| Box::new(else_))) - }, - )(input.clone()) -} - -pub fn parse_then(input: Parser) -> Res { - // NOTE: This is a tweek for then block that are at indent 0 (i.e. in the test files) - let (input, indent) = if input.extra.first_indent.is_some() && input.extra.block_indent > 0 { - parse_block_indent(input)? - } else { - (input, 0) - }; - - if indent == input.extra.block_indent { - let (input, _) = terminated(tag("then"), space0)(input)?; - - Ok((input, ())) - } else { - Err(nom::Err::Error(ParseError::from_error_kind( - input, - ErrorKind::Tag, - ))) - } -} - -pub fn parse_else(input: Parser) -> Res { - // NOTE: This is a tweek for else block that are at indent 0 (i.e. in the test files) - let (input, indent) = if input.extra.first_indent.is_some() && input.extra.block_indent > 0 { - parse_block_indent(input)? - } else { - (input, 0) - }; - - if indent == input.extra.block_indent { - alt(( - map( - tuple(( - terminated(tag("else"), space1), - terminated(parse_if, space0), - )), - |(_, if_)| Else::If(if_), - ), - map( - tuple(( - terminated(tag("else"), space0), - terminated(parse_body, space0), - )), - |(_, body)| Else::Body(body), - ), - ))(input) - } else { - Err(nom::Err::Error(ParseError::from_error_kind( - input, - ErrorKind::Tag, - ))) - } -} - -pub fn parse_for(input: Parser) -> Res { - alt((map(parse_for_in, For::In), map(parse_while, For::While)))(input) -} - -pub fn parse_for_in(input: Parser) -> Res { - map( - tuple(( - terminated(tag("for"), space1), - terminated(parse_identifier, space0), - terminated(tag("in"), space0), - terminated(parse_expression, space0), - parse_body, - )), - |(_, var, _, expr, body)| ForIn::new(var, expr, body), - )(input) -} - -pub fn parse_while(input: Parser) -> Res { - map( - tuple(( - terminated(tag("while"), space1), - terminated(parse_expression, space0), - parse_body, - )), - |(_, cond, body)| While::new(cond, body), - )(input) -} - -pub fn parse_assign(input: Parser) -> Res { - map( - tuple(( - opt(terminated(tag("let"), space1)), - terminated(parse_assign_left_side, space0), - terminated(tag("="), space0), - terminated(parse_expression, space0), - )), - |(opt_let, var, _, expr)| Assign::new(var, expr, opt_let.is_some()), - )(input) -} - -pub fn parse_assign_left_side(input: Parser) -> Res { - let (input, expr) = parse_expression(input)?; - - let res = if expr.is_dot() { - AssignLeftSide::Dot(expr) - } else if expr.is_indice() { - AssignLeftSide::Indice(expr) - } else if expr.is_identifier() { - AssignLeftSide::Identifier(expr) - } else { - return Err(nom::Err::Error(ParseError::from_error_kind( - input, - ErrorKind::Tag, - ))); - }; - - Ok((input, res)) -} - -pub fn parse_expression(input: Parser) -> Res { - alt(( - map( - tuple(( - parse_unary, - delimited(space0, parse_operator, space0), - parse_expression, - )), - |(l, op, r)| Expression::new_binop(l, op, r), - ), - map(parse_unary, Expression::new_unary), - map(parse_struct_ctor, Expression::new_struct_ctor), - map(parse_native_operator, |(op, id1, id2)| { - Expression::new_native_operator(op, id1, id2) - }), - // TODO: Return - ))(input) -} - -pub fn parse_native_operator( - input: Parser, -) -> Res { - map( - tuple(( - preceded( - tag("~"), - alt(( - tag("IAdd"), - tag("ISub"), - tag("IMul"), - tag("IDiv"), - tag("FAdd"), - tag("FSub"), - tag("FMul"), - tag("FDiv"), - tag("IEq"), - tag("Igt"), - tag("Ige"), - tag("Ilt"), - tag("Ile"), - tag("FEq"), - tag("Fgt"), - tag("Fge"), - tag("Flt"), - tag("Fle"), - tag("BEq"), - tag("Len"), - )), - ), - preceded(space1, parse_identifier), - preceded(space1, parse_identifier), - )), - |(tag, id1, id2)| { - let (input, node_id) = new_identity(input.clone(), &tag); - ( - NativeOperator::new(node_id, NativeOperatorKind::from_str(tag.fragment())), - id1, - id2, - ) - }, - )(input.clone()) -} - -pub fn parse_struct_ctor(input: Parser) -> Res { - map( - tuple(( - // parse_identity, - terminated(parse_capitalized_identifier, line_ending), - indent(separated_list0( - line_ending, - preceded( - parse_block_indent, - tuple(( - terminated(parse_identifier, delimited(space0, tag(":"), space0)), - parse_expression, - )), - ), - )), - )), - |(name, decls)| StructCtor::new(name, decls.into_iter().collect()), - )(input) -} - -pub fn parse_unary(input: Parser) -> Res { - map(parse_primary, UnaryExpr::new_primary)(input) -} - -pub fn parse_primary(input: Parser) -> Res { - map( - tuple((parse_identity, parse_operand, many0(parse_secondary))), - |(node_id, op, secs)| PrimaryExpr::new(node_id, op, secs), - )(input) -} - -pub fn parse_secondary(input: Parser) -> Res { - alt(( - map(parse_indice, SecondaryExpr::Indice), - map(parse_dot, SecondaryExpr::Dot), - map(parse_arguments, SecondaryExpr::Arguments), - ))(input) -} - -pub fn parse_arguments(input: Parser) -> Res { - alt(( - map( - tuple(( - terminated(tag("("), space0), - separated_list0(tuple((space0, tag(","), space0)), parse_argument), - terminated(tag(")"), space0), - )), - |(_, args, _)| args, - ), - map( - tuple(( - space1, - separated_list1( - tuple((space0, terminated(tag(","), space0), space0)), - parse_argument, - ), - )), - |(_, args)| args, - ), - ))(input) -} - -pub fn parse_argument(input: Parser) -> Res { - map(parse_unary, Argument::new)(input) -} - -pub fn parse_indice(input: Parser) -> Res> { - map( - tuple(( - terminated(tag("["), space0), - terminated(parse_expression, space0), - terminated(tag("]"), space0), - )), - |(_, index, _)| Box::new(index), - )(input) -} - -pub fn parse_dot(input: Parser) -> Res { - map( - tuple(( - terminated(tag("."), space0), - terminated(parse_identifier, space0), - )), - |(_, ident)| ident, - )(input) -} - -pub fn parse_operand(input: Parser) -> Res { - alt(( - map(parse_literal, Operand::new_literal), - map(parse_identifier_path, Operand::new_identifier_path), - map( - delimited( - terminated(tag("("), space0), - parse_expression, - terminated(space0, tag(")")), - ), - Operand::new_expression, - ), - ))(input) -} - -pub fn parse_identifier_path(input: Parser) -> Res { - map( - separated_list1( - tag("::"), - alt(( - map(tuple((parse_identity, tag("(*)"))), |(node_id, _)| { - Identifier::new("(*)".to_string(), node_id) - }), - parse_identifier, - // map(parse_operator, |op| op.0), - )), - ), - IdentifierPath::new, - )(input) -} - -pub fn parse_capitalized_identifier(input: Parser) -> Res { - let (input, (node_id, txt)) = tuple((parse_identity, parse_capitalized_text))(input)?; - - Ok(( - input, - Identifier { - name: txt.to_string(), - node_id, - }, - )) -} - -pub fn parse_identifier(input: Parser) -> Res { - let (input, ident_parsed) = - recognize(many1(one_of("abcdefghijklmnopqrstuvwxyz_0123456789")))(input)?; - - let (input, node_id) = new_identity(input, &ident_parsed); - - Ok(( - input, - Identifier { - name: ident_parsed.to_string(), - node_id, - }, - )) -} - -pub fn parse_operator(input: Parser) -> Res { - let (input, parsed_op) = recognize(many1(one_of(LocatedSpan::new( - // We parse any accepted operators chars here, and then check if it is a valid operator later - crate::parser::accepted_operator_chars() - .iter() - .cloned() - .collect::() - .as_str(), - ))))(input)?; - - if parsed_op.to_string() == "=" { - return Err(Err::Error(error_position!(input, ErrorKind::Eof))); - } - - let (input, pos) = position(input)?; - - let (input, node_id) = new_identity(input, &pos); - - Ok(( - input, - Operator(Identifier { - name: parsed_op.to_string(), - node_id, - }), - )) -} - -pub fn parse_literal(input: Parser) -> Res { - alt(( - parse_bool, - parse_float, - parse_number, - parse_array, - parse_string, - ))(input) -} - -pub fn parse_string(input: Parser) -> Res { - map( - tuple(( - parse_identity, - terminated(tag("\""), space0), - recognize(take_while(|c: char| c != '"')), - terminated(tag("\""), space0), - )), - |(node_id, _, s, _)| Literal::new_string(String::from(*s.fragment()), node_id), - )(input) -} - -pub fn parse_array(input: Parser) -> Res { - map( - tuple(( - parse_identity, - terminated(tag("["), space0), - separated_list0( - tuple((space0, terminated(tag(","), space0), space0)), - parse_expression, - ), - terminated(tag("]"), space0), - )), - |(node_id, _, elements, _)| { - Literal::new_array(Array::new(elements.into_iter().collect()), node_id) - }, - )(input) -} - -pub fn parse_bool(input: Parser) -> Res { - let (input, bool_parsed) = alt((tag("true"), tag("false")))(input)?; - - let num: bool = bool_parsed - .parse() - .map_err(|_| Err::Error(make_error(input.clone(), ErrorKind::Alpha)))?; - - let (input, node_id) = new_identity(input, &bool_parsed); - - Ok((input, Literal::new_bool(num, node_id))) -} - -pub fn parse_float(input: Parser) -> Res { - let (input, float_parsed) = - recognize(tuple((parse_number, char('.'), opt(parse_number))))(input)?; - - let num: f64 = float_parsed - .parse() - .map_err(|_| Err::Error(make_error(input.clone(), ErrorKind::Digit)))?; - - let (input, node_id) = new_identity(input, &float_parsed); - - Ok((input, Literal::new_float(num, node_id))) -} - -pub fn parse_number(input: Parser) -> Res { - let (input, parsed) = take_while(is_digit)(input)?; - - let num: i64 = parsed - .parse() - .map_err(|_| Err::Error(make_error(input.clone(), ErrorKind::Digit)))?; - - let (input, node_id) = new_identity(input, &parsed); - - Ok((input, Literal::new_number(num, node_id))) -} - -// Types - -pub fn parse_signature(input: Parser) -> Res { - let (input, parsed) = tuple(( - parse_type, - many0(preceded(delimited(space0, tag("->"), space0), parse_type)), - ))(input)?; - - let mut types = vec![parsed.0]; - - types.extend(parsed.1); - - let ret = types.pop().unwrap(); - - Ok((input, FuncType::new(types, ret))) -} - -pub fn parse_type(input: Parser) -> Res { - let (input, ty) = alt(( - map( - terminated( - one_of("abcdefghijklmnopqrstuvwxyz"), - peek(alt((space1, line_ending, eof))), - ), - |c| Type::ForAll(String::from(c)), - ), - map(delimited(tag("["), parse_type, tag("]")), |t| { - Type::Primitive(PrimitiveType::Array( - Box::new(t), - 0, // FIXME - )) - }), - map( - alt(( - map(tag("Bool"), |_| PrimitiveType::Bool), - map(tag("Int64"), |_| PrimitiveType::Int64), - map(tag("Float64"), |_| PrimitiveType::Float64), - map(tag("String"), |_| PrimitiveType::String), - )), - |t| Type::from(t), - ), - map(parse_struct_type, Type::Struct), - map(parse_capitalized_text, Type::Trait), - ))(input)?; - - Ok((input, ty)) -} - -pub fn parse_struct_type(input: Parser) -> Res { - let (input, name) = parse_capitalized_text(input)?; - - let ty = if let Some(struct_t) = input.extra.structs.get(&name) { - struct_t.as_struct_type() - } else { - return Err(nom::Err::Error(ParseError::from_error_kind( - input, - ErrorKind::Tag, - ))); - }; - - Ok((input, ty)) -} - -pub fn parse_capitalized_text(input: Parser) -> Res { - let (input, parsed) = tuple((satisfy(char::is_uppercase), alphanumeric0))(input)?; - - let txt = - format!("{}", parsed.0) + &String::from_utf8(parsed.1.bytes().collect::>()).unwrap(); - - Ok((input, txt)) -} - -// Helpers - -fn is_digit(c: char) -> bool { - c.is_numeric() -} - -fn new_identity<'a>(mut input: Parser<'a>, parsed: &Parser<'a>) -> (Parser<'a>, NodeId) { - let node_id = input.extra.new_identity(Span::from(parsed.clone())); - - (input, node_id) -} - -fn parse_identity(input: Parser) -> Res { - let (input, pos) = position(input)?; - - let (input, node_id) = new_identity(input, &pos); - - Ok((input, node_id)) -} -/* -fn parse_identity2<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> Res, O, E> -where - F: nom::Parser, O, E>, -{ - move |mut input: Parser<'a>| { - let (input, pos) = position(input)?; - - let (mut input, output) = parser.parse(input)?; - - let (input, node_id) = new_identity(input, &output); - - Ok(()) - } -} */ - -pub fn allowed_operator_chars(input: Parser) -> Res { - let (input, c) = one_of(LocatedSpan::new( - crate::parser::accepted_operator_chars() - .iter() - .map(|c| c.to_string()) - .collect::>() - .join("") - .as_str(), - ))(input)?; - - Ok((input, c.to_string())) -} diff --git a/src/lib/parser2/tests.rs b/src/lib/parser2/tests.rs deleted file mode 100644 index e95ca5ef..00000000 --- a/src/lib/parser2/tests.rs +++ /dev/null @@ -1,903 +0,0 @@ -use nom::Finish; - -use super::*; - -#[cfg(test)] -mod parse_literal { - use super::*; - - #[test] - fn bool() { - let input = Parser::new_extra("true", ParserCtx::new(PathBuf::new())); - - let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); - - assert!(matches!(num_parsed.kind, LiteralKind::Bool(true))); - } - - #[test] - fn number() { - let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); - - let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); - - assert!(matches!(num_parsed.kind, LiteralKind::Number(42))); - } - - #[test] - fn float() { - let input = Parser::new_extra("42.42", ParserCtx::new(PathBuf::new())); - - let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); - - assert!(matches!(num_parsed.kind, LiteralKind::Float(f) if f == 42.42)); - } -} - -#[cfg(test)] -mod parse_bool { - use super::*; - - #[test] - fn r#true() { - let input = Parser::new_extra("true", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_bool(input).finish().unwrap(); - - assert!(matches!(parsed.kind, LiteralKind::Bool(true))); - } - - #[test] - fn r#false() { - let input = Parser::new_extra("false", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_bool(input).finish().unwrap(); - - assert!(matches!(parsed.kind, LiteralKind::Bool(false))); - } - - #[test] - fn invalid() { - let input = Parser::new_extra("atrue", ParserCtx::new(PathBuf::new())); - - assert!(parse_bool(input).finish().is_err()); - } -} - -#[cfg(test)] -mod parse_float { - use super::*; - - #[test] - fn valid_with_last_part() { - let input = Parser::new_extra("42.42", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_float(input).finish().unwrap(); - - assert!(matches!(parsed.kind, LiteralKind::Float(f) if f == 42.42)); - } - - #[test] - fn valid_no_last_part() { - let input = Parser::new_extra("42.", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_float(input).finish().unwrap(); - - assert!(matches!(parsed.kind, LiteralKind::Float(f) if f == 42.0)); - } - - #[test] - fn invalid() { - let input = Parser::new_extra("a42.", ParserCtx::new(PathBuf::new())); - - assert!(parse_float(input).finish().is_err()); - } -} - -#[cfg(test)] -mod parse_number { - use super::*; - - #[test] - fn valid() { - let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_number(input).finish().unwrap(); - - assert!(matches!(parsed.kind, LiteralKind::Number(42))); - } - - #[test] - fn invalid() { - let input = Parser::new_extra("a42", ParserCtx::new(PathBuf::new())); - - assert!(parse_number(input).finish().is_err()); - } -} - -#[cfg(test)] -mod parse_signature { - use super::*; - - #[test] - fn valid_1_arg() { - let input = Parser::new_extra("Int64", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_signature(input).finish().unwrap(); - - assert_eq!(parsed.arguments, vec![]); - assert_eq!(parsed.ret, Box::new(Type::int64())); - } - - #[test] - fn valid_2_arg() { - let input = Parser::new_extra("Int64 -> Int64", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_signature(input).finish().unwrap(); - - assert_eq!(parsed.arguments, vec![Type::int64()]); - assert_eq!(parsed.ret, Box::new(Type::int64())); - } -} - -#[cfg(test)] -mod parse_type { - use super::*; - - #[test] - fn valid() { - let input = Parser::new_extra("Int64", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_type(input).finish().unwrap(); - - assert_eq!(parsed, Type::int64()); - } - - #[test] - fn valid_for_all() { - let input = Parser::new_extra("a", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_type(input).finish().unwrap(); - - assert_eq!(parsed, Type::forall("a")); - } - - #[test] - fn invalid() { - let input = Parser::new_extra("int64", ParserCtx::new(PathBuf::new())); - - assert!(parse_type(input).finish().is_err()); - } -} - -#[cfg(test)] -mod parse_infix_op { - use super::*; - - #[test] - fn valid() { - let input = Parser::new_extra("infix + 5", ParserCtx::new(PathBuf::new())); - - let (rest, parsed) = parse_infix(input).finish().unwrap(); - - assert!(matches!(parsed, TopLevel::Infix(_op, 5))); - - let operators = HashMap::from([("+".to_string(), 5)]); - assert_eq!(rest.extra.operators_list, operators); - } -} - -#[cfg(test)] -mod parse_operator { - use super::*; - - #[test] - fn valid() { - let operators = HashMap::from([("+".to_string(), 5)]); - - let input = Parser::new_extra( - "+", - ParserCtx::new_with_operators(PathBuf::new(), operators), - ); - - let (_rest, parsed) = parse_operator(input).finish().unwrap(); - - assert_eq!( - parsed, - Operator(Identifier { - name: String::from("+"), - node_id: 0, - }) - ); - } -} - -#[cfg(test)] -mod parse_identifier { - use super::*; - - #[test] - fn valid() { - let input = Parser::new_extra("foo", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_identifier(input).finish().unwrap(); - - assert_eq!( - parsed, - Identifier { - name: String::from("foo"), - node_id: 0, - } - ); - } -} - -#[cfg(test)] -mod parse_identifier_path { - use super::*; - - #[test] - fn valid() { - let input = Parser::new_extra("foo::bar", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_identifier_path(input).finish().unwrap(); - - assert_eq!( - parsed, - IdentifierPath { - path: vec![ - Identifier { - name: String::from("foo"), - node_id: 0, - }, - Identifier { - name: String::from("bar"), - node_id: 0, - }, - ], - } - ); - } -} - -#[cfg(test)] -mod parse_operand { - use super::*; - - #[test] - fn valid_literal() { - let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_operand(input).finish().unwrap(); - - assert!(matches!( - parsed, - Operand::Literal(Literal { - kind: LiteralKind::Number(42), - node_id: 0, - }) - )); - } - - #[test] - fn valid_identifier_path() { - let input = Parser::new_extra("foo::bar", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_operand(input).finish().unwrap(); - - assert!(matches!( - parsed, - Operand::Identifier(IdentifierPath { path: _ }) - )); - } - - #[test] - fn valid_expression() { - let input = Parser::new_extra("(3)", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_operand(input).finish().unwrap(); - - assert!(matches!(parsed, Operand::Expression(_expr))); - } -} - -#[cfg(test)] -mod parse_expression { - use super::*; - - #[test] - fn valid_unary() { - let input = Parser::new_extra("3", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_expression(input).finish().unwrap(); - - assert!(matches!(parsed, Expression::UnaryExpr(_))); - } - - #[test] - fn valid_binary() { - let operators = HashMap::from([("+".to_string(), 5)]); - - let input = Parser::new_extra( - "3 + 4", - ParserCtx::new_with_operators(PathBuf::new(), operators), - ); - - let (_rest, parsed) = parse_expression(input).finish().unwrap(); - - assert!(matches!(parsed, Expression::BinopExpr(_, _, _))); - } -} -#[cfg(test)] -mod parse_primary { - use super::*; - - mod arguments { - use super::*; - - mod parenthesis { - use super::*; - - #[test] - fn valid_no_args() { - let input = Parser::new_extra("foo()", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_primary(input).finish().unwrap(); - - let secondaries = parsed.secondaries.unwrap(); - assert_eq!(secondaries.len(), 1); - - let args = &secondaries[0]; - - match args { - SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 0), - _ => panic!("expected Arguments"), - } - } - - #[test] - fn valid_one_arg() { - let input = Parser::new_extra("foo(2)", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_primary(input).finish().unwrap(); - - let secondaries = parsed.secondaries.unwrap(); - assert_eq!(secondaries.len(), 1); - - let args = &secondaries[0]; - - match args { - SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 1), - _ => panic!("expected Arguments"), - } - } - - #[test] - fn valid_two_args() { - let input = Parser::new_extra("foo(2, 3)", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_primary(input).finish().unwrap(); - - let secondaries = parsed.secondaries.unwrap(); - assert_eq!(secondaries.len(), 1); - - let args = &secondaries[0]; - - match args { - SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 2), - _ => panic!("expected Arguments"), - } - } - } - - mod no_parenthesis { - use super::*; - - #[test] - fn valid_one_arg() { - let input = Parser::new_extra("foo 2", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_primary(input).finish().unwrap(); - - let secondaries = parsed.secondaries.unwrap(); - assert_eq!(secondaries.len(), 1); - - let args = &secondaries[0]; - - match args { - SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 1), - _ => panic!("expected Arguments"), - } - } - - #[test] - fn valid_two_args() { - let input = Parser::new_extra("foo 2, 3", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_primary(input).finish().unwrap(); - - let secondaries = parsed.secondaries.unwrap(); - assert_eq!(secondaries.len(), 1); - - let args = &secondaries[0]; - - match args { - SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 2), - _ => panic!("expected Arguments"), - } - } - } - } - - #[test] - fn valid_indice() { - let input = Parser::new_extra("foo[3]", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_primary(input).finish().unwrap(); - - let secondaries = parsed.secondaries.unwrap(); - assert_eq!(secondaries.len(), 1); - - let args = &secondaries[0]; - - match args { - SecondaryExpr::Indice(expr) => {} - _ => panic!("expected indice"), - } - } - - #[test] - fn valid_dot() { - let input = Parser::new_extra("foo.toto", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_primary(input).finish().unwrap(); - - let secondaries = parsed.secondaries.unwrap(); - assert_eq!(secondaries.len(), 1); - - let args = &secondaries[0]; - - match args { - SecondaryExpr::Dot(expr) => {} - _ => panic!("expected dot"), - } - } - - #[test] - fn valid_mixed() { - let input = Parser::new_extra("foo.toto()[a]", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_primary(input).finish().unwrap(); - - let secondaries = parsed.secondaries.unwrap(); - - assert_eq!(secondaries.len(), 3); - } -} - -#[cfg(test)] -mod parse_fn_decl { - use super::*; - - #[test] - fn valid_no_args() { - let input = Parser::new_extra("toto =\n 2\n", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_fn(input).finish().unwrap(); - - let expected = FunctionDecl { - name: Identifier { - name: String::from("toto"), - node_id: 0, - }, - body: Body::new(vec![Statement::Expression(Box::new( - Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { - op: Operand::Literal(Literal { - kind: LiteralKind::Number(2), - node_id: 0, - }), - node_id: 0, - secondaries: None, - })), - ))]), - arguments: vec![], - signature: FuncType { - ret: Box::new(Type::forall("a")), - arguments: vec![], - }, - node_id: 0, - }; - - assert_eq!(parsed.name, expected.name); - assert_eq!(parsed.arguments, expected.arguments); - assert_eq!(parsed.signature, expected.signature); - } - - #[test] - fn valid_2_args() { - let operators = HashMap::from([("+".to_string(), 5)]); - - let input = Parser::new_extra( - "toto a b =\n a + b", - ParserCtx::new_with_operators(PathBuf::new(), operators), - ); - - let (_rest, parsed) = parse_fn(input).finish().unwrap(); - - let expected = FunctionDecl { - name: Identifier { - name: String::from("toto"), - node_id: 0, - }, - arguments: vec![ - Identifier { - name: String::from("a"), - node_id: 0, - }, - Identifier { - name: String::from("b"), - node_id: 0, - }, - ], - node_id: 0, - body: Body { - stmts: vec![Statement::Expression(Box::new(Expression::BinopExpr( - UnaryExpr::PrimaryExpr(PrimaryExpr { - op: Operand::Identifier(IdentifierPath { - path: vec![Identifier { - name: String::from("a"), - node_id: 0, - }], - }), - node_id: 0, - secondaries: None, - }), - Operator(Identifier { - name: String::from("+"), - node_id: 0, - }), - Box::new(Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { - op: Operand::Identifier(IdentifierPath { - path: vec![Identifier { - name: String::from("b"), - node_id: 0, - }], - }), - node_id: 0, - secondaries: None, - }))), - )))], - }, - signature: FuncType { - ret: Box::new(Type::forall("c")), - arguments: vec![Type::forall("a"), Type::forall("b")], - }, - }; - - assert_eq!(parsed.name, expected.name); - assert_eq!(parsed.arguments, expected.arguments); - // assert_eq!(parsed.body, expected.body); - assert_eq!(parsed.signature, expected.signature); - } - - #[test] - fn valid_multiline() { - let operators = HashMap::from([("+".to_string(), 5)]); - - let input = Parser::new_extra( - "toto a b =\n a + b\n a + b", - ParserCtx::new_with_operators(PathBuf::new(), operators), - ); - - let (rest, _parsed) = parse_fn(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } - - #[test] - fn valid_one_line() { - let operators = HashMap::from([("+".to_string(), 5)]); - - let input = Parser::new_extra( - "toto a b = a + b", - ParserCtx::new_with_operators(PathBuf::new(), operators), - ); - - let (rest, _parsed) = parse_fn(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } -} - -#[cfg(test)] -mod parse_prototype { - use super::*; - - #[test] - fn valid() { - let input = Parser::new_extra("toto :: Int64 -> Int64", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_prototype(input).finish().unwrap(); - - let expected = Prototype { - name: Identifier { - name: String::from("toto"), - node_id: 0, - }, - signature: FuncType { - ret: Box::new(Type::int64()), - arguments: vec![Type::int64()], - }, - node_id: 0, - }; - - assert_eq!(parsed.name, expected.name); - } -} - -#[cfg(test)] -mod parse_use { - use super::*; - - #[test] - fn valid() { - let input = Parser::new_extra("use foo", ParserCtx::new(PathBuf::new())); - - let (_rest, parsed) = parse_use(input).finish().unwrap(); - - assert_eq!( - parsed.path, - IdentifierPath { - path: vec![Identifier { - name: String::from("foo"), - node_id: 0, - }], - } - ); - } -} - -#[cfg(test)] -mod parse_if { - use super::*; - - #[test] - fn valid_if() { - let input = Parser::new_extra("if a\nthen b", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_if(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } - - #[test] - fn valid_if_else() { - let input = Parser::new_extra("if a\nthen b\nelse c", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_if(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } - - #[test] - fn valid_if_else_if() { - let input = Parser::new_extra( - "if a\nthen b\nelse if false\nthen c", - ParserCtx::new(PathBuf::new()), - ); - - let (rest, _parsed) = parse_if(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } - - #[test] - fn valid_if_else_if_else() { - let input = Parser::new_extra( - "if a\nthen b\nelse if true\nthen c\nelse d", - ParserCtx::new(PathBuf::new()), - ); - - let (rest, _parsed) = parse_if(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } - - #[test] - fn valid_multiline_if_else() { - let input = Parser::new_extra("if a\nthen\n b\nelse\n d", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_if(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } -} - -#[cfg(test)] -mod parse_for { - use super::*; - - #[test] - fn valid_for_in() { - let input = Parser::new_extra("for x in a\n b", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_for(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } - - #[test] - fn valid_while() { - let input = Parser::new_extra("while a\n b = 2", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_for(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } -} - -#[cfg(test)] -mod parse_assign { - use super::*; - - #[test] - fn valid_assign() { - let input = Parser::new_extra("let a = 2", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_assign(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } - - #[test] - fn valid_reassign_ident() { - let input = Parser::new_extra("a = 2", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_assign(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } - - #[test] - fn valid_reassign_dot() { - let input = Parser::new_extra("a.b = 2", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_assign(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } - - #[test] - fn valid_reassign_indice() { - let input = Parser::new_extra("a[2] = 2", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_assign(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } -} - -#[cfg(test)] -mod parse_struct_decl { - use super::*; - - #[test] - fn valid_struct_decl() { - let input = Parser::new_extra("struct Foo", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_struct_decl(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } - - #[test] - fn valid_struct_decl_with_fields() { - let input = Parser::new_extra( - "struct Foo\n a :: Int64\n b :: Float64", - ParserCtx::new(PathBuf::new()), - ); - - let (rest, _parsed) = parse_struct_decl(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } -} - -#[cfg(test)] -mod parse_struct_ctor { - use super::*; - - #[test] - fn valid_struct_ctor() { - let input = Parser::new_extra("Foo\n", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_struct_ctor(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } - - #[test] - fn valid_struct_ctor_with_fields() { - let input = Parser::new_extra("Foo\n a: 2\n b: 3.0", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_struct_ctor(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } -} - -#[cfg(test)] -mod parse_trait { - use super::*; - - #[test] - fn valid_trait() { - let input = Parser::new_extra( - "trait Foo\n a :: Int64 -> Int64\n b :: Float64 -> String", - ParserCtx::new(PathBuf::new()), - ); - - let (rest, _parsed) = parse_trait(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } -} - -#[cfg(test)] -mod parse_impl { - use super::*; - - #[test] - fn valid_impl() { - let input = Parser::new_extra( - "impl Foo\n a =\n 2\n b a =\n a", - ParserCtx::new(PathBuf::new()), - ); - - let (rest, _parsed) = parse_impl(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } -} - -#[cfg(test)] -mod parse_native_operator { - use super::*; - - #[test] - fn valid_native_operator() { - let input = Parser::new_extra("~IAdd a b", ParserCtx::new(PathBuf::new())); - - let (rest, (parsed, _, _)) = parse_native_operator(input).finish().unwrap(); - - assert_eq!(parsed.kind, NativeOperatorKind::IAdd); - } -} - -#[cfg(test)] -mod parse_array { - use super::*; - - #[test] - fn valid_array() { - let input = Parser::new_extra("[1, 2, 3]", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_array(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } -} - -#[cfg(test)] -mod parse_string { - use super::*; - - #[test] - fn valid_string() { - let input = Parser::new_extra("\"foo\"", ParserCtx::new(PathBuf::new())); - - let (rest, _parsed) = parse_string(input).finish().unwrap(); - - assert!(rest.fragment().is_empty()); - } -} diff --git a/src/lib/resolver/mod.rs b/src/lib/resolver/mod.rs index 69245d62..f0618ca9 100644 --- a/src/lib/resolver/mod.rs +++ b/src/lib/resolver/mod.rs @@ -1,8 +1,8 @@ use crate::{ - ast::{span_collector, visit::*, IdentifierPath, Root}, + ast::{tree::IdentifierPath, tree::Root, visit::*}, diagnostics::Diagnostic, helpers::scopes::Scopes, - parser::ParsingCtx, + parser::{ParsingCtx, Span}, }; mod resolution_map; @@ -11,6 +11,8 @@ mod unused_collector; use std::collections::HashMap; +use crate::parser::span::Span as OldSpan; + pub use resolution_map::*; pub use resolve_ctx::*; @@ -32,14 +34,12 @@ pub fn resolve(root: &mut Root, parsing_ctx: &mut ParsingCtx) -> Result<(), Diag let (mut unused_fns, unused_methods) = unused_collector::collect_unused(root); - root.spans = span_collector::collect_spans(root); - for unused_fn in &unused_fns { - let span = root.spans.get(unused_fn).unwrap(); + let span = parsing_ctx.identities.get(unused_fn).unwrap(); parsing_ctx .diagnostics - .push_warning(Diagnostic::new_unused_function(span.clone())); + .push_warning(Diagnostic::new_unused_function(OldSpan::from(span.clone()))); } unused_fns.extend(unused_methods); diff --git a/src/lib/resolver/resolution_map.rs b/src/lib/resolver/resolution_map.rs index 18d02b3b..adb652b1 100644 --- a/src/lib/resolver/resolution_map.rs +++ b/src/lib/resolver/resolution_map.rs @@ -1,6 +1,6 @@ use std::collections::HashMap; -use crate::{ast::NodeId, ast_lowering2::HirMap, hir::HirId}; +use crate::{ast::NodeId, ast_lowering::HirMap, hir::HirId}; #[derive(Clone, Default, Debug, Serialize, Deserialize)] pub struct ResolutionMap(HashMap) diff --git a/src/lib/resolver/resolve_ctx.rs b/src/lib/resolver/resolve_ctx.rs index 700dd856..0d205129 100644 --- a/src/lib/resolver/resolve_ctx.rs +++ b/src/lib/resolver/resolve_ctx.rs @@ -1,9 +1,10 @@ use std::collections::HashMap; use crate::{ - ast::{visit::*, *}, + ast::{tree::*, visit::*, NodeId}, diagnostics::Diagnostic, helpers::scopes::*, + parser::span2::Span as Span2, parser::ParsingCtx, resolver::ResolutionMap, }; @@ -11,15 +12,15 @@ use crate::{ #[derive(Debug)] pub struct ResolveCtx<'a> { pub parsing_ctx: &'a mut ParsingCtx, - pub scopes: HashMap>, // + pub scopes: HashMap>, // pub cur_scope: IdentifierPath, pub resolutions: ResolutionMap, } impl<'a> ResolveCtx<'a> { - pub fn add_to_current_scope(&mut self, name: String, ident: Identity) { + pub fn add_to_current_scope(&mut self, name: String, node_id: NodeId) { if let Some(ref mut scopes) = self.scopes.get_mut(&self.cur_scope) { - scopes.add(name, ident); + scopes.add(name, node_id); } } @@ -41,48 +42,52 @@ impl<'a> ResolveCtx<'a> { } } - pub fn get(&mut self, name: String) -> Option { + pub fn get(&mut self, name: String) -> Option { match self.scopes.get_mut(&self.cur_scope) { Some(ref mut scopes) => scopes.get(name), None => None, } } + + pub fn get_span2(&self, node_id: NodeId) -> Span2 { + self.parsing_ctx.identities.get(&node_id).unwrap().clone() + } } impl<'a> Visitor<'a> for ResolveCtx<'a> { fn visit_mod(&mut self, m: &'a Mod) { // We add every top level first for top in &m.top_levels { - match &top.kind { - TopLevelKind::Prototype(p) => { - self.add_to_current_scope((*p.name).clone(), p.identity.clone()); + match &top { + TopLevel::Prototype(p) => { + self.add_to_current_scope((*p.name).clone(), p.node_id); } - TopLevelKind::Use(_u) => (), - TopLevelKind::Trait(t) => { + TopLevel::Use(_u) => (), + TopLevel::Trait(t) => { for proto in &t.defs { - self.add_to_current_scope((*proto.name).clone(), proto.identity.clone()); + self.add_to_current_scope((*proto.name).clone(), proto.node_id); } } - TopLevelKind::Struct(s) => { - self.add_to_current_scope(s.name.get_name(), s.identity.clone()); + TopLevel::Struct(s) => { + self.add_to_current_scope(s.name.name.clone(), s.name.node_id); s.defs.iter().for_each(|p| { - self.add_to_current_scope((*p.name).clone(), p.identity.clone()); + self.add_to_current_scope((*p.name).clone(), p.node_id); }) } - TopLevelKind::Impl(i) => { + TopLevel::Impl(i) => { for proto in &i.defs { let mut proto = proto.clone(); proto.mangle(&i.types.iter().map(|t| t.get_name()).collect::>()); - self.add_to_current_scope((*proto.name).clone(), proto.identity.clone()); + self.add_to_current_scope((*proto.name).clone(), proto.node_id); } } - TopLevelKind::Mod(_, _m) => (), - TopLevelKind::Infix(_, _) => (), - TopLevelKind::Function(f) => { - self.add_to_current_scope((*f.name).clone(), f.identity.clone()); + TopLevel::Mod(_, _m) => (), + TopLevel::Infix(_, _) => (), + TopLevel::Function(f) => { + self.add_to_current_scope((*f.name).clone(), f.node_id); } } } @@ -98,7 +103,7 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { fn visit_for_in(&mut self, for_in: &'a ForIn) { self.visit_expression(&for_in.expr); - self.add_to_current_scope(for_in.value.name.clone(), for_in.value.identity.clone()); + self.add_to_current_scope(for_in.value.name.clone(), for_in.value.node_id); self.visit_body(&for_in.body); } @@ -108,16 +113,18 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { match &assign.name { AssignLeftSide::Identifier(id) => { + let ident = id.as_identifier().unwrap(); + if !assign.is_let { - if let Some(previous_assign_node_id) = self.get(id.name.clone()) { + if let Some(previous_assign_node_id) = self.get(ident.name.clone()) { self.resolutions - .insert(id.identity.node_id, previous_assign_node_id.node_id); + .insert(ident.node_id, previous_assign_node_id); } - self.visit_identifier(id) + self.visit_identifier(ident) } - self.add_to_current_scope(id.name.clone(), id.identity.clone()); + self.add_to_current_scope(ident.name.clone(), ident.node_id); } AssignLeftSide::Indice(expr) => self.visit_expression(expr), AssignLeftSide::Dot(expr) => self.visit_expression(expr), @@ -125,17 +132,17 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { } fn visit_top_level(&mut self, top: &'a TopLevel) { - match &top.kind { - TopLevelKind::Prototype(p) => self.visit_prototype(p), - TopLevelKind::Use(u) => { + match &top { + TopLevel::Prototype(p) => self.visit_prototype(p), + TopLevel::Use(u) => { self.visit_use(u); } - TopLevelKind::Infix(_, _) => (), - TopLevelKind::Trait(t) => self.visit_trait(t), - TopLevelKind::Impl(i) => self.visit_impl(i), - TopLevelKind::Struct(s) => self.visit_struct_decl(s), - TopLevelKind::Function(f) => self.visit_function_decl(f), - TopLevelKind::Mod(name, m) => { + TopLevel::Infix(_, _) => (), + TopLevel::Trait(t) => self.visit_trait(t), + TopLevel::Impl(i) => self.visit_impl(i), + TopLevel::Struct(s) => self.visit_struct_decl(s), + TopLevel::Function(f) => self.visit_function_decl(f), + TopLevel::Mod(name, m) => { let current_mod = self.cur_scope.clone(); self.new_mod(self.cur_scope.child(name.clone())); @@ -156,15 +163,17 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { } fn visit_struct_ctor(&mut self, s: &'a StructCtor) { - match self.get(s.name.get_name()) { - Some(pointed) => self.resolutions.insert(s.identity.node_id, pointed.node_id), + match self.get(s.name.name.clone()) { + Some(pointed) => self.resolutions.insert(s.name.node_id, pointed), None => self .parsing_ctx .diagnostics - .push_error(Diagnostic::new_unknown_identifier(s.identity.span.clone())), + .push_error(Diagnostic::new_unknown_identifier( + self.get_span2(s.name.node_id).into(), + )), }; - self.visit_type(&s.name); + self.visit_identifier(&s.name); walk_struct_ctor(self, s); } @@ -172,7 +181,13 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { fn visit_function_decl(&mut self, f: &'a FunctionDecl) { self.push_scope(); - walk_function_decl(self, f); + self.visit_identifier(&f.name); + + for arg in &f.arguments { + self.add_to_current_scope(arg.name.clone(), arg.node_id); + } + + self.visit_body(&f.body); self.pop_scope(); } @@ -202,7 +217,9 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { self.add_to_current_scope((*ident).name.clone(), pointed); } None => self.parsing_ctx.diagnostics.push_error( - Diagnostic::new_unknown_identifier(ident.identity.span.clone()), + Diagnostic::new_unknown_identifier( + self.get_span2(ident.node_id).into(), + ), ), }; } @@ -212,7 +229,7 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { .parsing_ctx .diagnostics .push_error(Diagnostic::new_module_not_found( - ident.identity.span.clone(), + self.get_span2(ident.node_id).into(), mod_path .path .iter() @@ -223,10 +240,10 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { }; } - fn visit_argument_decl(&mut self, arg: &'a ArgumentDecl) { - self.add_to_current_scope(arg.name.clone(), arg.identity.clone()); - } - + /* fn visit_argument_decl(&mut self, arg: &'a ArgumentDecl) { + self.add_to_current_scope(arg.name.clone(), arg.node_id); + } + */ fn visit_identifier_path(&mut self, path: &'a IdentifierPath) { let ident = path.last_segment_ref(); @@ -242,14 +259,12 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { match self.scopes.get(&mod_path) { Some(scopes) => match scopes.get((*ident).to_string()) { - Some(pointed) => self - .resolutions - .insert(ident.identity.node_id, pointed.node_id), + Some(pointed) => self.resolutions.insert(ident.node_id, pointed), None => { self.parsing_ctx .diagnostics .push_error(Diagnostic::new_unknown_identifier( - ident.identity.span.clone(), + self.get_span2(ident.node_id).into(), )) } }, @@ -259,7 +274,7 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { .parsing_ctx .diagnostics .push_error(Diagnostic::new_module_not_found( - ident.identity.span.clone(), + self.get_span2(ident.node_id).into(), mod_path .path .iter() @@ -272,13 +287,13 @@ impl<'a> Visitor<'a> for ResolveCtx<'a> { fn visit_identifier(&mut self, id: &'a Identifier) { match self.get((*id).to_string()) { - Some(pointed) => self - .resolutions - .insert(id.identity.node_id, pointed.node_id), + Some(pointed) => self.resolutions.insert(id.node_id, pointed), None => self .parsing_ctx .diagnostics - .push_error(Diagnostic::new_unknown_identifier(id.identity.span.clone())), + .push_error(Diagnostic::new_unknown_identifier( + self.get_span2(id.node_id).into(), + )), }; } } diff --git a/src/lib/resolver/unused_collector.rs b/src/lib/resolver/unused_collector.rs index fa856025..2b59d353 100644 --- a/src/lib/resolver/unused_collector.rs +++ b/src/lib/resolver/unused_collector.rs @@ -1,6 +1,9 @@ use std::collections::HashMap; -use crate::{ast::*, resolver::ResolutionMap}; +use crate::{ + ast::{tree::*, visit::*, NodeId}, + resolver::ResolutionMap, +}; #[derive(Debug, Default)] pub struct UnusedCollector { @@ -37,23 +40,23 @@ impl<'a> Visitor<'a> for UnusedCollector { // We add every top level first for top in &m.top_levels { - match &top.kind { - TopLevelKind::Prototype(_p) => {} - TopLevelKind::Use(_u) => (), - TopLevelKind::Trait(t) => { + match &top { + TopLevel::Prototype(_p) => {} + TopLevel::Use(_u) => (), + TopLevel::Trait(t) => { for f in &t.defs { - self.method_list.insert(f.identity.node_id, false); + self.method_list.insert(f.node_id, false); } } - TopLevelKind::Impl(_i) => {} - TopLevelKind::Struct(_s) => {} - TopLevelKind::Mod(_, _m) => (), - TopLevelKind::Infix(_, _) => (), - TopLevelKind::Function(f) => { - self.fn_list.insert(f.identity.node_id, false); + TopLevel::Impl(_i) => {} + TopLevel::Struct(_s) => {} + TopLevel::Mod(_, _m) => (), + TopLevel::Infix(_, _) => (), + TopLevel::Function(f) => { + self.fn_list.insert(f.node_id, false); if f.name.name == *"main" { - self.fn_list.insert(f.identity.node_id, true); + self.fn_list.insert(f.node_id, true); } } } @@ -63,18 +66,18 @@ impl<'a> Visitor<'a> for UnusedCollector { } fn visit_top_level(&mut self, top_level: &'a TopLevel) { - match &top_level.kind { - TopLevelKind::Prototype(p) => self.visit_prototype(p), - TopLevelKind::Use(_u) => (), - TopLevelKind::Trait(t) => self.visit_trait(t), - TopLevelKind::Impl(i) => self.visit_impl(i), - TopLevelKind::Struct(i) => self.visit_struct_decl(i), - TopLevelKind::Mod(name, m) => { + match &top_level { + TopLevel::Prototype(p) => self.visit_prototype(p), + TopLevel::Use(_u) => (), + TopLevel::Trait(t) => self.visit_trait(t), + TopLevel::Impl(i) => self.visit_impl(i), + TopLevel::Struct(i) => self.visit_struct_decl(i), + TopLevel::Mod(name, m) => { self.visit_identifier(name); self.visit_mod(m); } - TopLevelKind::Function(f) => self.visit_function_decl(f), - TopLevelKind::Infix(_ident, _) => (), + TopLevel::Function(f) => self.visit_function_decl(f), + TopLevel::Infix(_ident, _) => (), }; } @@ -83,13 +86,13 @@ impl<'a> Visitor<'a> for UnusedCollector { } fn visit_function_decl(&mut self, f: &'a FunctionDecl) { - walk_list!(self, visit_argument_decl, &f.arguments); + walk_list!(self, visit_identifier, &f.arguments); self.visit_body(&f.body); } fn visit_identifier(&mut self, id: &'a Identifier) { - if let Some(reso) = self.resolutions.get_recur(&id.identity.node_id) { + if let Some(reso) = self.resolutions.get_recur(&id.node_id) { if let Some(used) = self.fn_list.get_mut(&reso) { *used = true; } else if let Some(used) = self.method_list.get_mut(&reso) { diff --git a/src/lib/resolver2/mod.rs b/src/lib/resolver2/mod.rs deleted file mode 100644 index 39eb19a1..00000000 --- a/src/lib/resolver2/mod.rs +++ /dev/null @@ -1,46 +0,0 @@ -use crate::{ - ast::{tree2::IdentifierPath, tree2::Root, visit2::*}, - diagnostics::Diagnostic, - helpers::scopes::Scopes, - parser::{ParsingCtx, Span}, -}; - -mod resolution_map; -mod resolve_ctx; -mod unused_collector; - -use std::collections::HashMap; - -pub use resolution_map::*; -pub use resolve_ctx::*; - -pub fn resolve(root: &mut Root, parsing_ctx: &mut ParsingCtx) -> Result<(), Diagnostic> { - let mut scopes = HashMap::new(); - - scopes.insert(IdentifierPath::new_root(), Scopes::new()); - - let mut ctx = ResolveCtx { - parsing_ctx, - scopes, - cur_scope: IdentifierPath::new_root(), - resolutions: ResolutionMap::default(), - }; - - ctx.visit_root(root); - - root.resolutions = ctx.resolutions; - - let (mut unused_fns, unused_methods) = unused_collector::collect_unused(root); - - for unused_fn in &unused_fns { - let span = parsing_ctx.identities.get(unused_fn).unwrap(); - - parsing_ctx - .diagnostics - .push_warning(Diagnostic::new_unused_function(Span::from(span.clone()))); - } - - unused_fns.extend(unused_methods); - - parsing_ctx.return_if_error() -} diff --git a/src/lib/resolver2/resolution_map.rs b/src/lib/resolver2/resolution_map.rs deleted file mode 100644 index 18d02b3b..00000000 --- a/src/lib/resolver2/resolution_map.rs +++ /dev/null @@ -1,57 +0,0 @@ -use std::collections::HashMap; - -use crate::{ast::NodeId, ast_lowering2::HirMap, hir::HirId}; - -#[derive(Clone, Default, Debug, Serialize, Deserialize)] -pub struct ResolutionMap(HashMap) -where - T: Eq + Clone + std::hash::Hash + Default; - -impl ResolutionMap { - pub fn insert(&mut self, pointer_id: T, pointee_id: T) { - if self.0.insert(pointer_id, pointee_id).is_some() { - debug!("Overriding resolution"); - } - } - - pub fn get(&self, pointer_id: &T) -> Option { - self.0.get(pointer_id).cloned() - } - - pub fn get_recur(&self, pointer_id: &T) -> Option { - self.get(pointer_id).and_then(|pointee_id| { - if *pointer_id == pointee_id { - warn!("Resolution loop"); - - Some(pointee_id) - } else { - self.get_recur(&pointee_id).or(Some(pointee_id)) - } - }) - } - - pub fn get_map(&self) -> HashMap { - self.0.clone() - } - - #[allow(dead_code)] - pub fn clear(&mut self) { - self.0.clear() - } - - pub fn remove(&mut self, item: &T) { - self.0.remove(item); - } -} - -impl ResolutionMap { - pub fn lower_resolution_map(&self, hir_map: &HirMap) -> ResolutionMap { - ResolutionMap( - self.0 - .iter() - // FIXME: Code smell, we silently delete unknown references - .filter_map(|(k, v)| Some((hir_map.get_hir_id(*k)?, hir_map.get_hir_id(*v)?))) - .collect(), - ) - } -} diff --git a/src/lib/resolver2/resolve_ctx.rs b/src/lib/resolver2/resolve_ctx.rs deleted file mode 100644 index 7660b1ea..00000000 --- a/src/lib/resolver2/resolve_ctx.rs +++ /dev/null @@ -1,299 +0,0 @@ -use std::collections::HashMap; - -use crate::{ - ast::{tree2::*, visit2::*, NodeId}, - diagnostics::Diagnostic, - helpers::scopes::*, - parser::span2::Span as Span2, - parser::ParsingCtx, - resolver2::ResolutionMap, -}; - -#[derive(Debug)] -pub struct ResolveCtx<'a> { - pub parsing_ctx: &'a mut ParsingCtx, - pub scopes: HashMap>, // - pub cur_scope: IdentifierPath, - pub resolutions: ResolutionMap, -} - -impl<'a> ResolveCtx<'a> { - pub fn add_to_current_scope(&mut self, name: String, node_id: NodeId) { - if let Some(ref mut scopes) = self.scopes.get_mut(&self.cur_scope) { - scopes.add(name, node_id); - } - } - - pub fn new_mod(&mut self, name: IdentifierPath) { - self.scopes.insert(name.clone(), Scopes::new()); - - self.cur_scope = name; - } - - pub fn push_scope(&mut self) { - if let Some(ref mut scopes) = self.scopes.get_mut(&self.cur_scope) { - scopes.push(); - } - } - - pub fn pop_scope(&mut self) { - if let Some(ref mut scopes) = self.scopes.get_mut(&self.cur_scope) { - scopes.pop(); - } - } - - pub fn get(&mut self, name: String) -> Option { - match self.scopes.get_mut(&self.cur_scope) { - Some(ref mut scopes) => scopes.get(name), - None => None, - } - } - - pub fn get_span2(&self, node_id: NodeId) -> Span2 { - self.parsing_ctx.identities.get(&node_id).unwrap().clone() - } -} - -impl<'a> Visitor<'a> for ResolveCtx<'a> { - fn visit_mod(&mut self, m: &'a Mod) { - // We add every top level first - for top in &m.top_levels { - match &top { - TopLevel::Prototype(p) => { - self.add_to_current_scope((*p.name).clone(), p.node_id); - } - TopLevel::Use(_u) => (), - TopLevel::Trait(t) => { - for proto in &t.defs { - self.add_to_current_scope((*proto.name).clone(), proto.node_id); - } - } - TopLevel::Struct(s) => { - self.add_to_current_scope(s.name.name.clone(), s.name.node_id); - - s.defs.iter().for_each(|p| { - self.add_to_current_scope((*p.name).clone(), p.node_id); - }) - } - TopLevel::Impl(i) => { - for proto in &i.defs { - let mut proto = proto.clone(); - - proto.mangle(&i.types.iter().map(|t| t.get_name()).collect::>()); - - self.add_to_current_scope((*proto.name).clone(), proto.node_id); - } - } - TopLevel::Mod(_, _m) => (), - TopLevel::Infix(_, _) => (), - TopLevel::Function(f) => { - self.add_to_current_scope((*f.name).clone(), f.node_id); - } - } - } - - walk_list!(self, visit_top_level, &m.top_levels); - } - - // fn visit_for(&mut self, for_loop: &'a For) { - // self.visit_expression(&for_loop.expr); - // self.visit_body(&for_loop.body); - // } - - fn visit_for_in(&mut self, for_in: &'a ForIn) { - self.visit_expression(&for_in.expr); - - self.add_to_current_scope(for_in.value.name.clone(), for_in.value.node_id); - - self.visit_body(&for_in.body); - } - - fn visit_assign(&mut self, assign: &'a Assign) { - self.visit_expression(&assign.value); - - match &assign.name { - AssignLeftSide::Identifier(id) => { - let ident = id.as_identifier().unwrap(); - - if !assign.is_let { - if let Some(previous_assign_node_id) = self.get(ident.name.clone()) { - self.resolutions - .insert(ident.node_id, previous_assign_node_id); - } - - self.visit_identifier(ident) - } - - self.add_to_current_scope(ident.name.clone(), ident.node_id); - } - AssignLeftSide::Indice(expr) => self.visit_expression(expr), - AssignLeftSide::Dot(expr) => self.visit_expression(expr), - } - } - - fn visit_top_level(&mut self, top: &'a TopLevel) { - match &top { - TopLevel::Prototype(p) => self.visit_prototype(p), - TopLevel::Use(u) => { - self.visit_use(u); - } - TopLevel::Infix(_, _) => (), - TopLevel::Trait(t) => self.visit_trait(t), - TopLevel::Impl(i) => self.visit_impl(i), - TopLevel::Struct(s) => self.visit_struct_decl(s), - TopLevel::Function(f) => self.visit_function_decl(f), - TopLevel::Mod(name, m) => { - let current_mod = self.cur_scope.clone(); - - self.new_mod(self.cur_scope.child(name.clone())); - - self.visit_mod(m); - - self.cur_scope = current_mod; - } - }; - } - - fn visit_struct_decl(&mut self, s: &'a StructDecl) { - self.push_scope(); - - walk_struct_decl(self, s); - - self.pop_scope() - } - - fn visit_struct_ctor(&mut self, s: &'a StructCtor) { - match self.get(s.name.name.clone()) { - Some(pointed) => self.resolutions.insert(s.name.node_id, pointed), - None => self - .parsing_ctx - .diagnostics - .push_error(Diagnostic::new_unknown_identifier( - self.get_span2(s.name.node_id).into(), - )), - }; - - self.visit_identifier(&s.name); - - walk_struct_ctor(self, s); - } - - fn visit_function_decl(&mut self, f: &'a FunctionDecl) { - self.push_scope(); - - self.visit_identifier(&f.name); - - for arg in &f.arguments { - self.add_to_current_scope(arg.name.clone(), arg.node_id); - } - - self.visit_body(&f.body); - - self.pop_scope(); - } - - fn visit_use(&mut self, r#use: &'a Use) { - let ident = r#use.path.last_segment_ref(); - - if r#use.path.path.len() == 1 { - panic!("Unimplemented"); - } - - let mut mod_path = r#use.path.parent().prepend_mod(self.cur_scope.clone()); - - mod_path.resolve_supers(); - - match self.scopes.get(&mod_path) { - Some(scopes) => { - if ident.name == "(*)" { - let scope = scopes.scopes.get(0).unwrap(); - - for (k, v) in &scope.items.clone() { - self.add_to_current_scope(k.clone(), v.clone()); - } - } else { - match scopes.get((*ident).to_string()) { - Some(pointed) => { - self.add_to_current_scope((*ident).name.clone(), pointed); - } - None => self.parsing_ctx.diagnostics.push_error( - Diagnostic::new_unknown_identifier( - self.get_span2(ident.node_id).into(), - ), - ), - }; - } - } - - None => self - .parsing_ctx - .diagnostics - .push_error(Diagnostic::new_module_not_found( - self.get_span2(ident.node_id).into(), - mod_path - .path - .iter() - .map(|p| p.name.clone()) - .collect::>() - .join("/"), - )), - }; - } - - /* fn visit_argument_decl(&mut self, arg: &'a ArgumentDecl) { - self.add_to_current_scope(arg.name.clone(), arg.node_id); - } - */ - fn visit_identifier_path(&mut self, path: &'a IdentifierPath) { - let ident = path.last_segment_ref(); - - if path.path.len() == 1 { - self.visit_identifier(ident); - - return; - } - - let mut mod_path = path.parent().prepend_mod(self.cur_scope.clone()); - - mod_path.resolve_supers(); - - match self.scopes.get(&mod_path) { - Some(scopes) => match scopes.get((*ident).to_string()) { - Some(pointed) => self.resolutions.insert(ident.node_id, pointed), - None => { - self.parsing_ctx - .diagnostics - .push_error(Diagnostic::new_unknown_identifier( - self.get_span2(ident.node_id).into(), - )) - } - }, - - // TODO: change to Unknown Mod diagnostic - None => self - .parsing_ctx - .diagnostics - .push_error(Diagnostic::new_module_not_found( - self.get_span2(ident.node_id).into(), - mod_path - .path - .iter() - .map(|p| p.name.clone()) - .collect::>() - .join("/"), - )), - }; - } - - fn visit_identifier(&mut self, id: &'a Identifier) { - match self.get((*id).to_string()) { - Some(pointed) => self.resolutions.insert(id.node_id, pointed), - None => self - .parsing_ctx - .diagnostics - .push_error(Diagnostic::new_unknown_identifier( - self.get_span2(id.node_id).into(), - )), - }; - } -} diff --git a/src/lib/resolver2/unused_collector.rs b/src/lib/resolver2/unused_collector.rs deleted file mode 100644 index 54e1a2e4..00000000 --- a/src/lib/resolver2/unused_collector.rs +++ /dev/null @@ -1,111 +0,0 @@ -use std::collections::HashMap; - -use crate::{ - ast::{tree2::*, visit2::*, NodeId}, - resolver2::ResolutionMap, -}; - -#[derive(Debug, Default)] -pub struct UnusedCollector { - resolutions: ResolutionMap, - fn_list: HashMap, - method_list: HashMap, -} - -impl UnusedCollector { - pub fn new(resolutions: ResolutionMap) -> Self { - Self { - resolutions, - ..Default::default() - } - } - - // (fns, methods) - pub fn take_unused(self) -> (Vec, Vec) { - ( - self.fn_list - .into_iter() - .filter_map(|(id, used)| if !used { Some(id) } else { None }) - .collect(), - self.method_list - .into_iter() - .filter_map(|(id, used)| if !used { Some(id) } else { None }) - .collect(), - ) - } -} - -impl<'a> Visitor<'a> for UnusedCollector { - fn visit_mod(&mut self, m: &'a Mod) { - // We add every top level first - - for top in &m.top_levels { - match &top { - TopLevel::Prototype(_p) => {} - TopLevel::Use(_u) => (), - TopLevel::Trait(t) => { - for f in &t.defs { - self.method_list.insert(f.node_id, false); - } - } - TopLevel::Impl(_i) => {} - TopLevel::Struct(_s) => {} - TopLevel::Mod(_, _m) => (), - TopLevel::Infix(_, _) => (), - TopLevel::Function(f) => { - self.fn_list.insert(f.node_id, false); - - if f.name.name == *"main" { - self.fn_list.insert(f.node_id, true); - } - } - } - } - - walk_list!(self, visit_top_level, &m.top_levels); - } - - fn visit_top_level(&mut self, top_level: &'a TopLevel) { - match &top_level { - TopLevel::Prototype(p) => self.visit_prototype(p), - TopLevel::Use(_u) => (), - TopLevel::Trait(t) => self.visit_trait(t), - TopLevel::Impl(i) => self.visit_impl(i), - TopLevel::Struct(i) => self.visit_struct_decl(i), - TopLevel::Mod(name, m) => { - self.visit_identifier(name); - self.visit_mod(m); - } - TopLevel::Function(f) => self.visit_function_decl(f), - TopLevel::Infix(_ident, _) => (), - }; - } - - fn visit_prototype(&mut self, prototype: &'a Prototype) { - self.visit_func_type(&prototype.signature); - } - - fn visit_function_decl(&mut self, f: &'a FunctionDecl) { - walk_list!(self, visit_identifier, &f.arguments); - - self.visit_body(&f.body); - } - - fn visit_identifier(&mut self, id: &'a Identifier) { - if let Some(reso) = self.resolutions.get_recur(&id.node_id) { - if let Some(used) = self.fn_list.get_mut(&reso) { - *used = true; - } else if let Some(used) = self.method_list.get_mut(&reso) { - *used = true; - } - } - } -} - -pub fn collect_unused(root: &Root) -> (Vec, Vec) { - let mut unused_collector = UnusedCollector::new(root.resolutions.clone()); - - unused_collector.visit_root(root); - - unused_collector.take_unused() -} diff --git a/src/lib/rock.rs b/src/lib/rock.rs index 144b3459..30d019d7 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -23,14 +23,14 @@ mod ast; mod infer; // mod ast_lowering; -mod ast_lowering2; +mod ast_lowering; mod codegen; pub mod diagnostics; mod hir; mod parser; -mod parser2; +// mod parser2; mod resolver; -mod resolver2; +// mod resolver2; mod tests; mod ty; @@ -40,9 +40,7 @@ use diagnostics::Diagnostic; pub use helpers::config::Config; use nom::Finish; use nom_locate::LocatedSpan; -use parser::{ParsingCtx, SourceFile}; - -use crate::parser2::ParserCtx; +use parser::{ParserCtx, ParsingCtx, SourceFile}; pub fn compile_file(in_name: String, config: &Config) -> Result<(), Diagnostic> { let mut source_file = SourceFile::from_file(in_name)?; @@ -78,7 +76,7 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { @@ -94,11 +92,11 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result Resolving"); - resolver2::resolve(&mut ast, parsing_ctx)?; + resolver::resolve(&mut ast, parsing_ctx)?; // Lowering to HIR debug!(" -> Lowering to HIR"); - let mut hir = ast_lowering2::lower_crate(&ast); + let mut hir = ast_lowering::lower_crate(&ast); // Debug hir if parsing_ctx.config.show_hir { diff --git a/src/lib/ty/struct_type.rs b/src/lib/ty/struct_type.rs index 08769eed..2e7ebdcf 100644 --- a/src/lib/ty/struct_type.rs +++ b/src/lib/ty/struct_type.rs @@ -29,14 +29,14 @@ impl fmt::Debug for StructType { } } -impl From<&ast::tree2::StructDecl> for StructType { - fn from(s: &ast::tree2::StructDecl) -> Self { +impl From<&ast::tree::StructDecl> for StructType { + fn from(s: &ast::tree::StructDecl) -> Self { s.into() } } -impl From for StructType { - fn from(s: ast::tree2::StructDecl) -> Self { +impl From for StructType { + fn from(s: ast::tree::StructDecl) -> Self { StructType { name: s.name.to_string(), defs: s @@ -57,19 +57,19 @@ impl From for StructType { } } -/* impl From<&ast::tree2::StructCtor> for StructType { - fn from(s: &ast::tree2::StructCtor) -> Self { +/* impl From<&ast::tree::StructCtor> for StructType { + fn from(s: &ast::tree::StructCtor) -> Self { s.into() } } -impl From for StructType { - fn from(s: ast::tree2::StructCtor) -> Self { +impl From for StructType { + fn from(s: ast::tree::StructCtor) -> Self { s.ty.clone() } } */ -impl From<&ast::StructDecl> for StructType { +/* impl From<&ast::StructDecl> for StructType { fn from(s: &ast::StructDecl) -> Self { s.into() } @@ -95,7 +95,7 @@ impl From for StructType { .collect(), } } -} +} */ impl From for StructType { fn from(s: hir::StructDecl) -> Self { From 544a53f48c6603b13d8ab12e46ce0ef9b2fbcdf7 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 18:10:15 +0200 Subject: [PATCH 70/74] Parser cleanup in rock.rs --- src/lib/parser/mod.rs | 124 +++++++++++++++++++++++------------------- src/lib/rock.rs | 67 ++--------------------- 2 files changed, 73 insertions(+), 118 deletions(-) diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index 21088883..d17a9003 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -1,25 +1,31 @@ -use std::collections::{BTreeMap, HashMap}; - -use std::path::PathBuf; - -use nom::branch::alt; -use nom::bytes::complete::{tag, take_while}; -use nom::character::complete::{alphanumeric0, char, line_ending, one_of, satisfy, space0, space1}; -use nom::combinator::{eof, map, opt, peek, recognize}; -use nom::error::{make_error, ErrorKind, VerboseError}; -use nom::error_position; -use nom::multi::{many0, many1, separated_list0, separated_list1}; -use nom::sequence::{delimited, preceded, terminated, tuple}; -use nom::{error::ParseError, Err, IResult}; - -// use crate::ast::identity2::Identity; -use crate::ast::tree::*; -use crate::ast::NodeId; -/* use crate::parser::span2::Span; -use crate::parser::SourceFile; */ -use crate::ty::{FuncType, PrimitiveType, StructType, Type}; +use std::{ + collections::{BTreeMap, HashMap}, + path::PathBuf, +}; + +use nom::{ + branch::alt, + bytes::complete::{tag, take_while}, + character::complete::{alphanumeric0, char, line_ending, one_of, satisfy, space0, space1}, + combinator::{eof, map, opt, peek, recognize}, + error::{make_error, ErrorKind, ParseError, VerboseError}, + error_position, + multi::{many0, many1, separated_list0, separated_list1}, + sequence::{delimited, preceded, terminated, tuple}, + Err, IResult, +}; use nom_locate::{position, LocatedSpan}; + +use crate::{ + ast::{ + tree::{self, *}, + NodeId, + }, + diagnostics::Diagnostic, + ty::{FuncType, PrimitiveType, StructType, Type}, +}; + pub type Parser<'a> = LocatedSpan<&'a str, ParserCtx>; type Res = IResult>; @@ -116,10 +122,6 @@ impl ParserCtx { &self.cur_file_path } - // pub fn identities(&self) -> &Vec { - // &self.identities - // } - pub fn operators(&self) -> &HashMap { &self.operators_list } @@ -128,24 +130,8 @@ impl ParserCtx { self.operators_list.insert(op, prec); } - /* pub fn resolve_new_mod(&mut self, name: &str) -> Self { - let mut new = Self::new( - self.cur_file_path - .parent() - .unwrap() - .join(name.to_owned() + ".rk"), - ); - - new.identities = self.identities.clone(); - - new - } */ - pub fn identities(&self) -> BTreeMap { self.identities.clone() - /* .iter() - .map(|identity| (identity.node_id, identity.clone())) - .collect() */ } pub fn operators_list(&self) -> HashMap { @@ -741,7 +727,6 @@ pub fn parse_identifier_path(input: Parser) -> Res { Identifier::new("(*)".to_string(), node_id) }), parse_identifier, - // map(parse_operator, |op| op.0), )), ), IdentifierPath::new, @@ -969,21 +954,6 @@ fn parse_identity(input: Parser) -> Res { Ok((input, node_id)) } -/* -fn parse_identity2<'a, O, E, F>(mut parser: F) -> impl FnMut(Parser<'a>) -> Res, O, E> -where - F: nom::Parser, O, E>, -{ - move |mut input: Parser<'a>| { - let (input, pos) = position(input)?; - - let (mut input, output) = parser.parse(input)?; - - let (input, node_id) = new_identity(input, &output); - - Ok(()) - } -} */ pub fn allowed_operator_chars(input: Parser) -> Res { let (input, c) = one_of(LocatedSpan::new( @@ -997,3 +967,45 @@ pub fn allowed_operator_chars(input: Parser) -> Res { Ok((input, c.to_string())) } + +pub fn parse(parsing_ctx: &mut ParsingCtx) -> Result { + use nom::Finish; + use nom_locate::LocatedSpan; + + let content = &parsing_ctx.get_current_file().content; + + let parser = LocatedSpan::new_extra( + content.as_str(), + ParserCtx::new(parsing_ctx.get_current_file().file_path.clone()), + ); + + let ast = parse_root(parser).finish(); + + let mut ast = match ast { + Ok((ctx, mut ast)) => { + parsing_ctx.identities = ctx.extra.identities(); + parsing_ctx.files = ctx.extra.files(); + + ast.operators_list = ctx.extra.operators_list(); + ast.spans = ctx.extra.identities().into_iter().collect(); + + // Debug ast + if parsing_ctx.config.show_ast { + ast.print(); + } + + Ok(ast) + } + Err(e) => { + let diagnostic = Diagnostic::from(e); + + parsing_ctx.diagnostics.push_error(diagnostic.clone()); + + Err(diagnostic) + } + }?; + + parsing_ctx.return_if_error()?; + + Ok(ast) +} diff --git a/src/lib/rock.rs b/src/lib/rock.rs index 30d019d7..b81288bd 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -3,7 +3,6 @@ #[macro_use] extern crate serde_derive; -#[macro_use] extern crate bitflags; #[macro_use] @@ -22,15 +21,12 @@ mod ast; #[macro_use] mod infer; -// mod ast_lowering; mod ast_lowering; mod codegen; pub mod diagnostics; mod hir; mod parser; -// mod parser2; mod resolver; -// mod resolver2; mod tests; mod ty; @@ -38,8 +34,6 @@ use ast::ast_print::AstPrintContext; use codegen::interpret; use diagnostics::Diagnostic; pub use helpers::config::Config; -use nom::Finish; -use nom_locate::LocatedSpan; use parser::{ParserCtx, ParsingCtx, SourceFile}; pub fn compile_file(in_name: String, config: &Config) -> Result<(), Diagnostic> { @@ -69,60 +63,9 @@ pub fn compile_str(input: &SourceFile, config: &Config) -> Result<(), Diagnostic } pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result { - let content = &parsing_ctx.get_current_file().content; - - let parser = LocatedSpan::new_extra( - content.as_str(), - ParserCtx::new(parsing_ctx.get_current_file().file_path.clone()), - ); - - let ast_test = parser::parse_root(parser).finish(); - - let hir = match ast_test { - Ok((ctx, mut ast)) => { - parsing_ctx.identities = ctx.extra.identities(); - parsing_ctx.files = ctx.extra.files(); - - ast.operators_list = ctx.extra.operators_list(); - ast.spans = ctx.extra.identities().into_iter().collect(); - - // Debug ast - if parsing_ctx.config.show_ast { - ast.print(); - } - - debug!(" -> Resolving"); - resolver::resolve(&mut ast, parsing_ctx)?; - - // Lowering to HIR - debug!(" -> Lowering to HIR"); - let mut hir = ast_lowering::lower_crate(&ast); - - // Debug hir - if parsing_ctx.config.show_hir { - hir.print(); - } - - // Infer Hir - debug!(" -> Infer HIR"); - let new_hir = infer::infer(&mut hir, parsing_ctx, config)?; - - Ok(new_hir) - } - Err(e) => { - let diagnostic = Diagnostic::from(e); - - parsing_ctx.diagnostics.push_error(diagnostic.clone()); - - Err(diagnostic) - } - }?; - - parsing_ctx.return_if_error()?; - - /* // Text to Ast + // Text to Ast debug!(" -> Parsing"); - let mut ast = parser::parse_root(parsing_ctx)?; + let mut ast = parser::parse(parsing_ctx)?; // Name resolving debug!(" -> Resolving"); @@ -134,10 +77,9 @@ pub fn parse_str(parsing_ctx: &mut ParsingCtx, config: &Config) -> Result Infer HIR"); - let new_hir = infer::infer(&mut hir, parsing_ctx, config)?; */ + let new_hir = infer::infer(&mut hir, parsing_ctx, config)?; - // Ok(new_hir) - Ok(hir) + Ok(new_hir) } pub fn generate_ir(hir: hir::Root, config: &Config) -> Result<(), Diagnostic> { @@ -147,6 +89,7 @@ pub fn generate_ir(hir: hir::Root, config: &Config) -> Result<(), Diagnostic> { Ok(()) } + mod test { use super::*; use crate::{parser::SourceFile, Config}; From 86218a7662da446405911bdccbce7bc92d054e2c Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 18:18:18 +0200 Subject: [PATCH 71/74] Cleanup warnings --- src/lib/ast/tree.rs | 74 +-- src/lib/diagnostics/diagnostic.rs | 2 +- src/lib/parser/mod.rs | 23 +- src/lib/parser/parsing_context.rs | 4 +- src/lib/parser/tests.rs | 903 ++++++++++++++++++++++++++++++ src/lib/resolver/mod.rs | 2 +- src/lib/rock.rs | 5 +- 7 files changed, 921 insertions(+), 92 deletions(-) create mode 100644 src/lib/parser/tests.rs diff --git a/src/lib/ast/tree.rs b/src/lib/ast/tree.rs index d3da3e84..66bd6a7c 100644 --- a/src/lib/ast/tree.rs +++ b/src/lib/ast/tree.rs @@ -5,7 +5,7 @@ use crate::{ helpers::*, parser::span2::Span, resolver::ResolutionMap, - ty::{FuncType, StructType, Type}, + ty::{FuncType, Type}, }; use super::{ast_print::AstPrintContext, visit::Visitor}; @@ -19,17 +19,6 @@ pub struct Root { pub spans: HashMap, } -/* impl FromStr for Root { - type Err = String; - - fn from_str(s: &str) -> Result { - match parse_root(create_parser(s)).finish() { - Ok((_, root)) => Ok(root), - Err(e) => Err(format!("{:?}", e)), - } - } -} - */ impl Root { pub fn new(r#mod: Mod) -> Self { Self { @@ -49,7 +38,6 @@ impl Root { #[derive(Debug, Clone)] pub struct Mod { pub top_levels: Vec, - // pub node_id: NodeId, // TODO: setup a ModId } impl Mod { @@ -58,12 +46,6 @@ impl Mod { } } -// #[derive(Debug, Clone)] -// pub struct TopLevel { -// pub kind: TopLevelKind, -// // pub node_id: NodeId, -// } - #[derive(Debug, Clone)] pub enum TopLevel { Prototype(Prototype), @@ -188,7 +170,6 @@ impl Use { #[derive(Debug, Clone)] pub struct FunctionDecl { pub name: Identifier, - // pub mangled_name: Option, pub arguments: Vec, pub body: Body, pub node_id: NodeId, @@ -301,12 +282,6 @@ impl Identifier { } } -// impl Identifier { -// pub fn new(name: ) { - -// } -// } - impl PartialEq for Identifier { fn eq(&self, other: &Self) -> bool { self.name == other.name @@ -329,14 +304,6 @@ impl std::ops::Deref for Identifier { generate_has_name!(Identifier); -pub type ArgumentsDecl = Vec; - -// #[derive(Debug, Clone)] -// pub struct ArgumentDecl { -// pub name: String, -// pub node_id: NodeId, -// } - #[derive(Debug, Clone)] pub struct Body { pub stmts: Vec, @@ -348,11 +315,6 @@ impl Body { } } -// #[derive(Debug, Clone)] -// pub struct Statement { -// pub kind: Box, -// } - #[derive(Debug, Clone)] pub enum Statement { Expression(Box), @@ -426,16 +388,6 @@ impl AssignLeftSide { } } } -// impl AssignLeftSide { -// pub fn get_node_id(&self) -> NodeId { -// use AssignLeftSide::*; - -// match self { -// Identifier(id) => id.node_id.node_id, -// Indice(expr) => expr., -// } -// } -// } #[derive(Debug, Clone)] pub struct Assign { @@ -484,11 +436,6 @@ pub enum Else { Body(Body), } -// #[derive(Debug, Clone)] -// pub struct Expression { -// pub kind: ExpressionKind, -// } - impl Expression { #[allow(dead_code)] pub fn is_literal(&self) -> bool { @@ -555,20 +502,6 @@ impl Expression { _ => None, } } - - // #[allow(dead_code)] - // pub fn create_2_args_func_call(op: Operand, arg1: UnaryExpr, arg2: UnaryExpr) -> Expression { - // Expression { - // kind: Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { - // node_id: node_id::new_placeholder(), - // op, - // secondaries: Some(vec![SecondaryExpr::Arguments(vec![ - // Argument { arg: arg1 }, - // Argument { arg: arg2 }, - // ])]), - // })), - // } - // } } #[derive(Debug, Clone)] @@ -698,11 +631,6 @@ impl PrimaryExpr { } } -// #[derive(Debug, Clone)] -// pub struct Operand { -// pub kind: Operand, -// } - #[derive(Debug, Clone)] pub enum Operand { Literal(Literal), diff --git a/src/lib/diagnostics/diagnostic.rs b/src/lib/diagnostics/diagnostic.rs index 8f827dca..a7bc2b12 100644 --- a/src/lib/diagnostics/diagnostic.rs +++ b/src/lib/diagnostics/diagnostic.rs @@ -287,7 +287,7 @@ impl<'a> From> for Diagnostic { impl<'a> From>> for Diagnostic { fn from(err: VerboseError>) -> Self { - let (input, kind) = err.errors.into_iter().next().unwrap(); + let (input, _kind) = err.errors.into_iter().next().unwrap(); let span2 = Span2::from(input); let span = Span::from(span2); diff --git a/src/lib/parser/mod.rs b/src/lib/parser/mod.rs index d17a9003..4ae51779 100644 --- a/src/lib/parser/mod.rs +++ b/src/lib/parser/mod.rs @@ -143,14 +143,14 @@ impl ParserCtx { } } -pub fn create_parser(s: &str) -> Parser<'_> { +/* pub fn create_parser(s: &str) -> Parser<'_> { LocatedSpan::new_extra(s, ParserCtx::new(PathBuf::from(""))) } - -pub fn create_parser_with_filename(s: &str, path: PathBuf) -> Parser<'_> { + */ +/* pub fn create_parser_with_filename(s: &str, path: PathBuf) -> Parser<'_> { LocatedSpan::new_extra(s, ParserCtx::new(path)) } - + */ pub fn parse_root(input: Parser) -> Res { // TODO: move eof check in parse_mod map(terminated(parse_mod, eof), Root::new)(input) @@ -207,7 +207,7 @@ pub fn parse_mod_decl(input: Parser) -> Res { let content = std::fs::read_to_string(&new_ctx.current_file_path()).unwrap(); - let mut new_parser = Parser::new_extra(&content, new_ctx); + let new_parser = Parser::new_extra(&content, new_ctx); use nom::Finish; // FIXME: Errors are swallowed here @@ -271,7 +271,7 @@ pub fn parse_struct_decl(input: Parser) -> Res { preceded(parse_block_indent, parse_prototype), )), )), - |(tag, name, _, defs)| StructDecl::new(name, defs), + |(_tag, name, _, defs)| StructDecl::new(name, defs), )(input)?; let struct_t: StructType = struct_decl.clone().into(); @@ -295,7 +295,7 @@ pub fn parse_use(input: Parser) -> Res { } pub fn parse_infix(input: Parser) -> Res { - let (mut input, (parsed_op, pred)) = preceded( + let (input, (parsed_op, pred)) = preceded( terminated(tag("infix"), space1), tuple(( terminated(many1(allowed_operator_chars), space1), @@ -399,7 +399,7 @@ pub fn parse_block_indent(input: Parser) -> Res { } } -pub fn parse_body(mut input: Parser) -> Res { +pub fn parse_body(input: Parser) -> Res { let (input, opt_eol) = opt(line_ending)(input)?; // NOTE: should not fail if opt_eol.is_some() { @@ -435,7 +435,7 @@ pub fn parse_if(input: Parser) -> Res { parse_body, opt(tuple((line_ending, parse_else))), )), - |(node_id, if_, cond, _, _, body, else_)| { + |(node_id, _if_, cond, _, _, body, else_)| { If::new(node_id, cond, body, else_.map(|(_, else_)| Box::new(else_))) }, )(input.clone()) @@ -606,7 +606,7 @@ pub fn parse_native_operator( preceded(space1, parse_identifier), )), |(tag, id1, id2)| { - let (input, node_id) = new_identity(input.clone(), &tag); + let (_input, node_id) = new_identity(input.clone(), &tag); ( NativeOperator::new(node_id, NativeOperatorKind::from_str(tag.fragment())), id1, @@ -970,7 +970,6 @@ pub fn allowed_operator_chars(input: Parser) -> Res { pub fn parse(parsing_ctx: &mut ParsingCtx) -> Result { use nom::Finish; - use nom_locate::LocatedSpan; let content = &parsing_ctx.get_current_file().content; @@ -981,7 +980,7 @@ pub fn parse(parsing_ctx: &mut ParsingCtx) -> Result { let ast = parse_root(parser).finish(); - let mut ast = match ast { + let ast = match ast { Ok((ctx, mut ast)) => { parsing_ctx.identities = ctx.extra.identities(); parsing_ctx.files = ctx.extra.files(); diff --git a/src/lib/parser/parsing_context.rs b/src/lib/parser/parsing_context.rs index 17c93471..8acbd28b 100644 --- a/src/lib/parser/parsing_context.rs +++ b/src/lib/parser/parsing_context.rs @@ -6,7 +6,7 @@ use std::{ use colored::*; use crate::{ - ast::{ast_print::AstPrintContext, tree, Identifier, NodeId, Root}, + ast::{ast_print::AstPrintContext, tree, Identifier, NodeId}, diagnostics::{Diagnostic, DiagnosticType, Diagnostics}, parser::span2::Span, Config, @@ -127,7 +127,7 @@ impl ParsingCtx { Ok(()) } - pub fn new_span(&self, start: usize, end: usize) -> Span { + pub fn new_span(&self, start: usize, _end: usize) -> Span { Span { file_path: self.get_current_file().file_path, offset: start, diff --git a/src/lib/parser/tests.rs b/src/lib/parser/tests.rs new file mode 100644 index 00000000..9406086e --- /dev/null +++ b/src/lib/parser/tests.rs @@ -0,0 +1,903 @@ +use nom::Finish; + +use super::*; + +#[cfg(test)] +mod parse_literal { + use super::*; + + #[test] + fn bool() { + let input = Parser::new_extra("true", ParserCtx::new(PathBuf::new())); + + let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); + + assert!(matches!(num_parsed.kind, LiteralKind::Bool(true))); + } + + #[test] + fn number() { + let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); + + let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); + + assert!(matches!(num_parsed.kind, LiteralKind::Number(42))); + } + + #[test] + fn float() { + let input = Parser::new_extra("42.42", ParserCtx::new(PathBuf::new())); + + let (_rest, num_parsed) = parse_literal(input).finish().unwrap(); + + assert!(matches!(num_parsed.kind, LiteralKind::Float(f) if f == 42.42)); + } +} + +#[cfg(test)] +mod parse_bool { + use super::*; + + #[test] + fn r#true() { + let input = Parser::new_extra("true", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_bool(input).finish().unwrap(); + + assert!(matches!(parsed.kind, LiteralKind::Bool(true))); + } + + #[test] + fn r#false() { + let input = Parser::new_extra("false", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_bool(input).finish().unwrap(); + + assert!(matches!(parsed.kind, LiteralKind::Bool(false))); + } + + #[test] + fn invalid() { + let input = Parser::new_extra("atrue", ParserCtx::new(PathBuf::new())); + + assert!(parse_bool(input).finish().is_err()); + } +} + +#[cfg(test)] +mod parse_float { + use super::*; + + #[test] + fn valid_with_last_part() { + let input = Parser::new_extra("42.42", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_float(input).finish().unwrap(); + + assert!(matches!(parsed.kind, LiteralKind::Float(f) if f == 42.42)); + } + + #[test] + fn valid_no_last_part() { + let input = Parser::new_extra("42.", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_float(input).finish().unwrap(); + + assert!(matches!(parsed.kind, LiteralKind::Float(f) if f == 42.0)); + } + + #[test] + fn invalid() { + let input = Parser::new_extra("a42.", ParserCtx::new(PathBuf::new())); + + assert!(parse_float(input).finish().is_err()); + } +} + +#[cfg(test)] +mod parse_number { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_number(input).finish().unwrap(); + + assert!(matches!(parsed.kind, LiteralKind::Number(42))); + } + + #[test] + fn invalid() { + let input = Parser::new_extra("a42", ParserCtx::new(PathBuf::new())); + + assert!(parse_number(input).finish().is_err()); + } +} + +#[cfg(test)] +mod parse_signature { + use super::*; + + #[test] + fn valid_1_arg() { + let input = Parser::new_extra("Int64", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_signature(input).finish().unwrap(); + + assert_eq!(parsed.arguments, vec![]); + assert_eq!(parsed.ret, Box::new(Type::int64())); + } + + #[test] + fn valid_2_arg() { + let input = Parser::new_extra("Int64 -> Int64", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_signature(input).finish().unwrap(); + + assert_eq!(parsed.arguments, vec![Type::int64()]); + assert_eq!(parsed.ret, Box::new(Type::int64())); + } +} + +#[cfg(test)] +mod parse_type { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("Int64", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_type(input).finish().unwrap(); + + assert_eq!(parsed, Type::int64()); + } + + #[test] + fn valid_for_all() { + let input = Parser::new_extra("a", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_type(input).finish().unwrap(); + + assert_eq!(parsed, Type::forall("a")); + } + + #[test] + fn invalid() { + let input = Parser::new_extra("int64", ParserCtx::new(PathBuf::new())); + + assert!(parse_type(input).finish().is_err()); + } +} + +#[cfg(test)] +mod parse_infix_op { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("infix + 5", ParserCtx::new(PathBuf::new())); + + let (rest, parsed) = parse_infix(input).finish().unwrap(); + + assert!(matches!(parsed, TopLevel::Infix(_op, 5))); + + let operators = HashMap::from([("+".to_string(), 5)]); + assert_eq!(rest.extra.operators_list, operators); + } +} + +#[cfg(test)] +mod parse_operator { + use super::*; + + #[test] + fn valid() { + let operators = HashMap::from([("+".to_string(), 5)]); + + let input = Parser::new_extra( + "+", + ParserCtx::new_with_operators(PathBuf::new(), operators), + ); + + let (_rest, parsed) = parse_operator(input).finish().unwrap(); + + assert_eq!( + parsed, + Operator(Identifier { + name: String::from("+"), + node_id: 0, + }) + ); + } +} + +#[cfg(test)] +mod parse_identifier { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("foo", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_identifier(input).finish().unwrap(); + + assert_eq!( + parsed, + Identifier { + name: String::from("foo"), + node_id: 0, + } + ); + } +} + +#[cfg(test)] +mod parse_identifier_path { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("foo::bar", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_identifier_path(input).finish().unwrap(); + + assert_eq!( + parsed, + IdentifierPath { + path: vec![ + Identifier { + name: String::from("foo"), + node_id: 0, + }, + Identifier { + name: String::from("bar"), + node_id: 0, + }, + ], + } + ); + } +} + +#[cfg(test)] +mod parse_operand { + use super::*; + + #[test] + fn valid_literal() { + let input = Parser::new_extra("42", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_operand(input).finish().unwrap(); + + assert!(matches!( + parsed, + Operand::Literal(Literal { + kind: LiteralKind::Number(42), + node_id: 0, + }) + )); + } + + #[test] + fn valid_identifier_path() { + let input = Parser::new_extra("foo::bar", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_operand(input).finish().unwrap(); + + assert!(matches!( + parsed, + Operand::Identifier(IdentifierPath { path: _ }) + )); + } + + #[test] + fn valid_expression() { + let input = Parser::new_extra("(3)", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_operand(input).finish().unwrap(); + + assert!(matches!(parsed, Operand::Expression(_expr))); + } +} + +#[cfg(test)] +mod parse_expression { + use super::*; + + #[test] + fn valid_unary() { + let input = Parser::new_extra("3", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_expression(input).finish().unwrap(); + + assert!(matches!(parsed, Expression::UnaryExpr(_))); + } + + #[test] + fn valid_binary() { + let operators = HashMap::from([("+".to_string(), 5)]); + + let input = Parser::new_extra( + "3 + 4", + ParserCtx::new_with_operators(PathBuf::new(), operators), + ); + + let (_rest, parsed) = parse_expression(input).finish().unwrap(); + + assert!(matches!(parsed, Expression::BinopExpr(_, _, _))); + } +} +#[cfg(test)] +mod parse_primary { + use super::*; + + mod arguments { + use super::*; + + mod parenthesis { + use super::*; + + #[test] + fn valid_no_args() { + let input = Parser::new_extra("foo()", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 0), + _ => panic!("expected Arguments"), + } + } + + #[test] + fn valid_one_arg() { + let input = Parser::new_extra("foo(2)", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 1), + _ => panic!("expected Arguments"), + } + } + + #[test] + fn valid_two_args() { + let input = Parser::new_extra("foo(2, 3)", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 2), + _ => panic!("expected Arguments"), + } + } + } + + mod no_parenthesis { + use super::*; + + #[test] + fn valid_one_arg() { + let input = Parser::new_extra("foo 2", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 1), + _ => panic!("expected Arguments"), + } + } + + #[test] + fn valid_two_args() { + let input = Parser::new_extra("foo 2, 3", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Arguments(arr) => assert_eq!(arr.len(), 2), + _ => panic!("expected Arguments"), + } + } + } + } + + #[test] + fn valid_indice() { + let input = Parser::new_extra("foo[3]", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Indice(_expr) => {} + _ => panic!("expected indice"), + } + } + + #[test] + fn valid_dot() { + let input = Parser::new_extra("foo.toto", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + assert_eq!(secondaries.len(), 1); + + let args = &secondaries[0]; + + match args { + SecondaryExpr::Dot(_expr) => {} + _ => panic!("expected dot"), + } + } + + #[test] + fn valid_mixed() { + let input = Parser::new_extra("foo.toto()[a]", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_primary(input).finish().unwrap(); + + let secondaries = parsed.secondaries.unwrap(); + + assert_eq!(secondaries.len(), 3); + } +} + +#[cfg(test)] +mod parse_fn_decl { + use super::*; + + #[test] + fn valid_no_args() { + let input = Parser::new_extra("toto =\n 2\n", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_fn(input).finish().unwrap(); + + let expected = FunctionDecl { + name: Identifier { + name: String::from("toto"), + node_id: 0, + }, + body: Body::new(vec![Statement::Expression(Box::new( + Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { + op: Operand::Literal(Literal { + kind: LiteralKind::Number(2), + node_id: 0, + }), + node_id: 0, + secondaries: None, + })), + ))]), + arguments: vec![], + signature: FuncType { + ret: Box::new(Type::forall("a")), + arguments: vec![], + }, + node_id: 0, + }; + + assert_eq!(parsed.name, expected.name); + assert_eq!(parsed.arguments, expected.arguments); + assert_eq!(parsed.signature, expected.signature); + } + + #[test] + fn valid_2_args() { + let operators = HashMap::from([("+".to_string(), 5)]); + + let input = Parser::new_extra( + "toto a b =\n a + b", + ParserCtx::new_with_operators(PathBuf::new(), operators), + ); + + let (_rest, parsed) = parse_fn(input).finish().unwrap(); + + let expected = FunctionDecl { + name: Identifier { + name: String::from("toto"), + node_id: 0, + }, + arguments: vec![ + Identifier { + name: String::from("a"), + node_id: 0, + }, + Identifier { + name: String::from("b"), + node_id: 0, + }, + ], + node_id: 0, + body: Body { + stmts: vec![Statement::Expression(Box::new(Expression::BinopExpr( + UnaryExpr::PrimaryExpr(PrimaryExpr { + op: Operand::Identifier(IdentifierPath { + path: vec![Identifier { + name: String::from("a"), + node_id: 0, + }], + }), + node_id: 0, + secondaries: None, + }), + Operator(Identifier { + name: String::from("+"), + node_id: 0, + }), + Box::new(Expression::UnaryExpr(UnaryExpr::PrimaryExpr(PrimaryExpr { + op: Operand::Identifier(IdentifierPath { + path: vec![Identifier { + name: String::from("b"), + node_id: 0, + }], + }), + node_id: 0, + secondaries: None, + }))), + )))], + }, + signature: FuncType { + ret: Box::new(Type::forall("c")), + arguments: vec![Type::forall("a"), Type::forall("b")], + }, + }; + + assert_eq!(parsed.name, expected.name); + assert_eq!(parsed.arguments, expected.arguments); + // assert_eq!(parsed.body, expected.body); + assert_eq!(parsed.signature, expected.signature); + } + + #[test] + fn valid_multiline() { + let operators = HashMap::from([("+".to_string(), 5)]); + + let input = Parser::new_extra( + "toto a b =\n a + b\n a + b", + ParserCtx::new_with_operators(PathBuf::new(), operators), + ); + + let (rest, _parsed) = parse_fn(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_one_line() { + let operators = HashMap::from([("+".to_string(), 5)]); + + let input = Parser::new_extra( + "toto a b = a + b", + ParserCtx::new_with_operators(PathBuf::new(), operators), + ); + + let (rest, _parsed) = parse_fn(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} + +#[cfg(test)] +mod parse_prototype { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("toto :: Int64 -> Int64", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_prototype(input).finish().unwrap(); + + let expected = Prototype { + name: Identifier { + name: String::from("toto"), + node_id: 0, + }, + signature: FuncType { + ret: Box::new(Type::int64()), + arguments: vec![Type::int64()], + }, + node_id: 0, + }; + + assert_eq!(parsed.name, expected.name); + } +} + +#[cfg(test)] +mod parse_use { + use super::*; + + #[test] + fn valid() { + let input = Parser::new_extra("use foo", ParserCtx::new(PathBuf::new())); + + let (_rest, parsed) = parse_use(input).finish().unwrap(); + + assert_eq!( + parsed.path, + IdentifierPath { + path: vec![Identifier { + name: String::from("foo"), + node_id: 0, + }], + } + ); + } +} + +#[cfg(test)] +mod parse_if { + use super::*; + + #[test] + fn valid_if() { + let input = Parser::new_extra("if a\nthen b", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_if(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_if_else() { + let input = Parser::new_extra("if a\nthen b\nelse c", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_if(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_if_else_if() { + let input = Parser::new_extra( + "if a\nthen b\nelse if false\nthen c", + ParserCtx::new(PathBuf::new()), + ); + + let (rest, _parsed) = parse_if(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_if_else_if_else() { + let input = Parser::new_extra( + "if a\nthen b\nelse if true\nthen c\nelse d", + ParserCtx::new(PathBuf::new()), + ); + + let (rest, _parsed) = parse_if(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_multiline_if_else() { + let input = Parser::new_extra("if a\nthen\n b\nelse\n d", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_if(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} + +#[cfg(test)] +mod parse_for { + use super::*; + + #[test] + fn valid_for_in() { + let input = Parser::new_extra("for x in a\n b", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_for(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_while() { + let input = Parser::new_extra("while a\n b = 2", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_for(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} + +#[cfg(test)] +mod parse_assign { + use super::*; + + #[test] + fn valid_assign() { + let input = Parser::new_extra("let a = 2", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_assign(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_reassign_ident() { + let input = Parser::new_extra("a = 2", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_assign(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_reassign_dot() { + let input = Parser::new_extra("a.b = 2", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_assign(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_reassign_indice() { + let input = Parser::new_extra("a[2] = 2", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_assign(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} + +#[cfg(test)] +mod parse_struct_decl { + use super::*; + + #[test] + fn valid_struct_decl() { + let input = Parser::new_extra("struct Foo", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_struct_decl(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_struct_decl_with_fields() { + let input = Parser::new_extra( + "struct Foo\n a :: Int64\n b :: Float64", + ParserCtx::new(PathBuf::new()), + ); + + let (rest, _parsed) = parse_struct_decl(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} + +#[cfg(test)] +mod parse_struct_ctor { + use super::*; + + #[test] + fn valid_struct_ctor() { + let input = Parser::new_extra("Foo\n", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_struct_ctor(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } + + #[test] + fn valid_struct_ctor_with_fields() { + let input = Parser::new_extra("Foo\n a: 2\n b: 3.0", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_struct_ctor(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} + +#[cfg(test)] +mod parse_trait { + use super::*; + + #[test] + fn valid_trait() { + let input = Parser::new_extra( + "trait Foo\n a :: Int64 -> Int64\n b :: Float64 -> String", + ParserCtx::new(PathBuf::new()), + ); + + let (rest, _parsed) = parse_trait(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} + +#[cfg(test)] +mod parse_impl { + use super::*; + + #[test] + fn valid_impl() { + let input = Parser::new_extra( + "impl Foo\n a =\n 2\n b a =\n a", + ParserCtx::new(PathBuf::new()), + ); + + let (rest, _parsed) = parse_impl(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} + +#[cfg(test)] +mod parse_native_operator { + use super::*; + + #[test] + fn valid_native_operator() { + let input = Parser::new_extra("~IAdd a b", ParserCtx::new(PathBuf::new())); + + let (_rest, (parsed, _, _)) = parse_native_operator(input).finish().unwrap(); + + assert_eq!(parsed.kind, NativeOperatorKind::IAdd); + } +} + +#[cfg(test)] +mod parse_array { + use super::*; + + #[test] + fn valid_array() { + let input = Parser::new_extra("[1, 2, 3]", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_array(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} + +#[cfg(test)] +mod parse_string { + use super::*; + + #[test] + fn valid_string() { + let input = Parser::new_extra("\"foo\"", ParserCtx::new(PathBuf::new())); + + let (rest, _parsed) = parse_string(input).finish().unwrap(); + + assert!(rest.fragment().is_empty()); + } +} diff --git a/src/lib/resolver/mod.rs b/src/lib/resolver/mod.rs index f0618ca9..41e3ce06 100644 --- a/src/lib/resolver/mod.rs +++ b/src/lib/resolver/mod.rs @@ -2,7 +2,7 @@ use crate::{ ast::{tree::IdentifierPath, tree::Root, visit::*}, diagnostics::Diagnostic, helpers::scopes::Scopes, - parser::{ParsingCtx, Span}, + parser::ParsingCtx, }; mod resolution_map; diff --git a/src/lib/rock.rs b/src/lib/rock.rs index b81288bd..6028601d 100644 --- a/src/lib/rock.rs +++ b/src/lib/rock.rs @@ -1,4 +1,4 @@ -#![feature(associated_type_bounds, derive_default_enum)] +#![feature(associated_type_bounds)] #[macro_use] extern crate serde_derive; @@ -30,11 +30,10 @@ mod resolver; mod tests; mod ty; -use ast::ast_print::AstPrintContext; use codegen::interpret; use diagnostics::Diagnostic; pub use helpers::config::Config; -use parser::{ParserCtx, ParsingCtx, SourceFile}; +use parser::{ParsingCtx, SourceFile}; pub fn compile_file(in_name: String, config: &Config) -> Result<(), Diagnostic> { let mut source_file = SourceFile::from_file(in_name)?; From cb9956533132d266e228af6936edd3f980fffce4 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 16:23:34 +0000 Subject: [PATCH 72/74] Generated files for new version --- Cargo.toml | 2 +- README.md | 10 +++++----- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 12509478..f5450b37 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.8-new-parser" +version = "0.1.8-develop" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 9db1138f..55c3f61b 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Rock v0.1.8-new-parser +# Rock v0.1.8-develop -[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=new_parser)](https://github.com/Champii/Rock/actions/workflows/rust.yml) +[![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) Little language made with Rust and LLVM. @@ -45,10 +45,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.8-new-parser](https://github.com/Champii/Rock/releases/download/v0.1.8-new-parser/rock) (Tested on arch, btw) +[Rock v0.1.8-develop](https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.8-new-parser/rock +wget https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock chmod +x rock ./rock -V ``` @@ -250,7 +250,7 @@ rock --repl ``` ``` sh -Rock: v0.1.8-new-parser +Rock: v0.1.8-develop ---- Type ':?' for help From 765495e81c591dc9fb340a1cae028496a092f5e0 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 18:31:24 +0200 Subject: [PATCH 73/74] Bump version --- .github/version | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.github/version b/.github/version index da147300..1474d00f 100644 --- a/.github/version +++ b/.github/version @@ -1 +1 @@ -v0.1.8 +v0.2.0 From 204fc24250a54571a0205449a947d0697d07d2d8 Mon Sep 17 00:00:00 2001 From: Champii Date: Tue, 19 Apr 2022 16:32:51 +0000 Subject: [PATCH 74/74] Generated files for new version --- Cargo.toml | 2 +- README.md | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index f5450b37..7b6b1136 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,6 +1,6 @@ [package] name = "rock" -version = "0.1.8-develop" +version = "0.2.0-develop" authors = ["champii "] edition = "2018" diff --git a/README.md b/README.md index 55c3f61b..cd487e25 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Rock v0.1.8-develop +# Rock v0.2.0-develop [![Rust](https://github.com/Champii/Rock/actions/workflows/rust.yml/badge.svg?branch=develop)](https://github.com/Champii/Rock/actions/workflows/rust.yml) @@ -45,10 +45,10 @@ You will need `clang` somewhere in your $PATH Linux x86_64 only -[Rock v0.1.8-develop](https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock) (Tested on arch, btw) +[Rock v0.2.0-develop](https://github.com/Champii/Rock/releases/download/v0.2.0-develop/rock) (Tested on arch, btw) ``` sh -wget https://github.com/Champii/Rock/releases/download/v0.1.8-develop/rock +wget https://github.com/Champii/Rock/releases/download/v0.2.0-develop/rock chmod +x rock ./rock -V ``` @@ -250,7 +250,7 @@ rock --repl ``` ``` sh -Rock: v0.1.8-develop +Rock: v0.2.0-develop ---- Type ':?' for help