Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
227 changes: 0 additions & 227 deletions src/context.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1106,233 +1106,6 @@ impl TypleContext {
Ok(())
}

fn replace_typle_fold_expr(
&self,
mac: &mut Macro,
attrs: Vec<Attribute>,
state: &mut BlockState,
default_span: Span,
) -> syn::Result<Expr> {
let mut inner_state = BlockState::default();
let token_stream = std::mem::take(&mut mac.tokens);
let mut tokens = token_stream.into_iter();
let mut init_expr =
syn::parse2::<Expr>(Self::extract_to_semicolon(&mut tokens, default_span)?)?;
self.replace_expr(&mut init_expr, &mut inner_state)?;
let (pattern, range) = self.parse_pattern_range(&mut tokens)?;
if range.is_empty() {
return Ok(Expr::Paren(syn::ExprParen {
attrs,
paren_token: token::Paren::default(),
expr: Box::new(init_expr),
}));
}
let fold_ident = Self::parse_fold_ident(&mut tokens, default_span)?;
let fold_pat = Pat::Ident(syn::PatIdent {
attrs: Vec::new(),
by_ref: None,
mutability: None,
ident: fold_ident.clone(),
subpat: None,
});
let expr = syn::parse2::<Expr>(tokens.collect())?;
let mut stmts = Vec::with_capacity(range.len() + 2);
stmts.push(Stmt::Local(syn::Local {
attrs: Vec::new(),
let_token: token::Let::default(),
pat: fold_pat.clone(),
init: Some(syn::LocalInit {
eq_token: token::Eq::default(),
expr: Box::new(init_expr),
diverge: None,
}),
semi_token: token::Semi::default(),
}));
if !range.is_empty() {
let mut ctx = pattern.as_ref().map(|ident| {
let mut context = self.clone();
context.constants.insert(ident.clone(), 0);
(context, ident)
});
for (index, mut expr) in range.zip_clone(expr) {
if let Some((ref mut context, ident)) = ctx {
*context.constants.get_mut(ident).unwrap() = index;
}
let context = ctx.as_ref().map_or(self, |c| &c.0);
context.replace_expr(&mut expr, &mut inner_state)?;
stmts.push(Stmt::Local(syn::Local {
attrs: Vec::new(),
let_token: token::Let::default(),
pat: fold_pat.clone(),
init: Some(syn::LocalInit {
eq_token: token::Eq::default(),
expr: Box::new(expr),
diverge: None,
}),
semi_token: token::Semi::default(),
}));
}
}
if let Some(span) = inner_state.unlabelled_continue {
abort!(
span,
"unlabelled `continue` not supported in `typle_fold!` macro"
);
}
state.propagate(inner_state, None);
stmts.push(Stmt::Expr(
Expr::Break(syn::ExprBreak {
attrs: Vec::new(),
break_token: token::Break::default(),
label: None,
expr: Some(Box::new(Expr::Path(syn::PatPath {
attrs: Vec::new(),
qself: None,
path: ident_to_path(fold_ident),
}))),
}),
Some(token::Semi::default()),
));
// The fold may be used in an expression `typle_fold!() + ...`, in which
// case the loop needs to be in parentheses.
Ok(Expr::Paren(syn::ExprParen {
attrs,
paren_token: token::Paren::default(),
expr: Box::new(Expr::Loop(syn::ExprLoop {
attrs: Vec::new(),
label: None,
loop_token: token::Loop::default(),
body: Block {
brace_token: token::Brace::default(),
stmts,
},
})),
}))
}

