node.rs 2.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384
  1. use super::*;
  2. use proc_macro2::TokenStream as TokenStream2;
  3. use quote::{quote, ToTokens, TokenStreamExt};
  4. use syn::{
  5. parse::{Parse, ParseStream},
  6. token, Expr, LitStr, Result, Token,
  7. };
  8. /*
  9. Parse
  10. -> div {}
  11. -> Component {}
  12. -> component()
  13. -> "text {with_args}"
  14. -> (0..10).map(|f| rsx!("asd")), // <--- notice the comma - must be a complete expr
  15. */
  16. pub enum BodyNode {
  17. Element(Element),
  18. Component(Component),
  19. Text(LitStr),
  20. RawExpr(Expr),
  21. }
  22. impl Parse for BodyNode {
  23. fn parse(stream: ParseStream) -> Result<Self> {
  24. if stream.peek(LitStr) {
  25. return Ok(BodyNode::Text(stream.parse()?));
  26. }
  27. // div {} -> el
  28. // Div {} -> comp
  29. if stream.peek(syn::Ident) && stream.peek2(token::Brace) {
  30. if stream
  31. .fork()
  32. .parse::<Ident>()?
  33. .to_string()
  34. .chars()
  35. .next()
  36. .unwrap()
  37. .is_ascii_uppercase()
  38. {
  39. return Ok(BodyNode::Component(stream.parse()?));
  40. } else {
  41. return Ok(BodyNode::Element(stream.parse::<Element>()?));
  42. }
  43. }
  44. // component() -> comp
  45. // ::component {} -> comp
  46. // ::component () -> comp
  47. if (stream.peek(syn::Ident) && stream.peek2(token::Paren))
  48. || (stream.peek(Token![::]))
  49. || (stream.peek(Token![:]) && stream.peek2(Token![:]))
  50. {
  51. return Ok(BodyNode::Component(stream.parse::<Component>()?));
  52. }
  53. // crate::component{} -> comp
  54. // crate::component() -> comp
  55. if let Ok(pat) = stream.fork().parse::<syn::Path>() {
  56. if pat.segments.len() > 1 {
  57. return Ok(BodyNode::Component(stream.parse::<Component>()?));
  58. }
  59. }
  60. Ok(BodyNode::RawExpr(stream.parse::<Expr>()?))
  61. }
  62. }
  63. impl ToTokens for BodyNode {
  64. fn to_tokens(&self, tokens: &mut TokenStream2) {
  65. match &self {
  66. BodyNode::Element(el) => el.to_tokens(tokens),
  67. BodyNode::Component(comp) => comp.to_tokens(tokens),
  68. BodyNode::Text(txt) => tokens.append_all(quote! {
  69. __cx.text(format_args_f!(#txt))
  70. }),
  71. BodyNode::RawExpr(exp) => tokens.append_all(quote! {
  72. __cx.fragment_from_iter(#exp)
  73. }),
  74. }
  75. }
  76. }