Skip to content

Commit

Permalink
initial implementation of block attributes
Browse files Browse the repository at this point in the history
  • Loading branch information
tachibanayui authored and vldm committed Jul 28, 2024
1 parent a225580 commit 0ee7a50
Show file tree
Hide file tree
Showing 3 changed files with 93 additions and 3 deletions.
76 changes: 74 additions & 2 deletions src/node/attribute.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@ use syn::{
punctuated::Punctuated,
spanned::Spanned,
token::{Brace, Comma, Paren},
Attribute, Expr, Lit, Pat, PatType, Token,
Attribute, Block, Expr, Lit, Pat, PatType, Token,
};

use crate::{
Expand Down Expand Up @@ -59,10 +59,17 @@ impl AttributeValueExpr {
}
}

#[derive(Clone, Debug, syn_derive::ToTokens)]
pub struct AttributeValueBlock {
pub token_eq: Token![=],
pub value: NodeBlock,
}

#[derive(Clone, Debug, syn_derive::ToTokens)]
pub enum KeyedAttributeValue {
Binding(FnBinding),
Value(AttributeValueExpr),
Block(AttributeValueBlock),
None,
}

Expand All @@ -72,6 +79,7 @@ impl KeyedAttributeValue {
KeyedAttributeValue::Value(v) => Some(v),
KeyedAttributeValue::None => None,
KeyedAttributeValue::Binding(_) => None,
KeyedAttributeValue::Block(_) => None,
}
}
}
Expand Down Expand Up @@ -250,12 +258,76 @@ impl Parse for KeyedAttribute {
}
}

impl ParseRecoverable for KeyedAttribute {
fn parse_recoverable(parser: &mut RecoverableContext, input: ParseStream) -> Option<Self> {
// TODO: Make this function actually recoverable

let key = NodeName::parse(input)
.map_err(|e| parser.push_diagnostic(e))
.ok()?;

let possible_value = if input.peek(Paren) {
KeyedAttributeValue::Binding(
FnBinding::parse(input)
.map_err(|e| parser.push_diagnostic(e))
.ok()?,
)
} else if input.peek(Token![=]) {
let eq = input
.parse::<Token![=]>()
.map_err(|e| parser.push_diagnostic(e))
.ok()?;
if input.is_empty() {
parser.push_diagnostic(syn::Error::new(eq.span(), "missing attribute value"));
return None;
}

let fork = input.fork();
if let Some(res) = parser.parse_recoverable::<NodeBlock>(&fork) {
input.advance_to(&fork);
KeyedAttributeValue::Block(AttributeValueBlock {
token_eq: eq,
value: res,
})
} else {
let res = fork
.parse::<Expr>()
.map_err(|e| {
// if we stuck on end of input, span that is created will be call_site, so
// we need to correct it, in order to make it more
// IDE friendly.
if fork.is_empty() {
KeyedAttribute::correct_expr_error_span(e, input)
} else {
e
}
})
.map_err(|e| parser.push_diagnostic(e))
.ok()?;

input.advance_to(&fork);
KeyedAttributeValue::Value(AttributeValueExpr {
token_eq: eq,
value: res,
})
}
} else {
KeyedAttributeValue::None
};

Some(KeyedAttribute {
key,
possible_value,
})
}
}

impl ParseRecoverable for NodeAttribute {
fn parse_recoverable(parser: &mut RecoverableContext, input: ParseStream) -> Option<Self> {
let node = if input.peek(Brace) {
NodeAttribute::Block(parser.parse_recoverable(input)?)
} else {
NodeAttribute::Attribute(parser.parse_simple(input)?)
NodeAttribute::Attribute(parser.parse_recoverable(input)?)
};
Some(node)
}
Expand Down
2 changes: 1 addition & 1 deletion src/node/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ mod parser_ext;
mod raw_text;

pub use attribute::{
AttributeValueExpr, FnBinding, KeyedAttribute, KeyedAttributeValue, NodeAttribute,
AttributeValueExpr, AttributeValueBlock, FnBinding, KeyedAttribute, KeyedAttributeValue, NodeAttribute,
};
pub use node_name::{NodeName, NodeNameFragment};
pub use node_value::{InvalidBlock, NodeBlock};
Expand Down
18 changes: 18 additions & 0 deletions src/visitor.rs
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,13 @@ pub trait Visitor<Custom> {
) -> bool {
true
}
fn visit_attribute_block(
&mut self,
_key: &mut NodeName,
_value: &mut AttributeValueBlock,
) -> bool {
true
}
}

#[derive(Debug, Default, Clone, PartialEq, PartialOrd, Ord, Copy, Eq)]
Expand Down Expand Up @@ -344,6 +351,7 @@ where
KeyedAttributeValue::None => self.visit_attribute_flag(&mut attribute.key),
KeyedAttributeValue::Binding(b) => self.visit_attribute_binding(&mut attribute.key, b),
KeyedAttributeValue::Value(v) => self.visit_attribute_value(&mut attribute.key, v),
KeyedAttributeValue::Block(b) => self.visit_attribute_block(&mut attribute.key, b),
}
}
fn visit_attribute_flag(&mut self, key: &mut NodeName) -> bool {
Expand All @@ -368,6 +376,16 @@ where
self.visit_node_name(key);
self.visit_rust_code(RustCode::Expr(&mut value.value))
}
fn visit_attribute_block(
&mut self,
key: &mut NodeName,
value: &mut AttributeValueBlock,
) -> bool {
visit_inner!(self.visitor.visit_attribute_block(key, value));

self.visit_node_name(key);
self.visit_block(&mut value.value)
}

fn visit_invalid_block(&mut self, block: &mut InvalidBlock) -> bool {
visit_inner!(self.visitor.visit_invalid_block(block));
Expand Down

0 comments on commit 0ee7a50

Please sign in to comment.