diff --git a/Cargo.lock b/Cargo.lock index 02580b3f..d0ae91d3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -2,6 +2,12 @@ # It is not intended for manual editing. version = 3 +[[package]] +name = "anyhow" +version = "1.0.66" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "216261ddc8289130e551ddcd5ce8a064710c0d064a4d2895c67151c92b5443f6" + [[package]] name = "arrayvec" version = "0.7.2" @@ -351,6 +357,12 @@ dependencies = [ "libc", ] +[[package]] +name = "exitcode" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "de853764b47027c2e862a995c34978ffa63c1501f2e15f987ba11bd4f9bba193" + [[package]] name = "fixed-hash" version = "0.7.0" @@ -606,7 +618,9 @@ dependencies = [ name = "kind-cli" version = "0.3.0" dependencies = [ + "anyhow", "clap 4.0.29", + "exitcode", "kind-checker", "kind-driver", "kind-query", @@ -628,6 +642,7 @@ dependencies = [ name = "kind-driver" version = "0.1.0" dependencies = [ + "anyhow", "dashmap", "fxhash", "hvm", @@ -656,6 +671,7 @@ dependencies = [ name = "kind-pass" version = "0.1.0" dependencies = [ + "anyhow", "fxhash", "im-rc", "kind-derive", diff --git a/FEATURES.md b/FEATURES.md new file mode 100644 index 00000000..77f27a97 --- /dev/null +++ b/FEATURES.md @@ -0,0 +1,77 @@ +It's a entirely new compiler in the 0.3 version. A lot of the features are just simple increments to the old ones but they really help with DX. Lets start by the lexical features: + +- Identifiers cannot start with dot +- We can have numbers in a lot of formats now like: + - `0xFF`, `0XFF`, `0o17`, `0O17`, `0b10`, `0B10` and decimals. + - `0u60` and `0u120`, `0n` that describes u120 and u60 literals. +- Numbers can contain lots of underscores (just use one between digits please, + we will change it in the future) e.g `100_000_000` +- There's a distinction between Upper identifiers and Lower identifiers. Upper cased identifiers + can contain a single `'/'` between two parts, if the second part is available then the first one is the name that will be replaced by an 'use' statement. +- each string char and the char inside a char token can contain escape sequences in a looot of format. like `\x12` `\u1234` `\n` `\r` `\t` `\0` `\\` `\'` `\"` +- Comments with `/* */` that can be nested :) + +The syntatic features are almost all the same with some small changes. + +- Attributes are a little bit more complex and can be seen in some formats. + - Single identifier like: #inline + - With arguments like: #derive[match, open] + - With value like: #kdl_name = Joestar + +- Use statements are in the format `use A as B` and they rename upper cased identifiers like `B/c` to `A.c` + +- Type definitions now support indices and are in the .kind2 files! e.g: + ```js + // Parameters are always in the context like `t` but `n` isnt. + type Vec (t: Type) ~ (n: Nat) { + cons (x: t) (xs: Vec t size) : Vec t (Nat.succ size) + nil : Vec t Nat.zero + } + ``` + You can use the `match` eliminator to destruct this vec without having to pattern match on this (but you have to derive `match`). + ```js + Main : U60 + Main = + match Vec (Vec.cons 1 Vec.nil) { + cons xs .. => 0 + nil => 1 + } + ``` + Take a look at the section about `match patterns` in order to understand the `xs` and `..` inside the `cons` case. + +- Record definitions :D + ```js + record User { + constructor new + name : String + age : U60 + } + ``` + You can use the `destruct` notation if you want to destruct a record but you have to derive `open` to make this feature work. `#derive[open]` before the record definition. + ```js + // Using + Main : U60 + Main = let User.new name .. = User.new "abe" 21 + name + ``` + +- Entries stay all the same, except that you cannot put repeated names because it would make the named parameter process a bit harder. + Btw, you can make something like + ```js + Dio (n: U60) (i: U60) : Type + + // Named parameters :sunglasses: + Main { + Dio (i = 2) (n = 4) + } + ``` + +- All the current syntax sugars are: + - Sigma types + - Substitutions + - Do notation + - Match + - Let + - If + +- Doc strings (useful for the future) using `///` diff --git a/README.md b/README.md index 5508155e..1f0576a3 100644 --- a/README.md +++ b/README.md @@ -22,7 +22,7 @@ Pure functions are defined via equations, as in [Haskell](https://www.haskell.or // Applies a function to every element of a list map (list: List a) (f: a -> b) : List b map a b Nil f = Nil -map a b (Cons head tail) f = Cons (f x) (map tail f) +map a b (Cons head tail) f = Cons (f head) (map tail f) ``` Side-effective programs are written via monadic monads, resembling [Rust](https://www.rust-lang.org/) and [TypeScript](https://www.typescriptlang.org/): diff --git a/SYNTAX.md b/SYNTAX.md index 0dc5d366..cefd88ad 100644 --- a/SYNTAX.md +++ b/SYNTAX.md @@ -465,14 +465,6 @@ List.nil) But underneath the hood, what an implicit argument actually does is automatically put holes in these places. -Moreover, single holes can be shortened as `!`. So it can also be written as: - -``` -List.cons!(List.cons!(1, List.cons!(2, List.nil!)), -List.cons!(List.cons!(3, List.cons!(4, List.nil!)), -List.nil!)) -``` - Of course, in this particular example, we can just use the list notation directly: ``` diff --git a/crates/kind-cli/Cargo.toml b/crates/kind-cli/Cargo.toml index b73f573b..02d8a582 100644 --- a/crates/kind-cli/Cargo.toml +++ b/crates/kind-cli/Cargo.toml @@ -19,4 +19,6 @@ kind-report = { path = "../kind-report" } kind-checker = { path = "../kind-checker" } kind-query = { path = "../kind-query" } -clap = { version = "4.0.10", features = ["derive"] } \ No newline at end of file +clap = { version = "4.0.10", features = ["derive"] } +anyhow = "1.0.66" +exitcode = "1.1.2" \ No newline at end of file diff --git a/crates/kind-cli/src/main.rs b/crates/kind-cli/src/main.rs index 1a01a809..514382bc 100644 --- a/crates/kind-cli/src/main.rs +++ b/crates/kind-cli/src/main.rs @@ -3,6 +3,7 @@ use std::time::Instant; use std::{fmt, io}; use clap::{Parser, Subcommand}; +use driver::resolution::ResolutionError; use kind_driver::session::Session; use kind_report::data::{Diagnostic, Log}; use kind_report::report::{FileCache, Report}; @@ -33,7 +34,7 @@ pub struct Cli { pub no_color: bool, /// How much concurrency in HVM - #[arg(short, long)] + #[arg(long)] pub tids: Option, /// Prints all of the functions and their evaluation @@ -129,8 +130,8 @@ pub fn compile_in_session( root: PathBuf, file: String, compiled: bool, - fun: &mut dyn FnMut(&mut Session) -> Result, -) -> Result { + fun: &mut dyn FnMut(&mut Session) -> anyhow::Result, +) -> anyhow::Result { let (rx, tx) = std::sync::mpsc::channel(); let mut session = Session::new(root, rx); @@ -149,7 +150,8 @@ pub fn compile_in_session( let diagnostics = tx.try_iter().collect::>>(); - if diagnostics.is_empty() && res.is_ok() { + if diagnostics.is_empty() { + render_to_stderr( &render_config, &session, @@ -159,19 +161,27 @@ pub fn compile_in_session( Log::Checked(start.elapsed()) }, ); + eprintln!(); - Ok(res.unwrap()) + + res } else { render_to_stderr(&render_config, &session, &Log::Failed(start.elapsed())); eprintln!(); + for diagnostic in diagnostics { render_to_stderr(&render_config, &session, &diagnostic) } - Err(()) + + match res { + Ok(_) => Err(ResolutionError.into()), + Err(res) => Err(res) + } } } -pub fn run_cli(config: Cli) -> Result<(), ()> { +pub fn run_cli(config: Cli) -> anyhow::Result<()> { + kind_report::check_if_colors_are_supported(config.no_color); let render_config = kind_report::check_if_utf8_is_supported(config.ascii, 2); @@ -262,6 +272,9 @@ pub fn run_cli(config: Cli) -> Result<(), ()> { Ok(()) } -pub fn main() -> Result<(), ()> { - run_cli(Cli::parse()) +pub fn main() { + match run_cli(Cli::parse()) { + Ok(_) => std::process::exit(0), + Err(_) => std::process::exit(1), + } } diff --git a/crates/kind-driver/Cargo.toml b/crates/kind-driver/Cargo.toml index 3e25b1be..ffcc4efe 100644 --- a/crates/kind-driver/Cargo.toml +++ b/crates/kind-driver/Cargo.toml @@ -18,6 +18,7 @@ kind-target-kdl = { path = "../kind-target-kdl" } hvm = { git = "https://github.com/Kindelia/HVM.git" } +anyhow = "1.0.66" strsim = "0.10.0" fxhash = "0.2.1" dashmap = "5.4.0" \ No newline at end of file diff --git a/crates/kind-driver/src/errors.rs b/crates/kind-driver/src/errors.rs index 0e952adc..0b502846 100644 --- a/crates/kind-driver/src/errors.rs +++ b/crates/kind-driver/src/errors.rs @@ -56,7 +56,7 @@ impl Diagnostic for DriverError { DriverError::MultiplePaths(ident, paths) => DiagnosticFrame { code: 101, severity: Severity::Error, - title: "Multiple definitions for the same name".to_string(), + title: "Ambiguous definition location for the same name".to_string(), subtitles: paths .iter() .map(|path| Subtitle::Phrase(Color::Fst, vec![Word::White(path.display().to_string())])) diff --git a/crates/kind-driver/src/lib.rs b/crates/kind-driver/src/lib.rs index 9179c4d1..dd12398a 100644 --- a/crates/kind-driver/src/lib.rs +++ b/crates/kind-driver/src/lib.rs @@ -5,6 +5,7 @@ use kind_report::report::FileCache; use kind_span::SyntaxCtxIndex; use kind_tree::{backend, concrete, desugared, untyped}; +use resolution::ResolutionError; use session::Session; use std::path::PathBuf; @@ -25,17 +26,22 @@ pub fn type_check_book( session: &mut Session, path: &PathBuf, entrypoints: Vec, - tids: Option -) -> Result { + tids: Option, +) -> anyhow::Result { let concrete_book = to_book(session, path)?; let desugared_book = desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book)?; let all = desugared_book.entrs.iter().map(|x| x.0).cloned().collect(); - let succeeded = checker::type_check(&desugared_book, session.diagnostic_sender.clone(), all, tids); + let succeeded = checker::type_check( + &desugared_book, + session.diagnostic_sender.clone(), + all, + tids, + ); if !succeeded { - return Err(()); + return Err(ResolutionError.into()); } let mut book = erasure::erase_book( @@ -48,14 +54,10 @@ pub fn type_check_book( Ok(book) } -pub fn to_book(session: &mut Session, path: &PathBuf) -> Result { +pub fn to_book(session: &mut Session, path: &PathBuf) -> anyhow::Result { let mut concrete_book = resolution::parse_and_store_book(session, path)?; - let failed = resolution::check_unbound_top_level(session, &mut concrete_book); - - if failed { - return Err(()); - } + resolution::check_unbound_top_level(session, &mut concrete_book)?; Ok(concrete_book) } @@ -64,24 +66,29 @@ pub fn erase_book( session: &mut Session, path: &PathBuf, entrypoints: Vec, -) -> Result { +) -> anyhow::Result { let concrete_book = to_book(session, path)?; let desugared_book = desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book)?; + let mut book = erasure::erase_book( &desugared_book, session.diagnostic_sender.clone(), entrypoints, )?; + inline_book(&mut book); Ok(book) } -pub fn desugar_book(session: &mut Session, path: &PathBuf) -> Result { +pub fn desugar_book(session: &mut Session, path: &PathBuf) -> anyhow::Result { let concrete_book = to_book(session, path)?; desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book) } -pub fn check_erasure_book(session: &mut Session, path: &PathBuf) -> Result { +pub fn check_erasure_book( + session: &mut Session, + path: &PathBuf, +) -> anyhow::Result { let concrete_book = to_book(session, path)?; desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book) } @@ -95,9 +102,10 @@ pub fn compile_book_to_kdl( session: &mut Session, namespace: &str, entrypoints: Vec, -) -> Result { +) -> anyhow::Result { let concrete_book = to_book(session, path)?; let desugared_book = desugar::desugar_book(session.diagnostic_sender.clone(), &concrete_book)?; + let mut book = erasure::erase_book( &desugared_book, session.diagnostic_sender.clone(), @@ -106,28 +114,29 @@ pub fn compile_book_to_kdl( inline_book(&mut book); - kind_target_kdl::compile_book(book, session.diagnostic_sender.clone(), namespace) + let res = kind_target_kdl::compile_book(book, session.diagnostic_sender.clone(), namespace)?; + + Ok(res) } -pub fn check_main_entry(session: &mut Session, book: &untyped::Book) -> Result<(), ()> { +pub fn check_main_entry(session: &mut Session, book: &untyped::Book) -> anyhow::Result<()> { if !book.entrs.contains_key("Main") { - session - .diagnostic_sender - .send(Box::new(DriverError::ThereIsntAMain)) - .unwrap(); - Err(()) + let err = Box::new(DriverError::ThereIsntAMain); + session.diagnostic_sender.send(err).unwrap(); + Err(ResolutionError.into()) } else { Ok(()) } } -pub fn check_main_desugared_entry(session: &mut Session, book: &desugared::Book) -> Result<(), ()> { +pub fn check_main_desugared_entry( + session: &mut Session, + book: &desugared::Book, +) -> anyhow::Result<()> { if !book.entrs.contains_key("Main") { - session - .diagnostic_sender - .send(Box::new(DriverError::ThereIsntAMain)) - .unwrap(); - Err(()) + let err = Box::new(DriverError::ThereIsntAMain); + session.diagnostic_sender.send(err).unwrap(); + Err(ResolutionError.into()) } else { Ok(()) } diff --git a/crates/kind-driver/src/resolution.rs b/crates/kind-driver/src/resolution.rs index 45a81c00..6b021499 100644 --- a/crates/kind-driver/src/resolution.rs +++ b/crates/kind-driver/src/resolution.rs @@ -3,9 +3,11 @@ //! it returns a desugared book of all of the //! depedencies. +use core::fmt; use fxhash::FxHashSet; use kind_pass::expand::expand_module; use kind_pass::expand::uses::expand_uses; +use std::error::Error; use std::fs; use std::path::{Path, PathBuf}; use std::rc::Rc; @@ -19,6 +21,17 @@ use kind_tree::symbol::{Ident, QualifiedIdent}; use crate::{errors::DriverError, session::Session}; +#[derive(Debug)] +pub struct ResolutionError; + +impl fmt::Display for ResolutionError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "resolution error") + } +} + +impl Error for ResolutionError {} + /// The extension of kind2 files. const EXT: &str = "kind2"; @@ -30,10 +43,11 @@ fn accumulate_neighbour_paths( raw_path: &Path, ) -> Result, Box> { let mut canon_path = raw_path.to_path_buf(); - let mut dir_file_path = raw_path.to_path_buf(); - let dir_path = raw_path.to_path_buf(); + let mut dir_file_path = canon_path.clone(); + let dir_path = canon_path.clone(); canon_path.set_extension(EXT); + dir_file_path.push("_"); dir_file_path.set_extension(EXT); @@ -81,13 +95,12 @@ fn try_to_insert_new_name<'a>( book: &'a mut Book, ) -> bool { if let Some(first_occorence) = book.names.get(ident.to_string().as_str()) { - session - .diagnostic_sender - .send(Box::new(DriverError::DefinedMultipleTimes( - first_occorence.clone(), - ident, - ))) - .unwrap(); + let err = Box::new(DriverError::DefinedMultipleTimes( + first_occorence.clone(), + ident, + )); + + session.diagnostic_sender.send(err).unwrap(); *failed = true; false } else { @@ -107,29 +120,30 @@ fn module_to_book<'a>( for entry in module.entries { match entry { TopLevel::SumType(sum) => { - public_names.insert(sum.name.to_string()); + let name = sum.name.to_string(); + + public_names.insert(name.clone()); for cons in &sum.constructors { let mut cons_ident = sum.name.add_segment(cons.name.to_str()); cons_ident.range = cons.name.range; if try_to_insert_new_name(failed, session, cons_ident.clone(), book) { - public_names.insert(cons_ident.to_string()); - book.count - .insert(cons_ident.to_string(), cons.extract_book_info(&sum)); + let cons_name = cons_ident.to_string(); + public_names.insert(cons_name.clone()); + book.count.insert(cons_name, cons.extract_book_info(&sum)); } } if try_to_insert_new_name(failed, session, sum.name.clone(), book) { - book.count - .insert(sum.name.to_string(), sum.extract_book_info()); - book.entries - .insert(sum.name.to_string(), TopLevel::SumType(sum)); + book.count.insert(name.clone(), sum.extract_book_info()); + book.entries.insert(name, TopLevel::SumType(sum)); } } TopLevel::RecordType(rec) => { - public_names.insert(rec.name.to_string()); - book.count - .insert(rec.name.to_string(), rec.extract_book_info()); + let name = rec.name.to_string(); + public_names.insert(name.clone()); + book.count.insert(name.clone(), rec.extract_book_info()); + try_to_insert_new_name(failed, session, rec.name.clone(), book); let cons_ident = rec.name.add_segment(rec.constructor.to_str()); @@ -138,18 +152,18 @@ fn module_to_book<'a>( cons_ident.to_string(), rec.extract_book_info_of_constructor(), ); + try_to_insert_new_name(failed, session, cons_ident, book); - book.entries - .insert(rec.name.to_string(), TopLevel::RecordType(rec)); + book.entries.insert(name.clone(), TopLevel::RecordType(rec)); } TopLevel::Entry(entr) => { + let name = entr.name.to_string(); + try_to_insert_new_name(failed, session, entr.name.clone(), book); - public_names.insert(entr.name.to_string()); - book.count - .insert(entr.name.to_string(), entr.extract_book_info()); - book.entries - .insert(entr.name.to_string(), TopLevel::Entry(entr)); + public_names.insert(name.clone()); + book.count.insert(name.clone(), entr.extract_book_info()); + book.entries.insert(name, TopLevel::Entry(entr)); } } } @@ -176,25 +190,19 @@ fn parse_and_store_book_by_identifier( } } -fn parse_and_store_book_by_path( - session: &mut Session, - path: &PathBuf, - book: &mut Book, -) -> bool { +fn parse_and_store_book_by_path(session: &mut Session, path: &PathBuf, book: &mut Book) -> bool { if !path.exists() { - session - .diagnostic_sender - .send(Box::new(DriverError::CannotFindFile( - path.to_str().unwrap().to_string(), - ))) - .unwrap(); + let err = Box::new(DriverError::CannotFindFile( + path.to_str().unwrap().to_string(), + )); + + session.diagnostic_sender.send(err).unwrap(); return true; } - if session - .loaded_paths_map - .contains_key(&fs::canonicalize(path).unwrap()) - { + let canon_path = &fs::canonicalize(path).unwrap(); + + if session.loaded_paths_map.contains_key(canon_path) { return false; } @@ -213,15 +221,14 @@ fn parse_and_store_book_by_path( let ctx_id = session.book_counter; session.add_path(Rc::new(fs::canonicalize(path).unwrap()), input.clone()); + let tx = session.diagnostic_sender.clone(); - let (mut module, mut failed) = - kind_parser::parse_book(session.diagnostic_sender.clone(), ctx_id, &input); + let (mut module, mut failed) = kind_parser::parse_book(tx.clone(), ctx_id, &input); - expand_uses(&mut module, session.diagnostic_sender.clone()); + expand_uses(&mut module, tx.clone()); + expand_module(tx.clone(), &mut module); - expand_module(session.diagnostic_sender.clone(), &mut module); - - let mut state = UnboundCollector::new(session.diagnostic_sender.clone(), false); + let mut state = UnboundCollector::new(tx.clone(), false); state.visit_module(&mut module); for idents in state.unbound.values() { @@ -230,7 +237,7 @@ fn parse_and_store_book_by_path( } module_to_book(&mut failed, session, module, book); - + for idents in state.unbound_top_level.values() { let fst = idents.iter().next().unwrap(); if !book.names.contains_key(&fst.to_string()) { @@ -251,41 +258,45 @@ fn unbound_variable(session: &mut Session, book: &Book, idents: &[Ident]) { similar_names.sort_by(|x, y| x.0.total_cmp(&y.0)); - session - .diagnostic_sender - .send(Box::new(DriverError::UnboundVariable( - idents.to_vec(), - similar_names.iter().take(5).map(|x| x.1.clone()).collect(), - ))) - .unwrap(); + let err = Box::new(DriverError::UnboundVariable( + idents.to_vec(), + similar_names.iter().take(5).map(|x| x.1.clone()).collect(), + )); + + session.diagnostic_sender.send(err).unwrap(); } -pub fn parse_and_store_book(session: &mut Session, path: &PathBuf) -> Result { +pub fn parse_and_store_book(session: &mut Session, path: &PathBuf) -> anyhow::Result { let mut book = Book::default(); if parse_and_store_book_by_path(session, path, &mut book) { - Err(()) + Err(ResolutionError.into()) } else { Ok(book) } } -pub fn check_unbound_top_level(session: &mut Session, book: &mut Book) -> bool { +pub fn check_unbound_top_level(session: &mut Session, book: &mut Book) -> anyhow::Result<()> { let mut failed = false; let (_, unbound_tops) = unbound::get_book_unbound(session.diagnostic_sender.clone(), book, true); - for (_, unbound) in unbound_tops { + for unbound in unbound_tops.values() { let res: Vec = unbound .iter() .filter(|x| !x.generated) .map(|x| x.to_ident()) .collect(); + if !res.is_empty() { unbound_variable(session, book, &res); failed = true; } } - failed + if failed { + Err(ResolutionError.into()) + } else { + Ok(()) + } } diff --git a/crates/kind-parser/src/lexer/state.rs b/crates/kind-parser/src/lexer/state.rs index edf71591..6f033154 100644 --- a/crates/kind-parser/src/lexer/state.rs +++ b/crates/kind-parser/src/lexer/state.rs @@ -96,8 +96,8 @@ impl<'a> Lexer<'a> { Some(str) } - #[inline] /// Useful as entrypoint + #[inline] pub fn lex_next(&mut self) -> (Token, Range) { self.lex_token() } diff --git a/crates/kind-parser/src/top_level/mod.rs b/crates/kind-parser/src/top_level/mod.rs index 7a2e5bb6..8e7ae367 100644 --- a/crates/kind-parser/src/top_level/mod.rs +++ b/crates/kind-parser/src/top_level/mod.rs @@ -1,11 +1,8 @@ use fxhash::FxHashMap; use kind_tree::concrete::expr::Expr; use kind_tree::concrete::pat::{Pat, PatIdent, PatKind}; -/// Parses all of the top level structures -/// like Book, Entry, Rule and Argument. -use kind_tree::concrete::{ - Argument, Attribute, Entry, ExprKind, Module, Rule, Telescope, TopLevel, -}; + +use kind_tree::concrete::*; use kind_tree::symbol::QualifiedIdent; use crate::errors::SyntaxDiagnostic; @@ -85,6 +82,7 @@ impl<'a> Parser<'a> { fn parse_rule(&mut self, name: String) -> Result, SyntaxDiagnostic> { let start = self.range(); let ident; + if let Token::UpperId(name_id, ext) = self.get() { let qual = QualifiedIdent::new_static(name_id.as_str(), ext.clone(), start); if qual.to_string() == name { @@ -95,6 +93,7 @@ impl<'a> Parser<'a> { } else { return self.fail(vec![]); } + let mut pats = Vec::new(); while !self.get().same_variant(&Token::Eq) && !self.get().same_variant(&Token::Eof) { pats.push(self.parse_pat()?); diff --git a/crates/kind-pass/Cargo.toml b/crates/kind-pass/Cargo.toml index 123161f8..84c63af3 100644 --- a/crates/kind-pass/Cargo.toml +++ b/crates/kind-pass/Cargo.toml @@ -13,4 +13,5 @@ kind-derive = { path = "../kind-derive" } linked-hash-map = "0.5.6" fxhash = "0.2.1" -im-rc = "15.1.0" \ No newline at end of file +im-rc = "15.1.0" +anyhow = "1.0.66" \ No newline at end of file diff --git a/crates/kind-pass/src/desugar/mod.rs b/crates/kind-pass/src/desugar/mod.rs index e73391d7..19fa050e 100644 --- a/crates/kind-pass/src/desugar/mod.rs +++ b/crates/kind-pass/src/desugar/mod.rs @@ -16,7 +16,7 @@ use kind_tree::{ symbol::Ident, }; -use crate::errors::PassError; +use crate::errors::{PassError, GenericPassError}; pub mod app; pub mod attributes; @@ -35,7 +35,7 @@ pub struct DesugarState<'a> { pub fn desugar_book( errors: Sender>, book: &concrete::Book, -) -> Result { +) -> anyhow::Result { let mut state = DesugarState { errors, old_book: book, @@ -45,7 +45,7 @@ pub fn desugar_book( }; state.desugar_book(book); if state.failed { - Err(()) + Err(GenericPassError.into()) } else { Ok(state.new_book) } diff --git a/crates/kind-pass/src/desugar/top_level.rs b/crates/kind-pass/src/desugar/top_level.rs index 169516b0..5a2c003f 100644 --- a/crates/kind-pass/src/desugar/top_level.rs +++ b/crates/kind-pass/src/desugar/top_level.rs @@ -245,7 +245,6 @@ impl<'a> DesugarState<'a> { use concrete::pat::PatKind; match &pat.data { PatKind::App(head, spine) => { - // TODO: Fix lol let entry = self .old_book .count diff --git a/crates/kind-pass/src/erasure/mod.rs b/crates/kind-pass/src/erasure/mod.rs index 2dee76f5..50179ada 100644 --- a/crates/kind-pass/src/erasure/mod.rs +++ b/crates/kind-pass/src/erasure/mod.rs @@ -8,7 +8,7 @@ use kind_tree::desugared; use kind_tree::symbol::QualifiedIdent; use kind_tree::untyped::{self}; -use crate::errors::PassError; +use crate::errors::{PassError, GenericPassError}; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] enum Relevance { @@ -54,7 +54,7 @@ pub fn erase_book( book: &desugared::Book, errs: Sender>, entrypoints: Vec, -) -> Result { +) -> anyhow::Result { let mut state = ErasureState { errs, book, @@ -99,7 +99,7 @@ impl<'a> ErasureState<'a> { &mut self, book: &'a desugared::Book, named_entrypoints: Vec, - ) -> Result { + ) -> anyhow::Result { let mut vals = FxHashMap::default(); let mut entrypoints = Vec::new(); @@ -189,7 +189,7 @@ impl<'a> ErasureState<'a> { } if self.failed { - Err(()) + Err(GenericPassError.into()) } else { Ok(new_book) } diff --git a/crates/kind-pass/src/errors.rs b/crates/kind-pass/src/errors.rs index 7742eabd..b9c3ff05 100644 --- a/crates/kind-pass/src/errors.rs +++ b/crates/kind-pass/src/errors.rs @@ -1,7 +1,20 @@ +use std::{fmt::Display, error::Error}; + use kind_report::data::{Color, Diagnostic, DiagnosticFrame, Marker, Severity}; use kind_span::{Range, SyntaxCtxIndex}; use kind_tree::symbol::Ident; +#[derive(Debug)] +pub struct GenericPassError; + +impl Display for GenericPassError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "generic pass error") + } +} + +impl Error for GenericPassError { } + pub enum Sugar { DoNotation, List, diff --git a/crates/kind-target-kdl/src/compile.rs b/crates/kind-target-kdl/src/compile.rs index 977768e9..003ceb3a 100644 --- a/crates/kind-target-kdl/src/compile.rs +++ b/crates/kind-target-kdl/src/compile.rs @@ -8,7 +8,7 @@ use tiny_keccak::Hasher; pub use kindelia_lang::ast as kdl; -use crate::errors::KdlError; +use crate::{errors::KdlError, GenericCompilationToHVMError}; pub const KDL_NAME_LEN: usize = 12; const U60_MAX: kdl::U120 = kdl::U120(0xFFFFFFFFFFFFFFF); @@ -97,7 +97,7 @@ pub fn compile_book( book: &untyped::Book, sender: Sender>, namespace: &str, -) -> Result { +) -> Result { let mut ctx = CompileCtx::new(book, sender); for (name, entry) in &book.entrs { @@ -120,7 +120,7 @@ pub fn compile_book( } if ctx.failed { - return Err(()); + return Err(GenericCompilationToHVMError); } Ok(ctx.file) diff --git a/crates/kind-target-kdl/src/lib.rs b/crates/kind-target-kdl/src/lib.rs index 7a879f86..1fe33145 100644 --- a/crates/kind-target-kdl/src/lib.rs +++ b/crates/kind-target-kdl/src/lib.rs @@ -1,4 +1,4 @@ -use std::sync::mpsc::Sender; +use std::{sync::mpsc::Sender, fmt::Display, error::Error}; use flatten::flatten; use kind_report::data::Diagnostic; @@ -12,11 +12,22 @@ mod flatten; mod linearize; mod subst; +#[derive(Debug)] +pub struct GenericCompilationToHVMError; + +impl Display for GenericCompilationToHVMError { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + write!(f, "generic compilation to hvm error") + } +} + +impl Error for GenericCompilationToHVMError { } + pub fn compile_book( book: untyped::Book, sender: Sender>, namespace: &str, -) -> Result { +) -> Result { // TODO: Remove kdl_states (maybe check if they're ever called?) // TODO: Convert to some sort of Kindelia.Contract let flattened = flatten(book); diff --git a/crates/kind-tests/benches/pure.rs b/crates/kind-tests/benches/pure.rs index 632a2238..e1f8aaf2 100644 --- a/crates/kind-tests/benches/pure.rs +++ b/crates/kind-tests/benches/pure.rs @@ -97,8 +97,8 @@ fn bench_exp_pure_check_unbound(b: &mut Bencher) { b.iter(|| { books.iter_mut().map(|(session, book)| { - let failed = resolution::check_unbound_top_level(session, book); - assert!(!failed) + let result = resolution::check_unbound_top_level(session, book); + assert!(result.is_ok()); }).fold(0, |n, _| n + 1) }) } @@ -110,8 +110,8 @@ fn bench_exp_pure_desugar(b: &mut Bencher) { let mut books: Vec<_> = paths.iter().map(|x| { let mut session = new_session(); let mut book = resolution::parse_and_store_book(&mut session, &PathBuf::from(x)).unwrap(); - let failed = resolution::check_unbound_top_level(&mut session, &mut book); - assert!(!failed); + let result = resolution::check_unbound_top_level(&mut session, &mut book); + assert!(result.is_ok()); (session, book) }).collect(); @@ -130,9 +130,9 @@ fn bench_exp_pure_erase(b: &mut Bencher) { let books: Vec<_> = paths.iter().map(|x| { let mut session = new_session(); let mut book = resolution::parse_and_store_book(&mut session, &PathBuf::from(x)).unwrap(); - let failed = resolution::check_unbound_top_level(&mut session, &mut book); + let result = resolution::check_unbound_top_level(&mut session, &mut book); let book = desugar::desugar_book(session.diagnostic_sender.clone(), &book).unwrap(); - assert!(!failed); + assert!(result.is_ok()); (session, book) }).collect(); @@ -156,9 +156,9 @@ fn bench_exp_pure_to_hvm(b: &mut Bencher) { let books: Vec<_> = paths.iter().map(|x| { let mut session = new_session(); let mut book = resolution::parse_and_store_book(&mut session, &PathBuf::from(x)).unwrap(); - let failed = resolution::check_unbound_top_level(&mut session, &mut book); + let result = resolution::check_unbound_top_level(&mut session, &mut book); let book = desugar::desugar_book(session.diagnostic_sender.clone(), &book).unwrap(); - assert!(!failed); + assert!(result.is_ok()); let book = erasure::erase_book( &book,