ribir_macros 0.4.0-alpha.3

A non-intrusive declarative GUI framework, to build modern native/wasm cross-platform applications.
Documentation
use proc_macro::TokenStream as TokenStream1;
use proc_macro2::TokenStream;
use quote::quote_spanned;
use syn::{
  fold::Fold,
  parse::{Parse, ParseStream},
  parse_macro_input,
  spanned::Spanned,
  Stmt,
};

use crate::{
  ok,
  symbol_process::{not_subscribe_anything, symbol_to_macro, DollarRefsCtx},
};

pub(crate) struct BodyExpr(pub(crate) Vec<Stmt>);

pub fn gen_code(input: TokenStream, refs_ctx: &mut DollarRefsCtx) -> TokenStream1 {
  let span = input.span();
  let input = ok!(symbol_to_macro(TokenStream1::from(input)));
  let expr = parse_macro_input! { input as BodyExpr };

  refs_ctx.new_dollar_scope(true);
  let expr = expr
    .0
    .into_iter()
    .map(|s| refs_ctx.fold_stmt(s))
    .collect::<Vec<Stmt>>();
  let refs = refs_ctx.pop_dollar_scope(true, true);
  if refs.is_empty() {
    not_subscribe_anything(span)
  } else {
    let upstream = refs.upstream_tokens();

    if refs.used_ctx() {
      quote_spanned! {span =>
        MapPipe::new(
          ModifiesPipe::new(#upstream.filter(|s| s.contains(ModifyScope::FRAMEWORK)).box_it()),
          {
            #refs
            let _ctx_handle_ಠ_ಠ = ctx!().handle();
            move |_: ModifyScope| {
              _ctx_handle_ಠ_ಠ
                .with_ctx(|ctx!(): &BuildCtx<'_>| { #(#expr)* })
                .expect("ctx is not available")
            }
          }
        )
      }
    } else {
      quote_spanned! {span =>
        MapPipe::new(
          ModifiesPipe::new(#upstream.box_it()),
          {
            #refs
            move |_: ModifyScope| { #(#expr)* }
          }
        )
      }
    }
  }
  .into()
}

impl Parse for BodyExpr {
  fn parse(input: ParseStream) -> syn::Result<Self> { Ok(Self(syn::Block::parse_within(input)?)) }
}