From bbe6c14cd67eeb7037eccae6e1d224fc89aa184a Mon Sep 17 00:00:00 2001 From: felipegchi Date: Thu, 17 Nov 2022 10:40:41 -0300 Subject: [PATCH] fix: fixed some problems with attribute parsing --- src/kind-parser/src/top_level/attributes.rs | 21 +++--- src/kind-pass/src/desugar/attributes.rs | 81 ++++++++++++++++++++- src/kind-pass/src/errors.rs | 50 ++++++++++++- src/kind-pass/src/expand/mod.rs | 2 +- src/kind-tree/src/desugared/mod.rs | 8 +- 5 files changed, 146 insertions(+), 16 deletions(-) diff --git a/src/kind-parser/src/top_level/attributes.rs b/src/kind-parser/src/top_level/attributes.rs index 78e8fc8f..615564e2 100644 --- a/src/kind-parser/src/top_level/attributes.rs +++ b/src/kind-parser/src/top_level/attributes.rs @@ -1,4 +1,4 @@ -use kind_span::Locatable; +use kind_span::{Locatable, Range}; use kind_tree::concrete::{Attribute, AttributeStyle}; use crate::errors::SyntaxError; @@ -6,10 +6,10 @@ use crate::lexer::tokens::Token; use crate::state::Parser; impl<'a> Parser<'a> { - pub fn parse_attr_args(&mut self) -> Result, SyntaxError> { + pub fn parse_attr_args(&mut self) -> Result<(Vec, Range), SyntaxError> { let mut attrs = Vec::new(); - let range = self.range(); + let mut range = self.range(); if self.check_and_eat(Token::LBracket) { while let Some(res) = self.try_single(&|fun| fun.parse_attr_style())? { @@ -18,11 +18,12 @@ impl<'a> Parser<'a> { break; } } - - self.eat_closing_keyword(Token::RBracket, range)?; + let start = range; + range = self.range(); + self.eat_closing_keyword(Token::RBracket, start)?; } - Ok(attrs) + Ok((attrs, range)) } pub fn parse_attr_style(&mut self) -> Result { @@ -68,15 +69,17 @@ impl<'a> Parser<'a> { let name = self.parse_id()?; - let args = self.parse_attr_args()?; + let (args, mut last) = self.parse_attr_args()?; let style = if self.check_and_eat(Token::Eq) { - Some(self.parse_attr_style()?) + let res = self.parse_attr_style()?; + last = res.locate(); + Some(res) } else { None }; Ok(Attribute { - range: start.mix(style.clone().map(|x| x.locate()).unwrap_or(name.range)), + range: start.mix(last), value: style, args, name, diff --git a/src/kind-pass/src/desugar/attributes.rs b/src/kind-pass/src/desugar/attributes.rs index fe7d64a5..9737a81e 100644 --- a/src/kind-pass/src/desugar/attributes.rs +++ b/src/kind-pass/src/desugar/attributes.rs @@ -1,9 +1,84 @@ -use kind_tree::{concrete, desugared}; +use kind_tree::{concrete::{self, Attribute, AttributeStyle}, desugared}; + +use crate::errors::PassError; use super::DesugarState; impl<'a> DesugarState<'a> { - pub fn desugar_attributes(&self, _attr: &[concrete::Attribute]) -> Vec { - Vec::new() + + fn args_should_be_empty(&mut self, attr: &Attribute) { + if !attr.args.is_empty() { + self.send_err(PassError::AttributeDoesNotExpectArgs(attr.range)) + }; + } + + fn attr_without_value(&mut self, attr: &Attribute) { + if attr.value.is_some() { + self.send_err(PassError::AttributeDoesNotExpectEqual(attr.range)) + }; + } + + fn attr_invalid_argument(&mut self, attr: &Attribute) { + if !attr.value.is_some() { + self.send_err(PassError::InvalidAttributeArgument(attr.range)) + }; + } + + fn attr_expects_a_value(&mut self, attr: &Attribute) { + if !attr.value.is_some() { + self.send_err(PassError::InvalidAttributeArgument(attr.range)) + }; + } + + pub fn desugar_attributes( + &mut self, + attrs: &[concrete::Attribute], + ) -> Vec { + let mut vec = Vec::new(); + + for attr in attrs { + match attr.name.to_str() { + // The derive attribute is treated by the expand + // pass so here we just ignore it. + "derive" => (), + "inline" => { + self.args_should_be_empty(attr); + self.attr_without_value(attr); + vec.push(desugared::Attribute::Inline); + } + "kdl_run" => { + self.args_should_be_empty(attr); + self.attr_without_value(attr); + vec.push(desugared::Attribute::KdlRun); + } + "kdl_erase" => { + self.args_should_be_empty(attr); + self.attr_without_value(attr); + vec.push(desugared::Attribute::KdlErase); + } + "kdl_name" => { + self.args_should_be_empty(attr); + match &attr.value { + Some(AttributeStyle::Ident(_, ident)) => { + vec.push(desugared::Attribute::KdlState(ident.clone())); + }, + Some(_) => self.attr_invalid_argument(attr), + None => self.attr_expects_a_value(attr) + } + }, + "kdl_state" => { + self.args_should_be_empty(attr); + match &attr.value { + Some(AttributeStyle::Ident(_, ident)) => { + vec.push(desugared::Attribute::KdlState(ident.clone())); + }, + Some(_) => self.attr_invalid_argument(attr), + None => self.attr_expects_a_value(attr) + } + }, + _ => self.send_err(PassError::AttributeDoesNotExists(attr.range)) + } + } + vec } } diff --git a/src/kind-pass/src/errors.rs b/src/kind-pass/src/errors.rs index 4d0ef68d..bc60ad21 100644 --- a/src/kind-pass/src/errors.rs +++ b/src/kind-pass/src/errors.rs @@ -33,10 +33,13 @@ pub enum PassError { NoFieldCoverage(Range, Vec), CannotPatternMatchOnErased(Range), - AttributeDoesNotAcceptEqual(Range), + AttributeDoesNotExpectEqual(Range), + AttributeDoesNotExpectArgs(Range), InvalidAttributeArgument(Range), + AttributeExpectsAValue(Range), DuplicatedAttributeArgument(Range, Range), CannotDerive(String, Range), + AttributeDoesNotExists(Range) } // TODO: A way to build an error message with methods @@ -431,7 +434,7 @@ impl Diagnostic for PassError { main: true, }], }, - PassError::AttributeDoesNotAcceptEqual(place) => DiagnosticFrame { + PassError::AttributeDoesNotExpectEqual(place) => DiagnosticFrame { code: 209, severity: Severity::Error, title: "This attribute does not support values!".to_string(), @@ -445,6 +448,20 @@ impl Diagnostic for PassError { main: true, }], }, + PassError::AttributeDoesNotExpectArgs(place) => DiagnosticFrame { + code: 209, + severity: Severity::Error, + title: "This attribute does not expect arguments".to_string(), + subtitles: vec![], + hints: vec![], + positions: vec![Marker { + position: *place, + color: Color::Fst, + text: "Try to remove all of the arguments".to_string(), + no_code: false, + main: true, + }], + }, PassError::InvalidAttributeArgument(place) => DiagnosticFrame { code: 209, severity: Severity::Error, @@ -473,6 +490,35 @@ impl Diagnostic for PassError { main: true, }], }, + + PassError::AttributeExpectsAValue(place) => DiagnosticFrame { + code: 209, + severity: Severity::Error, + title: format!("This attribute expects a value"), + subtitles: vec![], + hints: vec![], + positions: vec![Marker { + position: *place, + color: Color::Fst, + text: "Here!".to_string(), + no_code: false, + main: true, + }], + }, + PassError::AttributeDoesNotExists(place) => DiagnosticFrame { + code: 209, + severity: Severity::Error, + title: format!("This attribute does not exists"), + 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, diff --git a/src/kind-pass/src/expand/mod.rs b/src/kind-pass/src/expand/mod.rs index 3c772274..2d0823fb 100644 --- a/src/kind-pass/src/expand/mod.rs +++ b/src/kind-pass/src/expand/mod.rs @@ -75,7 +75,7 @@ pub fn expand_derive( if let Some(attr) = &attr.value { error_channel - .send(Box::new(PassError::AttributeDoesNotAcceptEqual( + .send(Box::new(PassError::AttributeDoesNotExpectEqual( attr.locate(), ))) .unwrap(); diff --git a/src/kind-tree/src/desugared/mod.rs b/src/kind-tree/src/desugared/mod.rs index 929e7134..5a9317d6 100644 --- a/src/kind-tree/src/desugared/mod.rs +++ b/src/kind-tree/src/desugared/mod.rs @@ -257,7 +257,13 @@ pub struct Rule { /// Attributes describes some compiler specific aspects /// like inlining and derivations. #[derive(Clone, Debug)] -pub enum Attribute {} +pub enum Attribute { + Inline, + KdlRun, + KdlErase, + KdlName(Ident), + KdlState(Ident), +} /// An entry describes a function that is typed /// and has rules. The type of the function