#![allow(clippy::approx_constant)]
#[path = "dispatcher_helpers/macro_helpers.rs"]
mod macro_helpers;
#[path = "dispatcher_helpers/identifiers.rs"]
mod identifiers;
#[path = "dispatcher_helpers/misc.rs"]
mod misc;
use super::Transpiler;
use crate::frontend::ast::{Expr, ExprKind};
use anyhow::{bail, Result};
use proc_macro2::TokenStream;
use quote::{format_ident, quote};
impl Transpiler {
pub(super) fn transpile_basic_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::Literal(lit) => Ok(Self::transpile_literal(lit)),
ExprKind::Identifier(name) => Ok(self.transpile_identifier(name)),
ExprKind::QualifiedName { module, name } => {
Ok(Self::transpile_qualified_name(module, name))
}
ExprKind::StringInterpolation { parts } => self.transpile_string_interpolation(parts),
ExprKind::TypeCast { expr, target_type } => self.transpile_type_cast(expr, target_type),
_ => unreachable!("Non-basic expression in transpile_basic_expr"),
}
}
pub(super) fn transpile_operator_control_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::Binary { .. }
| ExprKind::Unary { .. }
| ExprKind::Assign { .. }
| ExprKind::CompoundAssign { .. }
| ExprKind::PreIncrement { .. }
| ExprKind::PostIncrement { .. }
| ExprKind::PreDecrement { .. }
| ExprKind::PostDecrement { .. }
| ExprKind::Await { .. }
| ExprKind::Spawn { .. }
| ExprKind::AsyncBlock { .. }
| ExprKind::AsyncLambda { .. } => self.transpile_operator_only_expr(expr),
ExprKind::If { .. }
| ExprKind::IfLet { .. }
| ExprKind::WhileLet { .. }
| ExprKind::Match { .. }
| ExprKind::For { .. }
| ExprKind::While { .. }
| ExprKind::Loop { .. }
| ExprKind::TryCatch { .. } => self.transpile_control_flow_only_expr(expr),
_ => unreachable!("Non-operator/control expression in transpile_operator_control_expr"),
}
}
fn transpile_operator_only_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::Binary { left, op, right } => self.transpile_binary(left, *op, right),
ExprKind::Unary { op, operand } => self.transpile_unary(*op, operand),
ExprKind::Assign { target, value } => self.transpile_assign(target, value),
ExprKind::CompoundAssign { target, op, value } => {
self.transpile_compound_assign(target, *op, value)
}
ExprKind::PreIncrement { target } => self.transpile_pre_increment(target),
ExprKind::PostIncrement { target } => self.transpile_post_increment(target),
ExprKind::PreDecrement { target } => self.transpile_pre_decrement(target),
ExprKind::PostDecrement { target } => self.transpile_post_decrement(target),
ExprKind::Await { expr } => self.transpile_await(expr),
ExprKind::Spawn { actor } => self.transpile_spawn(actor),
ExprKind::AsyncBlock { body } => self.transpile_async_block(body),
ExprKind::AsyncLambda { params, body } => self.transpile_async_lambda(params, body),
_ => unreachable!(),
}
}
fn transpile_control_flow_only_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::If {
condition,
then_branch,
else_branch,
} => self.transpile_if(condition, then_branch, else_branch.as_deref()),
ExprKind::Match { expr, arms } => self.transpile_match(expr, arms),
ExprKind::For {
var,
pattern,
iter,
body,
..
} => self.transpile_for(var, pattern.as_ref(), iter, body),
ExprKind::While {
condition, body, ..
} => self.transpile_while(condition, body),
ExprKind::IfLet {
pattern,
expr,
then_branch,
else_branch,
} => self.transpile_if_let(pattern, expr, then_branch, else_branch.as_deref()),
ExprKind::WhileLet {
pattern,
expr,
body,
..
} => self.transpile_while_let(pattern, expr, body),
ExprKind::Loop { body, .. } => self.transpile_loop(body),
ExprKind::TryCatch {
try_block,
catch_clauses,
finally_block,
} => self.transpile_try_catch(try_block, catch_clauses, finally_block.as_deref()),
_ => unreachable!(),
}
}
pub(super) fn transpile_function_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::Function {
name,
type_params,
params,
body,
is_async,
return_type,
is_pub,
} => self.transpile_function(
name,
type_params,
params,
body,
*is_async,
return_type.as_ref(),
*is_pub,
&expr.attributes,
),
ExprKind::Lambda { params, body } => self.transpile_lambda(params, body),
ExprKind::Call { func, args } => self.transpile_call(func, args),
ExprKind::MethodCall {
receiver,
method,
args,
} => self.transpile_method_call(receiver, method, args),
ExprKind::Macro { name, args } => self.transpile_macro(name, args),
_ => unreachable!("Non-function expression in transpile_function_expr"),
}
}
pub(super) fn transpile_macro(&self, name: &str, args: &[Expr]) -> Result<TokenStream> {
match name {
"println" => self.transpile_println_macro(args),
"print" => self.transpile_print_macro(args),
"panic" => self.transpile_panic_macro(args),
"vec" => self.transpile_vec_macro(args),
"assert" => self.transpile_assert_macro(args),
"assert_eq" => self.transpile_assert_eq_macro(args),
"assert_ne" => self.transpile_assert_ne_macro(args),
"json" | "sql" | "format" | "dbg" | "include_str" | "include_bytes" | "todo"
| "unimplemented" | "unreachable" | "compile_error" | "concat" | "env"
| "option_env" | "cfg" | "column" | "file" | "line" | "module_path" | "stringify"
| "write" | "writeln" | "eprintln" | "eprint" => {
self.transpile_passthrough_macro(name, args)
}
_ => bail!("Unknown macro: {name}"),
}
}
pub(super) fn transpile_struct_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::Struct {
name,
type_params,
fields,
methods,
derives,
is_pub,
} => self.transpile_struct_with_methods(
name,
type_params,
fields,
methods,
derives,
*is_pub,
),
ExprKind::TupleStruct {
name,
type_params,
fields,
derives,
is_pub,
} => self.transpile_tuple_struct(name, type_params, fields, derives, *is_pub),
ExprKind::Class {
name,
type_params,
superclass: _, traits,
fields,
constructors,
methods,
constants,
properties: _, derives,
is_pub,
is_sealed: _, is_abstract: _, decorators: _, } => self.transpile_class(
name,
type_params,
traits,
fields,
constructors,
methods,
constants,
derives,
*is_pub,
),
ExprKind::StructLiteral { name, fields, base } => {
self.transpile_struct_literal(name, fields, base.as_deref())
}
ExprKind::ObjectLiteral { fields } => self.transpile_object_literal(fields),
ExprKind::FieldAccess { object, field } => self.transpile_field_access(object, field),
ExprKind::IndexAccess { object, index } => self.transpile_index_access(object, index),
ExprKind::Slice { object, start, end } => {
self.transpile_slice(object, start.as_deref(), end.as_deref())
}
_ => unreachable!("Non-struct expression in transpile_struct_expr"),
}
}
pub(super) fn transpile_data_error_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::DataFrame { .. }
| ExprKind::DataFrameOperation { .. }
| ExprKind::List(_)
| ExprKind::Set(_)
| ExprKind::ArrayInit { .. }
| ExprKind::Tuple(_)
| ExprKind::ListComprehension { .. }
| ExprKind::SetComprehension { .. }
| ExprKind::DictComprehension { .. }
| ExprKind::Range { .. } => self.transpile_data_only_expr(expr),
ExprKind::Throw { .. }
| ExprKind::Ok { .. }
| ExprKind::Err { .. }
| ExprKind::Some { .. }
| ExprKind::None
| ExprKind::Try { .. } => self.transpile_error_only_expr(expr),
_ => unreachable!("Non-data/error expression in transpile_data_error_expr"),
}
}
fn transpile_data_only_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::DataFrame { columns } => self.transpile_dataframe(columns),
ExprKind::DataFrameOperation { source, operation } => {
self.transpile_dataframe_operation(source, operation)
}
ExprKind::List(elements) => self.transpile_list(elements),
ExprKind::Set(elements) => {
if elements.len() == 1 && !self.looks_like_real_set(&elements[0]) {
eprintln!("DEBUG: Set detected as misparsed Block, transpiling as expression");
self.transpile_expr(&elements[0])
} else {
self.transpile_set(elements)
}
}
ExprKind::ArrayInit { value, size } => self.transpile_array_init(value, size),
ExprKind::Tuple(elements) => self.transpile_tuple(elements),
ExprKind::ListComprehension { element, clauses } => {
self.transpile_list_comprehension_new(element, clauses)
}
ExprKind::SetComprehension { element, clauses } => {
self.transpile_set_comprehension_new(element, clauses)
}
ExprKind::DictComprehension {
key,
value,
clauses,
} => self.transpile_dict_comprehension_new(key, value, clauses),
ExprKind::Range {
start,
end,
inclusive,
} => self.transpile_range(start, end, *inclusive),
_ => unreachable!(),
}
}
fn transpile_error_only_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::Throw { expr } => self.transpile_throw(expr),
ExprKind::Ok { value } => self.transpile_result_ok(value),
ExprKind::Err { error } => self.transpile_result_err(error),
ExprKind::Some { value } => self.transpile_option_some(value),
ExprKind::None => Ok(quote! { None }),
ExprKind::Try { expr } => self.transpile_try_operator(expr),
_ => unreachable!(),
}
}
fn transpile_result_ok(&self, value: &Expr) -> Result<TokenStream> {
let value_tokens = self.transpile_expr(value)?;
let final_tokens = match &value.kind {
ExprKind::Literal(crate::frontend::ast::Literal::String(_)) => {
quote! { #value_tokens.to_string() }
}
_ => value_tokens,
};
Ok(quote! { Ok(#final_tokens) })
}
fn transpile_result_err(&self, error: &Expr) -> Result<TokenStream> {
let error_tokens = self.transpile_expr(error)?;
let final_tokens = match &error.kind {
ExprKind::Literal(crate::frontend::ast::Literal::String(_)) => {
quote! { #error_tokens.to_string() }
}
_ => error_tokens,
};
Ok(quote! { Err(#final_tokens) })
}
fn transpile_option_some(&self, value: &Expr) -> Result<TokenStream> {
let value_tokens = self.transpile_expr(value)?;
let final_tokens = match &value.kind {
ExprKind::Literal(crate::frontend::ast::Literal::String(_)) => {
quote! { #value_tokens.to_string() }
}
_ => value_tokens,
};
Ok(quote! { Some(#final_tokens) })
}
fn transpile_try_operator(&self, expr: &Expr) -> Result<TokenStream> {
let expr_tokens = self.transpile_expr(expr)?;
Ok(quote! { #expr_tokens? })
}
pub(super) fn transpile_actor_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::Actor {
name,
state,
handlers,
} => self.transpile_actor(name, state, handlers),
ExprKind::Effect { name, operations } => self.transpile_effect(name, operations),
ExprKind::Handle { expr, handlers } => self.transpile_handler(expr, handlers),
ExprKind::Send { actor, message } | ExprKind::ActorSend { actor, message } => {
self.transpile_send(actor, message)
}
ExprKind::Ask {
actor,
message,
timeout,
} => self.transpile_ask(actor, message, timeout.as_deref()),
ExprKind::ActorQuery { actor, message } => {
self.transpile_ask(actor, message, None)
}
ExprKind::Command {
program,
args,
env,
working_dir,
} => self.transpile_command(program, args, env, working_dir),
_ => unreachable!("Non-actor expression in transpile_actor_expr"),
}
}
pub(super) fn transpile_misc_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::Let {
name,
type_annotation,
value,
body,
is_mutable,
else_block,
} => {
if let Some(else_expr) = else_block {
self.transpile_let_else(name, value, body, else_expr)
} else {
let is_const = expr.attributes.iter().any(|attr| attr.name == "const");
self.transpile_let_with_type(
name,
type_annotation.as_ref(),
value,
body,
*is_mutable,
is_const,
)
}
}
ExprKind::LetPattern {
pattern,
type_annotation,
value,
body,
is_mutable: _,
else_block,
} => {
if let Some(else_expr) = else_block {
self.transpile_let_pattern_else(pattern, value, body, else_expr)
} else {
self.transpile_let_pattern_with_type(
pattern,
type_annotation.as_ref(),
value,
body,
)
}
}
ExprKind::Block(exprs) => self.transpile_block(exprs),
ExprKind::Pipeline { expr, stages } => self.transpile_pipeline(expr, stages),
ExprKind::Lazy { expr } => {
self.transpile_expr(expr)
}
ExprKind::Import { module, items } => {
let has_pub = expr.attributes.iter().any(|attr| attr.name == "pub");
let import_tokens = Self::transpile_import(module, items.as_deref());
if has_pub {
Ok(quote! { pub #import_tokens })
} else {
Ok(import_tokens)
}
}
ExprKind::ImportAll { module, alias } => {
let has_pub = expr.attributes.iter().any(|attr| attr.name == "pub");
let import_tokens = Self::transpile_import_all(module, alias);
if has_pub {
Ok(quote! { pub #import_tokens })
} else {
Ok(import_tokens)
}
}
ExprKind::ImportDefault { module, name } => {
Ok(Self::transpile_import_default(module, name))
}
ExprKind::ReExport { items, module } => Ok(Self::transpile_reexport(items, module)),
ExprKind::Module { name, body } => self.transpile_module(name, body),
ExprKind::ModuleDeclaration { name } => {
Ok(self.transpile_external_mod_declaration(name, expr))
}
ExprKind::Trait { .. }
| ExprKind::Impl { .. }
| ExprKind::Extension { .. }
| ExprKind::Enum { .. }
| ExprKind::TypeAlias { .. } => self.transpile_type_decl_expr(expr),
ExprKind::Break { .. } | ExprKind::Continue { .. } | ExprKind::Return { .. } => {
self.transpile_control_misc_expr(expr)
}
ExprKind::Export { expr, is_default } => Ok(Self::transpile_export(expr, *is_default)),
ExprKind::ExportList { names } => Ok(Self::transpile_export_list(names)),
ExprKind::ExportDefault { expr } => Ok(Self::transpile_export_default(expr)),
ExprKind::VecRepeat { value, count } => self.transpile_vec_repeat(value, count),
ExprKind::MacroInvocation { name, args } => self.transpile_macro(name, args),
_ => bail!("Unsupported expression kind: {:?}", expr.kind),
}
}
pub(crate) fn transpile_type_decl_expr(&self, expr: &Expr) -> Result<TokenStream> {
match &expr.kind {
ExprKind::Trait {
name,
type_params,
associated_types,
methods,
is_pub,
} => self.transpile_trait(name, type_params, associated_types, methods, *is_pub),
ExprKind::Impl {
type_params,
trait_name,
for_type,
methods,
is_pub,
} => self.transpile_impl(
for_type,
type_params,
trait_name.as_deref(),
methods,
*is_pub,
),
ExprKind::Extension {
target_type,
methods,
} => self.transpile_extend(target_type, methods),
ExprKind::Enum {
name,
type_params,
variants,
is_pub,
} => self.transpile_enum(name, type_params, variants, *is_pub),
ExprKind::TypeAlias { name, target_type } => {
let name_ident = format_ident!("{}", name);
let type_tokens = self.transpile_type(target_type)?;
Ok(quote! { type #name_ident = #type_tokens; })
}
_ => unreachable!(),
}
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::frontend::ast::{Expr, ExprKind, Literal, Span};
#[test]
fn test_transpile_basic_expr_literal() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Literal(Literal::Integer(42, None)),
Span::default(),
);
let result = transpiler.transpile_basic_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("42"));
}
#[test]
fn test_transpile_basic_expr_identifier() {
let transpiler = Transpiler::new();
let expr = Expr::new(ExprKind::Identifier("my_var".to_string()), Span::default());
let result = transpiler.transpile_basic_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("my_var"));
}
#[test]
fn test_transpile_basic_expr_qualified_name() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::QualifiedName {
module: "std::collections".to_string(),
name: "HashMap".to_string(),
},
Span::default(),
);
let result = transpiler.transpile_basic_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("HashMap"));
}
#[test]
fn test_transpile_basic_expr_string_interpolation() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::StringInterpolation { parts: vec![] },
Span::default(),
);
let result = transpiler.transpile_basic_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_macro_unknown_error() {
let transpiler = Transpiler::new();
let result = transpiler.transpile_macro("unknown_macro", &[]);
assert!(result.is_err());
assert!(result.unwrap_err().to_string().contains("Unknown macro"));
}
#[test]
fn test_transpile_macro_println() {
let transpiler = Transpiler::new();
let result = transpiler.transpile_macro("println", &[]);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("println"));
}
#[test]
fn test_transpile_macro_vec() {
let transpiler = Transpiler::new();
let elem = Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
);
let result = transpiler.transpile_macro("vec", &[elem]);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("vec"));
}
#[test]
fn test_transpile_macro_assert() {
let transpiler = Transpiler::new();
let condition = Expr::new(ExprKind::Literal(Literal::Bool(true)), Span::default());
let result = transpiler.transpile_macro("assert", &[condition]);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("assert"));
}
#[test]
fn test_transpile_macro_passthrough_json() {
let transpiler = Transpiler::new();
let result = transpiler.transpile_macro("json", &[]);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("json"));
}
#[test]
fn test_transpile_result_ok_integer() {
let transpiler = Transpiler::new();
let value = Expr::new(
ExprKind::Literal(Literal::Integer(42, None)),
Span::default(),
);
let result = transpiler.transpile_result_ok(&value);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("Ok"));
assert!(tokens.contains("42"));
}
#[test]
fn test_transpile_result_ok_string_conversion() {
let transpiler = Transpiler::new();
let value = Expr::new(
ExprKind::Literal(Literal::String("hello".to_string())),
Span::default(),
);
let result = transpiler.transpile_result_ok(&value);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("Ok"));
assert!(tokens.contains("to_string"));
}
#[test]
fn test_transpile_result_err_integer() {
let transpiler = Transpiler::new();
let error = Expr::new(
ExprKind::Literal(Literal::Integer(404, None)),
Span::default(),
);
let result = transpiler.transpile_result_err(&error);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("Err"));
assert!(tokens.contains("404"));
}
#[test]
fn test_transpile_result_err_string_conversion() {
let transpiler = Transpiler::new();
let error = Expr::new(
ExprKind::Literal(Literal::String("error message".to_string())),
Span::default(),
);
let result = transpiler.transpile_result_err(&error);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("Err"));
assert!(tokens.contains("to_string"));
}
#[test]
fn test_transpile_option_some_integer() {
let transpiler = Transpiler::new();
let value = Expr::new(
ExprKind::Literal(Literal::Integer(123, None)),
Span::default(),
);
let result = transpiler.transpile_option_some(&value);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("Some"));
assert!(tokens.contains("123"));
}
#[test]
fn test_transpile_option_some_string_conversion() {
let transpiler = Transpiler::new();
let value = Expr::new(
ExprKind::Literal(Literal::String("value".to_string())),
Span::default(),
);
let result = transpiler.transpile_option_some(&value);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("Some"));
assert!(tokens.contains("to_string"));
}
#[test]
fn test_transpile_try_operator() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Identifier("result_value".to_string()),
Span::default(),
);
let result = transpiler.transpile_try_operator(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("result_value"));
assert!(tokens.contains('?'));
}
#[test]
fn test_transpile_error_only_expr_none() {
let transpiler = Transpiler::new();
let expr = Expr::new(ExprKind::None, Span::default());
let result = transpiler.transpile_error_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("None"));
}
#[test]
fn test_transpile_error_only_expr_ok() {
let transpiler = Transpiler::new();
let value = Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
));
let expr = Expr::new(ExprKind::Ok { value }, Span::default());
let result = transpiler.transpile_error_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("Ok"));
}
#[test]
fn test_transpile_error_only_expr_err() {
let transpiler = Transpiler::new();
let error = Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
));
let expr = Expr::new(ExprKind::Err { error }, Span::default());
let result = transpiler.transpile_error_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("Err"));
}
#[test]
fn test_transpile_error_only_expr_some() {
let transpiler = Transpiler::new();
let value = Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
));
let expr = Expr::new(ExprKind::Some { value }, Span::default());
let result = transpiler.transpile_error_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("Some"));
}
#[test]
fn test_transpile_operator_control_expr_binary() {
use crate::frontend::ast::BinaryOp;
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Binary {
left: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
)),
op: BinaryOp::Add,
right: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(2, None)),
Span::default(),
)),
},
Span::default(),
);
let result = transpiler.transpile_operator_control_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_operator_control_expr_if() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::If {
condition: Box::new(Expr::new(
ExprKind::Literal(Literal::Bool(true)),
Span::default(),
)),
then_branch: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
)),
else_branch: None,
},
Span::default(),
);
let result = transpiler.transpile_operator_control_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_operator_control_expr_await() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Await {
expr: Box::new(Expr::new(
ExprKind::Identifier("future".to_string()),
Span::default(),
)),
},
Span::default(),
);
let result = transpiler.transpile_operator_control_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_operator_only_expr_binary() {
use crate::frontend::ast::BinaryOp;
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Binary {
left: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(5, None)),
Span::default(),
)),
op: BinaryOp::Multiply,
right: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(3, None)),
Span::default(),
)),
},
Span::default(),
);
let result = transpiler.transpile_operator_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains('5') && tokens.contains('3'));
}
#[test]
fn test_transpile_operator_only_expr_unary() {
use crate::frontend::ast::UnaryOp;
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Unary {
op: UnaryOp::Negate,
operand: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(5, None)),
Span::default(),
)),
},
Span::default(),
);
let result = transpiler.transpile_operator_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains('-'));
}
#[test]
fn test_transpile_operator_only_expr_assign() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Assign {
target: Box::new(Expr::new(
ExprKind::Identifier("x".to_string()),
Span::default(),
)),
value: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(10, None)),
Span::default(),
)),
},
Span::default(),
);
let result = transpiler.transpile_operator_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains('x'));
}
#[test]
fn test_transpile_operator_only_expr_compound_assign() {
use crate::frontend::ast::BinaryOp;
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::CompoundAssign {
target: Box::new(Expr::new(
ExprKind::Identifier("count".to_string()),
Span::default(),
)),
op: BinaryOp::Add,
value: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
)),
},
Span::default(),
);
let result = transpiler.transpile_operator_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("count"));
}
#[test]
fn test_transpile_operator_only_expr_pre_increment() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::PreIncrement {
target: Box::new(Expr::new(
ExprKind::Identifier("i".to_string()),
Span::default(),
)),
},
Span::default(),
);
let result = transpiler.transpile_operator_only_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_control_flow_only_expr_if() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::If {
condition: Box::new(Expr::new(
ExprKind::Literal(Literal::Bool(true)),
Span::default(),
)),
then_branch: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
)),
else_branch: Some(Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(0, None)),
Span::default(),
))),
},
Span::default(),
);
let result = transpiler.transpile_control_flow_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("if"));
}
#[test]
fn test_transpile_control_flow_only_expr_match() {
use crate::frontend::ast::{MatchArm, Pattern};
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Match {
expr: Box::new(Expr::new(
ExprKind::Identifier("x".to_string()),
Span::default(),
)),
arms: vec![MatchArm {
pattern: Pattern::Wildcard,
guard: None,
body: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
)),
span: Span::default(),
}],
},
Span::default(),
);
let result = transpiler.transpile_control_flow_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("match"));
}
#[test]
fn test_transpile_control_flow_only_expr_for() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::For {
var: "i".to_string(),
pattern: None,
iter: Box::new(Expr::new(
ExprKind::Identifier("items".to_string()),
Span::default(),
)),
body: Box::new(Expr::new(ExprKind::Block(vec![]), Span::default())),
label: None,
},
Span::default(),
);
let result = transpiler.transpile_control_flow_only_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_control_flow_only_expr_while() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::While {
condition: Box::new(Expr::new(
ExprKind::Literal(Literal::Bool(true)),
Span::default(),
)),
body: Box::new(Expr::new(ExprKind::Block(vec![]), Span::default())),
label: None,
},
Span::default(),
);
let result = transpiler.transpile_control_flow_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("while"));
}
#[test]
fn test_transpile_control_flow_only_expr_loop() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Loop {
body: Box::new(Expr::new(ExprKind::Block(vec![]), Span::default())),
label: None,
},
Span::default(),
);
let result = transpiler.transpile_control_flow_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("loop"));
}
#[test]
fn test_transpile_control_flow_only_expr_if_let() {
use crate::frontend::ast::Pattern;
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::IfLet {
pattern: Pattern::Wildcard,
expr: Box::new(Expr::new(
ExprKind::Identifier("opt".to_string()),
Span::default(),
)),
then_branch: Box::new(Expr::new(ExprKind::Block(vec![]), Span::default())),
else_branch: None,
},
Span::default(),
);
let result = transpiler.transpile_control_flow_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("if") && tokens.contains("let"));
}
#[test]
fn test_transpile_control_flow_only_expr_while_let() {
use crate::frontend::ast::Pattern;
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::WhileLet {
pattern: Pattern::Wildcard,
expr: Box::new(Expr::new(
ExprKind::Identifier("iter".to_string()),
Span::default(),
)),
body: Box::new(Expr::new(ExprKind::Block(vec![]), Span::default())),
label: None,
},
Span::default(),
);
let result = transpiler.transpile_control_flow_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("while") && tokens.contains("let"));
}
#[test]
fn test_transpile_data_only_expr_list() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::List(vec![
Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
),
Expr::new(
ExprKind::Literal(Literal::Integer(2, None)),
Span::default(),
),
]),
Span::default(),
);
let result = transpiler.transpile_data_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("vec") || tokens.contains("1") || tokens.contains("2"));
}
#[test]
fn test_transpile_data_only_expr_set() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Set(vec![
Expr::new(
ExprKind::Literal(Literal::Integer(10, None)),
Span::default(),
),
Expr::new(
ExprKind::Literal(Literal::Integer(20, None)),
Span::default(),
),
]),
Span::default(),
);
let result = transpiler.transpile_data_only_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_data_only_expr_tuple() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Tuple(vec![
Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
),
Expr::new(
ExprKind::Literal(Literal::String("hello".to_string())),
Span::default(),
),
]),
Span::default(),
);
let result = transpiler.transpile_data_only_expr(&expr);
assert!(result.is_ok());
let tokens = result
.expect("operation should succeed in test")
.to_string();
assert!(tokens.contains("1"));
}
#[test]
fn test_transpile_data_only_expr_range_inclusive() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Range {
start: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(0, None)),
Span::default(),
)),
end: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(10, None)),
Span::default(),
)),
inclusive: true,
},
Span::default(),
);
let result = transpiler.transpile_data_only_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_data_only_expr_range_exclusive() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Range {
start: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(0, None)),
Span::default(),
)),
end: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(10, None)),
Span::default(),
)),
inclusive: false,
},
Span::default(),
);
let result = transpiler.transpile_data_only_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_data_only_expr_array_init() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::ArrayInit {
value: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(0, None)),
Span::default(),
)),
size: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(10, None)),
Span::default(),
)),
},
Span::default(),
);
let result = transpiler.transpile_data_only_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_data_only_expr_set_single_misparsed_block() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Set(vec![Expr::new(
ExprKind::Identifier("result".to_string()),
Span::default(),
)]),
Span::default(),
);
let result = transpiler.transpile_data_only_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_data_only_expr_dataframe() {
use crate::frontend::ast::DataFrameColumn;
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::DataFrame {
columns: vec![DataFrameColumn {
name: "col1".to_string(),
values: vec![Expr::new(
ExprKind::Literal(Literal::Integer(1, None)),
Span::default(),
)],
}],
},
Span::default(),
);
let result = transpiler.transpile_data_only_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_misc_expr_let_pattern() {
use crate::frontend::ast::Pattern;
let transpiler = Transpiler::new();
let expr = Expr {
kind: ExprKind::LetPattern {
pattern: Pattern::Tuple(vec![
Pattern::Identifier("a".to_string()),
Pattern::Identifier("b".to_string()),
]),
type_annotation: None,
value: Box::new(Expr::new(
ExprKind::Identifier("pair".to_string()),
Span::default(),
)),
body: Box::new(Expr::new(
ExprKind::Identifier("a".to_string()),
Span::default(),
)),
is_mutable: false,
else_block: None,
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = transpiler.transpile_misc_expr(&expr);
assert!(result.is_ok());
let output = result
.expect("operation should succeed in test")
.to_string();
assert!(output.contains("let"));
}
#[test]
fn test_transpile_misc_expr_let_pattern_else() {
use crate::frontend::ast::Pattern;
let transpiler = Transpiler::new();
let expr = Expr {
kind: ExprKind::LetPattern {
pattern: Pattern::Identifier("x".to_string()),
type_annotation: None,
value: Box::new(Expr::new(
ExprKind::Identifier("maybe_val".to_string()),
Span::default(),
)),
body: Box::new(Expr::new(
ExprKind::Identifier("x".to_string()),
Span::default(),
)),
is_mutable: false,
else_block: Some(Box::new(Expr::new(
ExprKind::Block(vec![]),
Span::default(),
))),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = transpiler.transpile_misc_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_misc_expr_pipeline() {
use crate::frontend::ast::PipelineStage;
let transpiler = Transpiler::new();
let expr = Expr {
kind: ExprKind::Pipeline {
expr: Box::new(Expr::new(
ExprKind::Identifier("data".to_string()),
Span::default(),
)),
stages: vec![PipelineStage {
op: Box::new(Expr::new(
ExprKind::Identifier("process".to_string()),
Span::default(),
)),
span: Span::default(),
}],
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = transpiler.transpile_misc_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_misc_expr_lazy() {
let transpiler = Transpiler::new();
let expr = Expr {
kind: ExprKind::Lazy {
expr: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(42, None)),
Span::default(),
)),
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = transpiler.transpile_misc_expr(&expr);
assert!(result.is_ok());
let output = result
.expect("operation should succeed in test")
.to_string();
assert!(output.contains("42"));
}
#[test]
fn test_transpile_misc_expr_type_alias() {
use crate::frontend::ast::{Type, TypeKind};
let transpiler = Transpiler::new();
let expr = Expr {
kind: ExprKind::TypeAlias {
name: "MyInt".to_string(),
target_type: Type {
kind: TypeKind::Named("i32".to_string()),
span: Span::default(),
},
},
span: Span::default(),
attributes: vec![],
leading_comments: vec![],
trailing_comment: None,
};
let result = transpiler.transpile_misc_expr(&expr);
assert!(result.is_ok());
let output = result
.expect("operation should succeed in test")
.to_string();
assert!(output.contains("type"));
}
#[test]
fn test_transpile_misc_expr_unsupported() {
let transpiler = Transpiler::new();
let expr = Expr::new(
ExprKind::Identifier("x".to_string()),
Span::default(),
);
let result = transpiler.transpile_misc_expr(&expr);
assert!(result.is_err());
assert!(result
.unwrap_err()
.to_string()
.contains("Unsupported expression kind"));
}
#[test]
fn test_transpile_misc_expr_let_const() {
use crate::frontend::ast::Attribute;
let transpiler = Transpiler::new();
let expr = Expr {
kind: ExprKind::Let {
name: "MAX_SIZE".to_string(),
type_annotation: None,
value: Box::new(Expr::new(
ExprKind::Literal(Literal::Integer(100, None)),
Span::default(),
)),
body: Box::new(Expr::new(
ExprKind::Identifier("MAX_SIZE".to_string()),
Span::default(),
)),
is_mutable: false,
else_block: None,
},
span: Span::default(),
attributes: vec![Attribute {
name: "const".to_string(),
args: vec![],
span: Span::default(),
}],
leading_comments: vec![],
trailing_comment: None,
};
let result = transpiler.transpile_misc_expr(&expr);
assert!(result.is_ok());
}
#[test]
fn test_transpile_misc_expr_import_all_pub_alias() {
use crate::frontend::ast::Attribute;
let transpiler = Transpiler::new();
let expr = Expr {
kind: ExprKind::ImportAll {
module: "std::io".to_string(),
alias: "io_mod".to_string(),
},
span: Span::default(),
attributes: vec![Attribute {
name: "pub".to_string(),
args: vec![],
span: Span::default(),
}],
leading_comments: vec![],
trailing_comment: None,
};
let result = transpiler.transpile_misc_expr(&expr);
assert!(result.is_ok());
let output = result
.expect("operation should succeed in test")
.to_string();
assert!(output.contains("pub"));
}
}