fn replace_macro_expr(
&self,
mac: &mut Macro,
attrs: &mut Vec<Attribute>,
state: &mut BlockState,
) -> syn::Result<Option<Expr>> {
self.replace_attrs(attrs)?;
if let Some(macro_name) = mac.path.get_ident() {
let default_span = macro_name.span();
if macro_name == "typle" {
// This is outside a comma-separated sequence so only no-range form is accepted
// typle!(=> if T::LEN == 0 {} else {})
let token_stream = std::mem::take(&mut mac.tokens);
return self.expand_typle_macro_singleton(token_stream, |context, token_stream| {
let mut expr = syn::parse2::<Expr>(token_stream)?;
let mut state = BlockState::default();
context.replace_expr(&mut expr, &mut state)?;
Ok(Some(expr))
});
} else if macro_name == "typle_fold" {
let expr =
self.replace_typle_fold_expr(mac, std::mem::take(attrs), state, default_span)?;
return Ok(Some(expr));
} else if macro_name == "typle_all" {
let token_stream = std::mem::take(&mut mac.tokens);
let expr = self.anyall(
token_stream,
state,
BinOp::And(token::AndAnd::default()),
true,
)?;
return Ok(Some(expr));
} else if macro_name == "typle_any" {
let token_stream = std::mem::take(&mut mac.tokens);
let expr = self.anyall(
token_stream,
state,
BinOp::Or(token::OrOr::default()),
false,
)?;
return Ok(Some(expr));
}
}
mac.tokens = self.replace_macro_token_stream(std::mem::take(&mut mac.tokens))?;
Ok(None)
}

fn anyall(
&self,
token_stream: TokenStream,
state: &mut BlockState,
op: BinOp,
default: bool,
) -> syn::Result<Expr> {
let mut tokens = token_stream.into_iter();
let (pattern, mut range) = self.parse_pattern_range(&mut tokens)?;
let expr = syn::parse2::<Expr>(tokens.collect())?;
let all = match range.next() {
Some(index) => {
// Parenthesize low precedence expressions.
let expr = match expr {
expr @ Expr::Lit(syn::PatLit {
lit: Lit::Bool(_), ..
}) => expr,
expr @ Expr::Block(_) => expr,
expr @ Expr::Paren(_) => expr,
expr @ Expr::Path(_) => expr,
expr @ Expr::MethodCall(_) => expr,
expr @ Expr::Field(_) => expr,
expr @ Expr::Call(_) => expr,
expr @ Expr::Index(_) => expr,
expr @ Expr::Unary(_) => expr,
expr @ Expr::Cast(_) => expr,
expr => Expr::Paren(syn::ExprParen {
attrs: Vec::new(),
paren_token: token::Paren::default(),
expr: Box::new(expr),
}),
};

let mut context = self.clone();
if let Some(ident) = &pattern {
context.constants.insert(ident.clone(), index);
}
let mut all = expr.clone();
context.replace_expr(&mut all, state)?;
for (index, mut expr) in range.zip_clone(expr) {
if let Some(ident) = &pattern {
*context.constants.get_mut(ident).unwrap() = index;
}
context.replace_expr(&mut expr, state)?;
all = Expr::Binary(syn::ExprBinary {
attrs: Vec::new(),
left: Box::new(all),
op,
right: Box::new(expr),
});
}
if let Expr::Binary(expr) = all {
// Wrap entire expression in parentheses to:
// 1. ensure that it is a single expression in a larger expression.
// 2. handle ambiguity: `{ true } || { true }` is not a boolean expression.
// It is a block followed by a closure that returns a boolean. Adding
// parentheses `({ true } || { true })` makes it a boolean expression.
all = Expr::Paren(syn::ExprParen {
attrs: Vec::new(),
paren_token: token::Paren::default(),
expr: Box::new(Expr::Binary(expr)),
});
}
all
}
None => Expr::Lit(syn::PatLit {
attrs: Vec::new(),
lit: Lit::Bool(syn::LitBool {
value: default,
span: expr.span(),
}),
}),
};
Ok(all)
}

// Look for `typle_ty!(...)` or `typle_expr!(...)` and evaluate body.
fn replace_macro_token_stream(&self, input: TokenStream) -> syn::Result<TokenStream> {
enum TTState {
Expand Down
Loading