fn convert_print_format_args(
parsed_args: &syn::punctuated::Punctuated<syn::Expr, syn::Token![,]>,
macro_name: &str,
) -> Result<Expr> {
let first_arg = &parsed_args[0];
let fmt_value = if let SynExpr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit_str),
..
}) = first_arg
{
lit_str.value()
} else {
return Ok(Expr::FunctionCall {
name: print_macro_func_name(macro_name).to_string(),
args: vec![convert_expr(first_arg)?],
});
};
let mut expr_args = Vec::new();
for arg_expr in parsed_args.iter().skip(1) {
expr_args.push(convert_expr(arg_expr)?);
}
let segments = parse_format_string(&fmt_value);
Ok(build_format_concat(&segments, &expr_args))
}
fn convert_macro_stmt(macro_stmt: &syn::StmtMacro) -> Result<Stmt> {
let macro_path = ¯o_stmt.mac.path;
let macro_name = macro_path
.segments
.last()
.ok_or_else(|| Error::Validation("Empty macro path".to_string()))?
.ident
.to_string();
if macro_name != "println" && macro_name != "eprintln" && macro_name != "print" {
return Err(Error::Validation(format!(
"Unsupported macro: {macro_name}!"
)));
}
let tokens = macro_stmt.mac.tokens.clone();
let parsed_args: syn::punctuated::Punctuated<syn::Expr, syn::Token![,]> =
syn::punctuated::Punctuated::parse_terminated
.parse2(tokens.clone())
.map_err(|_| Error::Validation(format!("Invalid {macro_name}! arguments")))?;
let arg = if parsed_args.len() <= 1 {
let parsed: syn::Expr = syn::parse2(tokens)
.map_err(|_| Error::Validation(format!("Invalid {macro_name}! arguments")))?;
convert_expr(&parsed)?
} else {
convert_print_format_args(&parsed_args, ¯o_name)?
};
let func_name = print_macro_func_name(¯o_name);
Ok(Stmt::Expr(Expr::FunctionCall {
name: func_name.to_string(),
args: vec![arg],
}))
}
fn has_multi_stmt_branch(expr_if: &syn::ExprIf) -> bool {
if expr_if.then_branch.stmts.len() > 1 {
return true;
}
if let Some((_, else_expr)) = &expr_if.else_branch {
if let SynExpr::Block(block) = &**else_expr {
return block.block.stmts.len() > 1;
}
}
false
}
fn extract_else_value(else_expr: &SynExpr) -> Result<Expr> {
match else_expr {
SynExpr::Block(block) => extract_branch_value(&block.block),
SynExpr::If(nested_if) => convert_if_expr(nested_if),
other => convert_expr(other),
}
}
fn convert_if_expr(expr_if: &syn::ExprIf) -> Result<Expr> {
if has_multi_stmt_branch(expr_if) {
let if_stmt = convert_if_stmt(expr_if)?;
return Ok(Expr::Block(vec![if_stmt]));
}
let condition = convert_expr(&expr_if.cond)?;
let then_value = extract_branch_value(&expr_if.then_branch)?;
let else_value = if let Some((_, else_expr)) = &expr_if.else_branch {
extract_else_value(else_expr)?
} else {
Expr::Literal(Literal::Str(String::new()))
};
Ok(Expr::FunctionCall {
name: "__if_expr".to_string(),
args: vec![condition, then_value, else_value],
})
}
fn extract_branch_value(block: &syn::Block) -> Result<Expr> {
if let Some(last_stmt) = block.stmts.last() {
match last_stmt {
SynStmt::Expr(expr, None) => convert_expr(expr),
SynStmt::Expr(expr, Some(_)) => convert_expr(expr),
_ => Ok(Expr::Literal(Literal::Str(String::new()))),
}
} else {
Ok(Expr::Literal(Literal::Str(String::new())))
}
}
fn convert_if_stmt(expr_if: &syn::ExprIf) -> Result<Stmt> {
let condition = convert_expr(&expr_if.cond)?;
let then_block = convert_block(&expr_if.then_branch)?;
let else_block = convert_else_block(&expr_if.else_branch)?;
Ok(Stmt::If {
condition,
then_block,
else_block,
})
}
fn convert_else_block(
else_branch: &Option<(syn::token::Else, Box<SynExpr>)>,
) -> Result<Option<Vec<Stmt>>> {
let Some((_, else_expr)) = else_branch else {
return Ok(None);
};
match &**else_expr {
SynExpr::Block(block) => Ok(Some(convert_block(&block.block)?)),
SynExpr::If(nested_if) => convert_else_if(nested_if),
_ => Ok(None),
}
}
fn convert_else_if(nested_if: &syn::ExprIf) -> Result<Option<Vec<Stmt>>> {
let nested_condition = convert_expr(&nested_if.cond)?;
let nested_then = convert_block(&nested_if.then_branch)?;
let nested_else = convert_nested_else(&nested_if.else_branch)?;
Ok(Some(vec![Stmt::If {
condition: nested_condition,
then_block: nested_then,
else_block: nested_else,
}]))
}
fn convert_nested_else(
else_branch: &Option<(syn::token::Else, Box<SynExpr>)>,
) -> Result<Option<Vec<Stmt>>> {
let Some((_, nested_else_expr)) = else_branch else {
return Ok(None);
};
match &**nested_else_expr {
SynExpr::Block(block) => Ok(Some(convert_block(&block.block)?)),
SynExpr::If(_) => {
let stmt = SynStmt::Expr((**nested_else_expr).clone(), None);
Ok(Some(vec![convert_stmt(&stmt)?]))
}
_ => Ok(None),
}
}
fn convert_repeat_expr(expr_repeat: &syn::ExprRepeat) -> Result<Expr> {
let value = convert_expr(&expr_repeat.expr)?;
let count = if let SynExpr::Lit(lit) = &*expr_repeat.len {
if let syn::Lit::Int(lit_int) = &lit.lit {
lit_int.base10_digits().parse::<usize>().unwrap_or(1)
} else {
1
}
} else {
1
};
Ok(Expr::Array(vec![value; count]))
}
fn convert_block_expr(expr_block: &syn::ExprBlock) -> Result<Expr> {
let mut stmts = Vec::new();
for stmt in &expr_block.block.stmts {
stmts.push(convert_stmt(stmt)?);
}
Ok(Expr::Block(stmts))
}
fn convert_let_expr(expr_let: &syn::ExprLet) -> Result<Expr> {
let rhs = convert_expr(&expr_let.expr)?;
match &*expr_let.pat {
Pat::Lit(lit_pat) => {
let lhs = convert_literal_expr(&syn::ExprLit {
attrs: vec![],
lit: lit_pat.lit.clone(),
})?;
Ok(Expr::Binary {
op: BinaryOp::Eq,
left: Box::new(rhs),
right: Box::new(lhs),
})
}
_ => Ok(rhs),
}
}
fn convert_struct_expr(expr_struct: &syn::ExprStruct) -> Result<Expr> {
let mut values = Vec::new();
for field in &expr_struct.fields {
values.push(convert_expr(&field.expr)?);
}
Ok(Expr::Array(values))
}
fn convert_tuple_expr(expr_tuple: &syn::ExprTuple) -> Result<Expr> {
let mut elements = Vec::new();
for elem in &expr_tuple.elems {
elements.push(convert_expr(elem)?);
}
Ok(Expr::Array(elements))
}
fn convert_expr(expr: &SynExpr) -> Result<Expr> {
match expr {
SynExpr::Lit(expr_lit) => convert_literal_expr(expr_lit),
SynExpr::Path(expr_path) => convert_path_expr(expr_path),
SynExpr::Call(expr_call) => convert_call_expr(expr_call),
SynExpr::Binary(expr_binary) => convert_binary_expr(expr_binary),
SynExpr::Unary(expr_unary) => convert_unary_expr(expr_unary),
SynExpr::MethodCall(method_call) => convert_method_call_expr(method_call),
SynExpr::Return(ret_expr) => convert_return_expr(ret_expr),
SynExpr::Paren(expr_paren) => convert_expr(&expr_paren.expr),
SynExpr::Array(expr_array) => convert_array_expr(expr_array),
SynExpr::Reference(expr_ref) => convert_reference_expr(expr_ref),
SynExpr::If(expr_if) => convert_if_expr(expr_if),
SynExpr::Range(range_expr) => convert_range_expr(range_expr),
SynExpr::Macro(expr_macro) => convert_macro_expr(expr_macro),
SynExpr::Index(expr_index) => {
let object = convert_expr(&expr_index.expr)?;
let index = convert_expr(&expr_index.index)?;
Ok(Expr::Index {
object: Box::new(object),
index: Box::new(index),
})
}
SynExpr::Repeat(expr_repeat) => convert_repeat_expr(expr_repeat),
SynExpr::Block(expr_block) => convert_block_expr(expr_block),
SynExpr::Cast(expr_cast) => convert_expr(&expr_cast.expr),
SynExpr::Match(expr_match) => {
let match_stmt = convert_match_stmt(expr_match)?;
Ok(Expr::Block(vec![match_stmt]))
}
SynExpr::Tuple(expr_tuple) => convert_tuple_expr(expr_tuple),
SynExpr::Closure(expr_closure) => convert_expr(&expr_closure.body),
SynExpr::Let(expr_let) => convert_let_expr(expr_let),
SynExpr::Struct(expr_struct) => convert_struct_expr(expr_struct),
SynExpr::Field(expr_field) => {
let object = convert_expr(&expr_field.base)?;
Ok(Expr::Index {
object: Box::new(object),
index: Box::new(Expr::Literal(Literal::I32(0))),
})
}
_ => Err(Error::Validation("Unsupported expression type".to_string())),
}
}
fn convert_array_expr(expr_array: &syn::ExprArray) -> Result<Expr> {
let mut elements = Vec::new();
for elem in &expr_array.elems {
elements.push(convert_expr(elem)?);
}
Ok(Expr::Array(elements))
}
fn convert_reference_expr(expr_ref: &syn::ExprReference) -> Result<Expr> {
convert_expr(&expr_ref.expr)
}
fn print_macro_func_name(macro_name: &str) -> &'static str {
match macro_name {
"eprintln" => "rash_eprintln",
"print" => "rash_print",
_ => "rash_println",
}
}
fn parse_format_macro_args(parts: &[String], macro_name: &str) -> Result<Expr> {
let fmt_str = &parts[0];
let parsed = syn::parse_str::<syn::Expr>(fmt_str)
.map_err(|_| Error::Validation(format!("Could not parse {macro_name}! format string")))?;
let fmt_value = if let SynExpr::Lit(syn::ExprLit {
lit: syn::Lit::Str(lit_str),
..
}) = &parsed
{
lit_str.value()
} else {
return convert_expr(&parsed);
};
let mut expr_args = Vec::new();
for part in &parts[1..] {
let arg = syn::parse_str::<syn::Expr>(part)
.map_err(|_| Error::Validation(format!("Invalid {macro_name}! argument: {part}")))?;
expr_args.push(convert_expr(&arg)?);
}
let segments = parse_format_string(&fmt_value);
Ok(build_format_concat(&segments, &expr_args))
}
fn convert_macro_expr_format(tokens: proc_macro2::TokenStream) -> Result<Expr> {
let token_str = tokens.to_string();
let parts = split_macro_args(&token_str);
if parts.len() <= 1 {
if let Ok(parsed) = syn::parse_str::<syn::Expr>(&token_str) {
return convert_expr(&parsed);
}
return Err(Error::Validation(
"Could not parse format! arguments".to_string(),
));
}
parse_format_macro_args(&parts, "format")
}
fn convert_macro_expr_vec(tokens: proc_macro2::TokenStream) -> Result<Expr> {
let token_str = tokens.to_string();
let array_str = format!("[{token_str}]");
if let Ok(parsed) = syn::parse_str::<syn::ExprArray>(&array_str) {
return convert_array_expr(&parsed);
}
Err(Error::Validation(
"Could not parse vec! arguments".to_string(),
))
}
include!("parser_convert.rs");