ribir_macros 0.4.0-alpha.26

A non-intrusive declarative GUI framework, to build modern native/wasm cross-platform applications.
Documentation
use proc_macro2::{Span, TokenStream};
use quote::{ToTokens, quote_spanned};

pub enum Error {
  InvalidFieldInVar(Box<[Span]>),
  WatchNothing(Span),
  RdlAtSyntax { at: Span, follow: Option<Span> },
  IdentNotFollowDollar(Span),

  Syn(syn::Error),
}

impl Error {
  pub fn to_compile_error(&self) -> TokenStream {
    match self {
      Error::InvalidFieldInVar(fields) => {
        let mut tokens = TokenStream::new();
        for span in fields.iter() {
          quote_spanned! { *span =>
            compile_error!("Only allow to declare builtin fields in a variable parent.");
          }
          .to_tokens(&mut tokens);
        }
        tokens
      }
      Error::WatchNothing(span) => quote_spanned! { *span =>
        compile_error!("expression not subscribe anything, it must contain at least one $")
      },
      &Error::RdlAtSyntax { at, follow } => {
        let span = follow.and_then(|f| at.join(f)).unwrap_or(at);
        quote_spanned! { span => compile_error!("Syntax Error: use `@` to declare object, must be: \n 1. `@ XXX { ... }`, \
        declare a new `XXX` type object;\n 2. `@ $parent { ... }`, declare a \
        variable as parent;\n 3. `@ { ... } `, declare an object by an expression.") }
      }
      Error::IdentNotFollowDollar(span) => {
        quote_spanned! { *span => compile_error!("Syntax error: expected an identifier after `$`"); }
      }

      Error::Syn(err) => err.to_compile_error(),
    }
  }
}

pub type Result<T> = std::result::Result<T, Error>;

pub fn result_to_token_stream<T: ToTokens>(res: Result<T>) -> TokenStream {
  match res {
    Ok(value) => value.to_token_stream(),
    Err(err) => err.to_compile_error(),
  }
}

impl From<syn::Error> for Error {
  fn from(value: syn::Error) -> Self { Error::Syn(value) }
}