diff --git a/src/kind-derive/Cargo.toml b/src/kind-derive/Cargo.toml index cbafc48d..cd44e417 100644 --- a/src/kind-derive/Cargo.toml +++ b/src/kind-derive/Cargo.toml @@ -8,4 +8,5 @@ edition = "2021" [dependencies] kind-span = { path = "../kind-span" } kind-tree = { path = "../kind-tree" } -kind-report = { path = "../kind-report" } \ No newline at end of file +kind-report = { path = "../kind-report" } +fxhash = "0.2.1" \ No newline at end of file diff --git a/src/kind-derive/src/lib.rs b/src/kind-derive/src/lib.rs index c7204324..216032ca 100644 --- a/src/kind-derive/src/lib.rs +++ b/src/kind-derive/src/lib.rs @@ -2,3 +2,4 @@ pub mod matching; pub mod open; +pub mod subst; diff --git a/src/kind-derive/src/matching.rs b/src/kind-derive/src/matching.rs index 35e445e1..4eea57b5 100644 --- a/src/kind-derive/src/matching.rs +++ b/src/kind-derive/src/matching.rs @@ -1,6 +1,7 @@ //! Module to derive a dependent //! eliminator out of a sum type declaration. +use fxhash::FxHashMap; use kind_span::Range; use kind_tree::concrete::expr::Expr; @@ -9,6 +10,8 @@ use kind_tree::concrete::*; use kind_tree::concrete::{self}; use kind_tree::symbol::{Ident, QualifiedIdent}; +use crate::subst::{substitute_in_expr}; + /// Derives an eliminator from a sum type declaration. pub fn derive_match(range: Range, sum: &SumTypeDecl) -> concrete::Entry { let mk_var = |name: Ident| -> Box { @@ -202,11 +205,11 @@ pub fn derive_match(range: Range, sum: &SumTypeDecl) -> concrete::Entry { spine_params = sum .parameters .extend(&cons.args) - .map(|x| x.name.with_name(|f| format!("{}", f))) + .map(|x| x.name.with_name(|f| format!("_{}_", f))) .to_vec(); spine = cons .args - .map(|x| x.name.with_name(|f| format!("{}", f))) + .map(|x| x.name.with_name(|f| format!("_{}_", f))) .to_vec(); args_indices = sp .iter() @@ -218,7 +221,22 @@ pub fn derive_match(range: Range, sum: &SumTypeDecl) -> concrete::Entry { Binding::Named(_, _, _) => unreachable!(), }) .collect::>(); - args_indices = args_indices[sum.parameters.len()..].into(); + args_indices = { + let mut indices = args_indices[sum.parameters.len()..].to_vec(); + + let renames = FxHashMap::from_iter( + sum.parameters + .extend(&cons.args) + .map(|x| (x.name.to_string(), format!("_{}_", x.name.to_string()))) + .iter() + .cloned(), + ); + + for indice in &mut indices { + substitute_in_expr(&mut indice.data, &renames) + } + indices + }; } _ => unreachable!(), }, @@ -228,12 +246,12 @@ pub fn derive_match(range: Range, sum: &SumTypeDecl) -> concrete::Entry { .parameters .extend(&sum.indices) .extend(&cons.args) - .map(|x| x.name.with_name(|f| format!("{}", f))) + .map(|x| x.name.with_name(|f| format!("_{}_", f))) .to_vec(); spine = sum .indices .extend(&cons.args) - .map(|x| x.name.with_name(|f| format!("{}", f))) + .map(|x| x.name.with_name(|f| format!("_{}_", f))) .to_vec(); args_indices = sum .indices diff --git a/src/kind-derive/src/subst.rs b/src/kind-derive/src/subst.rs new file mode 100644 index 00000000..4a3f5a45 --- /dev/null +++ b/src/kind-derive/src/subst.rs @@ -0,0 +1,21 @@ +use fxhash::FxHashMap; +use kind_tree::{concrete::{visitor::Visitor, expr::Expr}, symbol::Symbol}; + +pub struct Subst<'a> { + pub names: &'a FxHashMap, +} + +impl<'a> Visitor for Subst<'a> { + fn visit_ident(&mut self, ident: &mut kind_tree::symbol::Ident) { + if let Some(res) = self.names.get(ident.to_str()) { + ident.data = Symbol::new(res.clone()); + } + } +} + +pub fn substitute_in_expr(expr: &mut Expr, names: &FxHashMap) { + let mut session = Subst { + names, + }; + session.visit_expr(expr) +} diff --git a/src/kind-parser/src/expr.rs b/src/kind-parser/src/expr.rs index fba57bb5..9453d184 100644 --- a/src/kind-parser/src/expr.rs +++ b/src/kind-parser/src/expr.rs @@ -123,6 +123,13 @@ impl<'a> Parser<'a> { Ok(ident) } + pub fn parse_any_id(&mut self) -> Result { + let range = self.range(); + let id = eat_single!(self, Token::LowerId(x) | Token::UpperId(x, None) => x.clone())?; + let ident = Ident::new_static(&id, range); + Ok(ident) + } + pub fn parse_upper_id(&mut self) -> Result { let range = self.range(); let (start, end) = @@ -554,11 +561,11 @@ impl<'a> Parser<'a> { pub fn parse_sttm(&mut self) -> Result, SyntaxError> { let start = self.range(); - if self.check_actual(Token::Ask) { + if self.check_actual_id("ask") { self.parse_ask() - } else if self.check_actual(Token::Return) { + } else if self.check_actual_id("return") { self.parse_return() - } else if self.check_actual(Token::Let) { + } else if self.check_actual_id("let") { self.parse_monadic_let() } else { let expr = self.parse_expr(false)?; @@ -643,7 +650,7 @@ impl<'a> Parser<'a> { let mut cases = Vec::new(); while !self.get().same_variant(&Token::RBrace) { - let constructor = self.parse_id()?; + let constructor = self.parse_any_id()?; let (_range, bindings, ignore_rest) = self.parse_pat_destruct_bindings()?; self.eat_variant(Token::FatArrow)?; let value = self.parse_expr(false)?; @@ -722,7 +729,7 @@ impl<'a> Parser<'a> { self.eat_variant(Token::LBrace)?; let if_ = self.parse_expr(false)?; self.eat_variant(Token::RBrace)?; - self.eat_variant(Token::Else)?; + self.eat_id("else")?; self.eat_variant(Token::LBrace)?; let els_ = self.parse_expr(false)?; let end = self.eat_variant(Token::RBrace)?.1; @@ -738,13 +745,13 @@ impl<'a> Parser<'a> { /// some looakhead tokens. pub fn parse_expr(&mut self, multiline: bool) -> Result, SyntaxError> { self.ignore_docs(); - if self.check_actual(Token::Do) { + if self.check_actual_id("do") { self.parse_do() - } else if self.check_actual(Token::Match) { + } else if self.check_actual_id("match") { self.parse_match() - } else if self.check_actual(Token::Let) { + } else if self.check_actual_id("let") { self.parse_let() - } else if self.check_actual(Token::If) { + } else if self.check_actual_id("if") { self.parse_if() } else if self.check_actual(Token::Dollar) { self.parse_sigma_pair() diff --git a/src/kind-parser/src/lexer/mod.rs b/src/kind-parser/src/lexer/mod.rs index 8852fbfe..6c3437f9 100644 --- a/src/kind-parser/src/lexer/mod.rs +++ b/src/kind-parser/src/lexer/mod.rs @@ -52,18 +52,6 @@ impl<'a> Lexer<'a> { pub fn to_keyword(data: &str) -> Token { match data { "_" => Token::Hole, - "ask" => Token::Ask, - "do" => Token::Do, - "if" => Token::If, - "else" => Token::Else, - "match" => Token::Match, - "let" => Token::Let, - "use" => Token::Use, - "as" => Token::As, - "return" => Token::Return, - "type" => Token::Type, - "record" => Token::Record, - "constructor" => Token::Constructor, _ => Token::LowerId(data.to_string()), } } diff --git a/src/kind-parser/src/lexer/tokens.rs b/src/kind-parser/src/lexer/tokens.rs index 5cddc594..b1422b04 100644 --- a/src/kind-parser/src/lexer/tokens.rs +++ b/src/kind-parser/src/lexer/tokens.rs @@ -30,18 +30,18 @@ pub enum Token { UpperId(String, Option), // Keywords - Do, - If, - Else, - Match, - Ask, - Return, - Let, - Type, - Record, - Constructor, - Use, - As, + // Do, + // If, + // Else, + // Match, + // Ask, + // Return, + // Let, + // Type, + // Record, + // Constructor, + // Use, + // As, // Literals Char(char), @@ -139,18 +139,6 @@ impl fmt::Display for Token { Token::LowerId(id) => write!(f, "{}", id), Token::UpperId(main, Some(aux)) => write!(f, "{}/{}", main, aux), Token::UpperId(main, None) => write!(f, "{}", main), - Token::Do => write!(f, "do"), - Token::If => write!(f, "if"), - Token::Else => write!(f, "else"), - Token::Match => write!(f, "match"), - Token::Ask => write!(f, "ask"), - Token::Return => write!(f, "return"), - Token::Let => write!(f, "let"), - Token::Type => write!(f, "type"), - Token::Record => write!(f, "record"), - Token::Constructor => write!(f, "constructor"), - Token::Use => write!(f, "use"), - Token::As => write!(f, "as"), Token::Char(c) => write!(f, "'{}'", c), Token::Str(s) => write!(f, "\"{}\"", s), Token::Num60(n) => write!(f, "{}", n), diff --git a/src/kind-parser/src/state.rs b/src/kind-parser/src/state.rs index 90c65568..77fbc26b 100644 --- a/src/kind-parser/src/state.rs +++ b/src/kind-parser/src/state.rs @@ -105,6 +105,13 @@ impl<'a> Parser<'a> { } } + pub fn eat_id(&mut self, expect: &str) -> Result<(Token, Range), SyntaxError> { + match self.get() { + Token::LowerId(x) if x == expect => Ok(self.advance()), + _ => self.fail(vec![Token::LowerId(expect.to_string())]) + } + } + pub fn eat(&mut self, expect: fn(&Token) -> Option) -> Result { match expect(self.get()) { None => self.fail(vec![]), @@ -128,6 +135,10 @@ impl<'a> Parser<'a> { self.get().same_variant(&expect) } + pub fn check_actual_id(&self, expect: &str) -> bool { + matches!(self.get(), Token::LowerId(x) if x == expect) + } + pub fn try_single( &mut self, fun: &dyn Fn(&mut Parser<'a>) -> Result, diff --git a/src/kind-parser/src/top_level/attributes.rs b/src/kind-parser/src/top_level/attributes.rs index 73d33a43..78e8fc8f 100644 --- a/src/kind-parser/src/top_level/attributes.rs +++ b/src/kind-parser/src/top_level/attributes.rs @@ -6,11 +6,30 @@ use crate::lexer::tokens::Token; use crate::state::Parser; impl<'a> Parser<'a> { + pub fn parse_attr_args(&mut self) -> Result, SyntaxError> { + let mut attrs = Vec::new(); + + let range = self.range(); + + if self.check_and_eat(Token::LBracket) { + while let Some(res) = self.try_single(&|fun| fun.parse_attr_style())? { + attrs.push(res); + if !self.check_and_eat(Token::Comma) { + break; + } + } + + self.eat_closing_keyword(Token::RBracket, range)?; + } + + Ok(attrs) + } + pub fn parse_attr_style(&mut self) -> Result { match self.get().clone() { - Token::LowerId(_) => { + Token::LowerId(_) | Token::UpperId(_, None) => { let range = self.range(); - let ident = self.parse_id()?; + let ident = self.parse_any_id()?; Ok(AttributeStyle::Ident(range, ident)) } Token::Num60(num) => { @@ -46,7 +65,11 @@ impl<'a> Parser<'a> { pub fn parse_attr(&mut self) -> Result { let start = self.range(); self.eat_variant(Token::Hash)?; + let name = self.parse_id()?; + + let args = self.parse_attr_args()?; + let style = if self.check_and_eat(Token::Eq) { Some(self.parse_attr_style()?) } else { @@ -55,6 +78,7 @@ impl<'a> Parser<'a> { Ok(Attribute { range: start.mix(style.clone().map(|x| x.locate()).unwrap_or(name.range)), value: style, + args, name, }) } diff --git a/src/kind-parser/src/top_level/mod.rs b/src/kind-parser/src/top_level/mod.rs index 93618f81..6e02a676 100644 --- a/src/kind-parser/src/top_level/mod.rs +++ b/src/kind-parser/src/top_level/mod.rs @@ -32,8 +32,8 @@ impl<'a> Parser<'a> { pub fn is_top_level_start(&self) -> bool { self.is_top_level_entry() - || self.get().same_variant(&Token::Type) - || self.get().same_variant(&Token::Record) + || self.check_actual_id("type") + || self.check_actual_id("record") || self.get().same_variant(&Token::Hash) || self.get().is_doc() } @@ -231,13 +231,13 @@ impl<'a> Parser<'a> { let docs = self.parse_docs()?; let attrs = self.parse_attrs()?; - if self.check_actual(Token::Type) { + if self.check_actual_id("type") { Ok(TopLevel::SumType(self.parse_sum_type_def(docs, attrs)?)) - } else if self.check_actual(Token::Record) { + } else if self.check_actual_id("record") { Ok(TopLevel::RecordType(self.parse_record_def(docs, attrs)?)) } else if self.is_top_level_entry_continuation() { Ok(TopLevel::Entry(self.parse_entry(docs, attrs)?)) - } else if self.check_actual(Token::Use) { + } else if self.check_actual_id("use") { Err(SyntaxError::CannotUseUse(self.range())) } else { self.fail(vec![]) @@ -245,9 +245,9 @@ impl<'a> Parser<'a> { } pub fn parse_use(&mut self) -> Result<(String, String), SyntaxError> { - self.eat_variant(Token::Use)?; + self.eat_id("use")?; let origin = self.parse_upper_id()?; - self.eat_variant(Token::As)?; + self.eat_id("as")?; let alias = self.parse_upper_id()?; match (origin, alias) { @@ -275,7 +275,7 @@ impl<'a> Parser<'a> { let mut entries: Vec = Vec::new(); let mut uses: FxHashMap = Default::default(); - while self.get().same_variant(&Token::Use) { + while self.check_actual_id("use") { match self.parse_use() { Ok((origin, alias)) => { uses.insert(alias, origin); diff --git a/src/kind-parser/src/top_level/type_decl.rs b/src/kind-parser/src/top_level/type_decl.rs index b66e7a00..03057a70 100644 --- a/src/kind-parser/src/top_level/type_decl.rs +++ b/src/kind-parser/src/top_level/type_decl.rs @@ -7,7 +7,7 @@ use crate::state::Parser; impl<'a> Parser<'a> { pub fn parse_constructor(&mut self) -> Result { let docs = self.parse_docs()?; - let name = self.parse_id()?; + let name = self.parse_any_id()?; let args = self.parse_arguments()?; let typ = if self.check_and_eat(Token::Colon) { @@ -29,7 +29,7 @@ impl<'a> Parser<'a> { docs: Vec, attrs: Vec, ) -> Result { - self.eat_variant(Token::Type)?; + self.eat_id("type")?; let name = self.parse_upper_id()?; let parameters = self.parse_arguments()?; @@ -66,7 +66,7 @@ impl<'a> Parser<'a> { docs: Vec, attrs: Vec, ) -> Result { - self.eat_variant(Token::Record)?; + self.eat_id("record")?; let name = self.parse_upper_id()?; let parameters = self.parse_arguments()?; @@ -74,7 +74,7 @@ impl<'a> Parser<'a> { let range = self.range(); self.eat_variant(Token::LBrace)?; - self.eat_variant(Token::Constructor)?; + self.eat_id("constructor")?; let constructor = self.parse_id()?; diff --git a/src/kind-pass/src/desugar/destruct.rs b/src/kind-pass/src/desugar/destruct.rs index 49762217..b97c0d30 100644 --- a/src/kind-pass/src/desugar/destruct.rs +++ b/src/kind-pass/src/desugar/destruct.rs @@ -4,7 +4,7 @@ use kind_tree::concrete::{expr, CaseBinding, Destruct, TopLevel}; use kind_tree::desugared; use kind_tree::symbol::Ident; -use crate::errors::PassError; +use crate::errors::{PassError, Sugar}; use super::DesugarState; @@ -68,6 +68,7 @@ impl<'a> DesugarState<'a> { match binding { Destruct::Destruct(_, typ, case, jump_rest) => { let count = self.old_book.count.get(&typ.to_string()).unwrap(); + let open_id = typ.add_segment("open"); let rec = count .is_record_cons_of @@ -81,6 +82,11 @@ impl<'a> DesugarState<'a> { return desugared::Expr::err(typ.range); }; + if self.old_book.count.get(&open_id.to_string()).is_none() { + self.send_err(PassError::NeedToImplementMethods(binding.locate(), Sugar::Open(typ.to_string()))); + return desugared::Expr::err(range); + } + let ordered_fields = self.order_case_arguments( (&typ.range, typ.to_string()), &record @@ -102,8 +108,6 @@ impl<'a> DesugarState<'a> { } } - let open_id = typ.add_segment("open"); - let irrelev = count.arguments.map(|x| x.erased).to_vec(); let spine = vec![ @@ -148,6 +152,13 @@ impl<'a> DesugarState<'a> { ) -> Box { let entry = self.old_book.entries.get(&match_.typ.to_string()).unwrap(); + let match_id = match_.typ.add_segment("match"); + + if self.old_book.entries.get(&match_id.to_string()).is_none() { + self.send_err(PassError::NeedToImplementMethods(range, Sugar::Match(match_.typ.to_string()))); + return desugared::Expr::err(range); + } + let sum = if let TopLevel::SumType(sum) = entry { sum } else { @@ -226,7 +237,6 @@ impl<'a> DesugarState<'a> { self.send_err(PassError::NoCoverage(range, unbound)) } - let match_id = match_.typ.add_segment("match"); let motive = if let Some(res) = &match_.motive { self.desugar_expr(res) diff --git a/src/kind-pass/src/errors.rs b/src/kind-pass/src/errors.rs index fd742374..4d0ef68d 100644 --- a/src/kind-pass/src/errors.rs +++ b/src/kind-pass/src/errors.rs @@ -7,6 +7,8 @@ pub enum Sugar { Sigma, Pair, BoolIf, + Match(String), + Open(String), } /// Describes all of the possible errors inside each @@ -30,6 +32,11 @@ pub enum PassError { ShouldBeAParameter(Span, Range), NoFieldCoverage(Range, Vec), CannotPatternMatchOnErased(Range), + + AttributeDoesNotAcceptEqual(Range), + InvalidAttributeArgument(Range), + DuplicatedAttributeArgument(Range, Range), + CannotDerive(String, Range), } // TODO: A way to build an error message with methods @@ -150,11 +157,13 @@ impl Diagnostic for PassError { Sugar::Sigma => "You must implement 'Sigma' in order to use the sigma notation.".to_string(), Sugar::Pair => "You must implement 'Sigma' and 'Sigma.new' in order to use the sigma notation.".to_string(), Sugar::BoolIf => "You must implement 'Bool.if' in order to use the if notation.".to_string(), + Sugar::Match(name) => format!("You must implement '{}.match' in order to use the match notation (or derive match with #derive[match]).", name), + Sugar::Open(name) => format!("You must implement '{}.open' in order to use the open notation (or derive open with #derive[open]).", name), }], positions: vec![Marker { position: *expr_place, color: Color::Fst, - text: "Here!".to_string(), + text: "You cannot use this expression!".to_string(), no_code: false, main: true, }], @@ -422,6 +431,68 @@ impl Diagnostic for PassError { main: true, }], }, + PassError::AttributeDoesNotAcceptEqual(place) => DiagnosticFrame { + code: 209, + severity: Severity::Error, + title: "This attribute does not support values!".to_string(), + subtitles: vec![], + hints: vec![], + positions: vec![Marker { + position: *place, + color: Color::Fst, + text: "Try to remove everything after the equal".to_string(), + no_code: false, + main: true, + }], + }, + PassError::InvalidAttributeArgument(place) => DiagnosticFrame { + code: 209, + severity: Severity::Error, + title: "Invalid attribute argument".to_string(), + subtitles: vec![], + hints: vec![], + positions: vec![Marker { + position: *place, + color: Color::Fst, + text: "Remove it or replace".to_string(), + no_code: false, + main: true, + }], + }, + PassError::CannotDerive(name, place) => DiagnosticFrame { + code: 209, + severity: Severity::Error, + title: format!("Cannot derive '{}' for this definition", name), + subtitles: vec![], + hints: vec![], + positions: vec![Marker { + position: *place, + color: Color::Fst, + text: "Here!".to_string(), + no_code: false, + main: true, + }], + }, + PassError::DuplicatedAttributeArgument(first, sec) => DiagnosticFrame { + code: 209, + severity: Severity::Warning, + title: "Duplicated attribute argument".to_string(), + subtitles: vec![], + hints: vec![], + positions: vec![Marker { + position: *sec, + color: Color::For, + text: "Second declaration".to_string(), + no_code: false, + main: true, + },Marker { + position: *first, + color: Color::For, + text: "First declaration!".to_string(), + no_code: false, + main: true, + }], + }, } } } diff --git a/src/kind-pass/src/expand/mod.rs b/src/kind-pass/src/expand/mod.rs index 2570315f..3c772274 100644 --- a/src/kind-pass/src/expand/mod.rs +++ b/src/kind-pass/src/expand/mod.rs @@ -2,38 +2,182 @@ //! Currently it just derives `match` and `open` for sum type //! and record types respectively. +use std::fmt::Display; use std::sync::mpsc::Sender; use fxhash::FxHashMap; use kind_derive::matching::derive_match; use kind_derive::open::derive_open; use kind_report::data::Diagnostic; -use kind_tree::concrete::{Book, TopLevel}; +use kind_span::Locatable; +use kind_span::Range; +use kind_tree::concrete::{Attribute, Book, TopLevel}; + +use crate::errors::PassError; /// Expands sum type and record definitions to a lot of /// helper definitions like eliminators and replace qualified identifiers /// by their module names. pub mod uses; -pub fn expand_book(error_channel: Sender>, book: &mut Book) { +#[derive(Debug, Hash, PartialEq, Eq)] +pub enum Derive { + Match, + Open +} + +impl Display for Derive { + fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { + match self { + Derive::Match => write!(f, "match"), + Derive::Open => write!(f, "open"), + } + } +} + +pub fn insert_or_report( + channel: Sender>, + hashmap: &mut FxHashMap, + key: Derive, + range: Range, +) { + match hashmap.get(&key) { + Some(last_range) => { + channel + .send(Box::new(PassError::DuplicatedAttributeArgument(last_range.clone(), range))) + .unwrap(); + }, + None => { + hashmap.insert(key, range); + }, + } +} + +fn string_to_derive(name: &str) -> Option { + match name { + "match" => Some(Derive::Match), + "open" => Some(Derive::Open), + _ => None, + } +} + + +pub fn expand_derive( + error_channel: Sender>, + attrs: &[Attribute], +) -> Option> { + let mut failed = false; + let mut def = FxHashMap::default(); + + for attr in attrs { + if attr.name.to_str() != "derive" { + continue; + } + + if let Some(attr) = &attr.value { + error_channel + .send(Box::new(PassError::AttributeDoesNotAcceptEqual( + attr.locate(), + ))) + .unwrap(); + failed = true; + } + + use kind_tree::concrete::AttributeStyle::*; + for arg in &attr.args { + match arg { + Ident(range, ident) => match string_to_derive(ident.to_str()) { + Some(key) => insert_or_report(error_channel.clone(), &mut def, key, range.clone()), + _ => { + error_channel + .send(Box::new(PassError::InvalidAttributeArgument( + ident.locate(), + ))) + .unwrap(); + failed = true; + } + }, + other => { + error_channel + .send(Box::new(PassError::InvalidAttributeArgument( + other.locate(), + ))) + .unwrap(); + failed = true; + } + } + } + } + + if failed { + None + } else { + Some(def) + } + +} + +pub fn expand_book(error_channel: Sender>, book: &mut Book) -> bool { + let mut failed = false; + let mut entries = FxHashMap::default(); + for entry in book.entries.values() { match entry { TopLevel::SumType(sum) => { - let res = derive_match(sum.name.range, sum); - let info = res.extract_book_info(); - entries.insert(res.name.to_string(), (res, info)); + if let Some(derive) = expand_derive(error_channel.clone(), &sum.attrs) { + for (key, val) in derive { + match key { + Derive::Match => { + let res = derive_match(sum.name.range, sum); + let info = res.extract_book_info(); + entries.insert(res.name.to_string(), (res, info)); + } + other => { + error_channel + .send(Box::new(PassError::CannotDerive( + other.to_string(), val, + ))) + .unwrap(); + failed = true; + } + } + } + } else { + failed = true; + } } TopLevel::RecordType(rec) => { - let res = derive_open(rec.name.range, rec); - let info = res.extract_book_info(); - entries.insert(res.name.to_string(), (res, info)); + if let Some(derive) = expand_derive(error_channel.clone(), &rec.attrs) { + for (key, val) in derive { + match key { + Derive::Open => { + let res = derive_open(rec.name.range, rec); + let info = res.extract_book_info(); + entries.insert(res.name.to_string(), (res, info)); + } + other => { + error_channel + .send(Box::new(PassError::CannotDerive( + other.to_string(), val, + ))) + .unwrap(); + failed = true; + } + } + } + } else { + failed = true; + } } TopLevel::Entry(_) => (), } } + for (name, (tl, count)) in entries { book.count.insert(name.clone(), count); book.names.insert(name.clone().to_string(), tl.name.clone()); book.entries.insert(name.clone(), TopLevel::Entry(tl)); } + + failed } diff --git a/src/kind-pass/src/lib.rs b/src/kind-pass/src/lib.rs index fd903051..879616d5 100644 --- a/src/kind-pass/src/lib.rs +++ b/src/kind-pass/src/lib.rs @@ -6,6 +6,6 @@ pub mod desugar; pub mod erasure; -mod errors; pub mod expand; pub mod unbound; +mod errors; diff --git a/src/kind-query/src/lib.rs b/src/kind-query/src/lib.rs index 55a44158..bef0956e 100644 --- a/src/kind-query/src/lib.rs +++ b/src/kind-query/src/lib.rs @@ -15,8 +15,7 @@ pub struct Resource { path: PathBuf, concrete_tree: concrete::Module, - /// Accumulated diagnostics while - diagnostics: Vec>, + /// Useful for LSP URIs ext: T, } diff --git a/src/kind-tree/src/concrete/mod.rs b/src/kind-tree/src/concrete/mod.rs index 60fc1f84..63715d9a 100644 --- a/src/kind-tree/src/concrete/mod.rs +++ b/src/kind-tree/src/concrete/mod.rs @@ -67,6 +67,7 @@ pub enum AttributeStyle { #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Attribute { pub name: Ident, + pub args: Vec, pub value: Option, pub range: Range, } @@ -362,6 +363,14 @@ impl Display for AttributeStyle { impl Display for Attribute { fn fmt(&self, f: &mut Formatter<'_>) -> Result<(), Error> { write!(f, "#{}", self.name)?; + if !self.args.is_empty() { + write!(f, "[")?; + write!(f, "{}", self.args[0])?; + for arg in self.args[1..].iter() { + write!(f, ", {}", arg)?; + } + write!(f, "]")?; + } if let Some(res) = &self.value { write!(f, " = {}", res)?; } diff --git a/src/kind-tree/src/symbol.rs b/src/kind-tree/src/symbol.rs index 79100eda..f319188e 100644 --- a/src/kind-tree/src/symbol.rs +++ b/src/kind-tree/src/symbol.rs @@ -11,6 +11,12 @@ use kind_span::{Range, SyntaxCtxIndex}; #[derive(Clone, PartialEq, Eq, Hash, Debug)] pub struct Symbol(String); +impl Symbol { + pub fn new(str: String) -> Symbol { + Symbol(str) + } +} + /// Identifier inside a syntax context. #[derive(Clone, Debug, Hash, PartialEq, Eq)] pub struct Ident {