fix: fixed some problems with attribute parsing

This commit is contained in:
felipegchi 2022-11-17 10:40:41 -03:00
parent b7bc9e9f1f
commit bbe6c14cd6
5 changed files with 146 additions and 16 deletions

View File

@ -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<Vec<AttributeStyle>, SyntaxError> {
pub fn parse_attr_args(&mut self) -> Result<(Vec<AttributeStyle>, 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<AttributeStyle, SyntaxError> {
@ -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,

View File

@ -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<desugared::Attribute> {
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<desugared::Attribute> {
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
}
}

View File

@ -33,10 +33,13 @@ pub enum PassError {
NoFieldCoverage(Range, Vec<String>),
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,

View File

@ -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();

View File

@ -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