diff --git a/src/node/attribute.rs b/src/node/attribute.rs index 6db1825..9587673 100644 --- a/src/node/attribute.rs +++ b/src/node/attribute.rs @@ -2,12 +2,14 @@ use proc_macro2::TokenStream; use quote::ToTokens; use syn::{ parse::{discouraged::Speculative, Parse, ParseStream}, + parse_quote, punctuated::Punctuated, spanned::Spanned, token::{Brace, Comma, Paren}, - Attribute, Block, Expr, Lit, Pat, PatType, Token, + Attribute, Expr, Lit, Pat, PatType, Token, }; +use super::{parse::parse_valid_block_expr, InvalidBlock}; use crate::{ node::{NodeBlock, NodeName}, parser::recoverable::{ParseRecoverable, RecoverableContext}, @@ -16,8 +18,15 @@ use crate::{ #[derive(Clone, Debug, syn_derive::ToTokens)] pub struct AttributeValueExpr { pub token_eq: Token![=], - pub value: Expr, + pub value: KVAttributeValue, } + +#[derive(Clone, Debug, syn_derive::ToTokens)] +pub enum KVAttributeValue { + Expr(Expr), + Braced(InvalidBlock), +} + impl AttributeValueExpr { /// /// Returns string representation of inner value, @@ -46,7 +55,7 @@ impl AttributeValueExpr { /// Adapted from leptos pub fn value_literal_string(&self) -> Option { match &self.value { - Expr::Lit(l) => match &l.lit { + KVAttributeValue::Expr(Expr::Lit(l)) => match &l.lit { Lit::Str(s) => Some(s.value()), Lit::Char(c) => Some(c.value().to_string()), Lit::Int(i) => Some(i.base10_digits().to_string()), @@ -69,7 +78,6 @@ pub struct AttributeValueBlock { pub enum KeyedAttributeValue { Binding(FnBinding), Value(AttributeValueExpr), - Block(AttributeValueBlock), None, } @@ -79,7 +87,6 @@ impl KeyedAttributeValue { KeyedAttributeValue::Value(v) => Some(v), KeyedAttributeValue::None => None, KeyedAttributeValue::Binding(_) => None, - KeyedAttributeValue::Block(_) => None, } } } @@ -129,7 +136,13 @@ impl KeyedAttribute { } pub fn value(&self) -> Option<&Expr> { - self.possible_value.to_value().map(|v| &v.value) + self.possible_value + .to_value() + .map(|v| match &v.value { + KVAttributeValue::Expr(expr) => Some(expr), + KVAttributeValue::Braced(_) => None, + }) + .flatten() } // Checks if error is about eof. @@ -220,48 +233,8 @@ pub enum NodeAttribute { Attribute(KeyedAttribute), } -// Use custom parse to correct error. -impl Parse for KeyedAttribute { - fn parse(input: ParseStream) -> syn::Result { - let key = NodeName::parse(input)?; - let possible_value = if input.peek(Paren) { - KeyedAttributeValue::Binding(FnBinding::parse(input)?) - } else if input.peek(Token![=]) { - let eq = input.parse::()?; - if input.is_empty() { - return Err(syn::Error::new(eq.span(), "missing attribute value")); - } - - let fork = input.fork(); - let res = fork.parse::().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 - } - })?; - - input.advance_to(&fork); - KeyedAttributeValue::Value(AttributeValueExpr { - token_eq: eq, - value: res, - }) - } else { - KeyedAttributeValue::None - }; - Ok(KeyedAttribute { - key, - possible_value, - }) - } -} - impl ParseRecoverable for KeyedAttribute { fn parse_recoverable(parser: &mut RecoverableContext, input: ParseStream) -> Option { - // TODO: Make this function actually recoverable - let key = NodeName::parse(input) .map_err(|e| parser.push_diagnostic(e)) .ok()?; @@ -283,34 +256,42 @@ impl ParseRecoverable for KeyedAttribute { } let fork = input.fork(); - if let Some(res) = parser.parse_recoverable::(&fork) { - input.advance_to(&fork); - KeyedAttributeValue::Block(AttributeValueBlock { - token_eq: eq, - value: res, - }) - } else { - let res = fork - .parse::() - .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, - }) - } + let rs = match parse_valid_block_expr(parser, &fork) { + Ok(vbl) => { + input.advance_to(&fork); + KVAttributeValue::Expr(parse_quote!(#vbl)) + } + + Err(_) if input.fork().peek(Brace) => { + let ivb = parser.parse_simple(input)?; + KVAttributeValue::Braced(ivb) + } + Err(_) => { + let res = fork + .parse::() + .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); + KVAttributeValue::Expr(res) + } + }; + + KeyedAttributeValue::Value(AttributeValueExpr { + token_eq: eq, + value: rs, + }) } else { KeyedAttributeValue::None }; diff --git a/src/node/mod.rs b/src/node/mod.rs index f236cd8..ba96560 100644 --- a/src/node/mod.rs +++ b/src/node/mod.rs @@ -16,7 +16,8 @@ mod parser_ext; mod raw_text; pub use attribute::{ - AttributeValueExpr, AttributeValueBlock, FnBinding, KeyedAttribute, KeyedAttributeValue, NodeAttribute, + AttributeValueBlock, AttributeValueExpr, FnBinding, KVAttributeValue, KeyedAttribute, + KeyedAttributeValue, NodeAttribute, }; pub use node_name::{NodeName, NodeNameFragment}; pub use node_value::{InvalidBlock, NodeBlock}; diff --git a/src/node/node_value.rs b/src/node/node_value.rs index aefd6db..f908d18 100644 --- a/src/node/node_value.rs +++ b/src/node/node_value.rs @@ -8,9 +8,9 @@ use syn::{token::Brace, Block}; #[derive(Clone, Debug, syn_derive::ToTokens, syn_derive::Parse)] pub struct InvalidBlock { #[syn(braced)] - brace: Brace, + pub brace: Brace, #[syn(in = brace)] - body: TokenStream, + pub body: TokenStream, } /// Block node. diff --git a/src/node/parse.rs b/src/node/parse.rs index 7a23bb8..f0172a0 100644 --- a/src/node/parse.rs +++ b/src/node/parse.rs @@ -358,7 +358,7 @@ fn block_transform(input: ParseStream, transform_fn: &TransformBlockFn) -> syn:: } #[allow(clippy::needless_pass_by_ref_mut)] -fn parse_valid_block_expr( +pub(crate) fn parse_valid_block_expr( parser: &mut RecoverableContext, input: syn::parse::ParseStream, ) -> syn::Result { diff --git a/src/parser/recoverable.rs b/src/parser/recoverable.rs index dd7d64b..bbfbbfe 100644 --- a/src/parser/recoverable.rs +++ b/src/parser/recoverable.rs @@ -191,6 +191,7 @@ impl RecoverableContext { /// /// Result of parsing. +#[derive(Debug)] pub enum ParsingResult { /// Fully valid ast that was parsed without errors. Ok(T), diff --git a/src/visitor.rs b/src/visitor.rs index 73b992b..d2c4c2c 100644 --- a/src/visitor.rs +++ b/src/visitor.rs @@ -351,7 +351,6 @@ 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 { @@ -374,7 +373,10 @@ where visit_inner!(self.visitor.visit_attribute_value(key, value)); self.visit_node_name(key); - self.visit_rust_code(RustCode::Expr(&mut value.value)) + match &mut value.value { + KVAttributeValue::Expr(expr) => self.visit_rust_code(RustCode::Expr(expr)), + KVAttributeValue::Braced(braced) => self.visit_invalid_block(braced), + } } fn visit_attribute_block( &mut self, @@ -550,6 +552,16 @@ mod tests { assert_eq!(node_names, vec!["div", "span", "span", "foo"]); } + #[test] + fn asd() { + let a = quote! { + + }; + + let a = crate::parse2(a); + dbg!(a); + } + #[test] fn collect_rust_blocks() { #[derive(Default)]