rust_to_dtr 0.16.0

Convert Rust Soroban contracts to DTR format.
Documentation
use crate::common::compilation_state::CompilationState;
use crate::errors::not_translatable_error::NotTranslatableError;
use crate::instruction::Instruction;
use crate::translate::pattern::handle_pattern;
use syn::ExprMatch;

use super::parse_expression;

pub fn handle_match_expression(
    expr: &ExprMatch,
    compilation_state: &mut CompilationState,
) -> Result<Vec<Instruction>, NotTranslatableError> {
    let thing_to_compare_against: String = format!(
        "THING_TO_COMPARE_AGAINST_{}",
        compilation_state.get_global_uuid()
    );

    let original_assignment = compilation_state.next_assignment.clone();
    let mut thing_to_compare_against_instructions = parse_expression(
        &*expr.expr,
        &mut compilation_state.with_assignment(Some(thing_to_compare_against.clone())),
    )?;
    compilation_state.with_assignment(original_assignment);

    let mut match_conditional_evaluation_instructions: Vec<Instruction> = vec![];
    let mut match_body_instructions: Vec<Instruction> = vec![];

    expr.arms.iter().for_each(|arm| {
        let arm_path: String = handle_pattern(arm.clone().pat.clone()).unwrap();
        let conditional_jump_check = format!(
            "CONDITIONAL_JUMP_CHECK_{}",
            compilation_state.get_global_uuid()
        );

        match_conditional_evaluation_instructions.push(Instruction::new(
            compilation_state.get_global_uuid(),
            format!("evaluate"),
            vec![
                "equal_to".to_string(),
                thing_to_compare_against.clone(),
                arm_path.clone(),
            ],
            conditional_jump_check.clone(),
            compilation_state.scope(),
        ));

        let mut prev_scope = compilation_state.scope();
        compilation_state.enter_new_scope(false);

        match_conditional_evaluation_instructions.push(Instruction::new(
            compilation_state.get_global_uuid(),
            format!("jump"),
            vec![
                conditional_jump_check.clone(),
                compilation_state.scope().to_string(),
            ],
            "".to_string(),
            prev_scope,
        ));

        let arm_instructions =
            parse_expression(&*arm.clone().body, &mut compilation_state.clone()).unwrap();
        match_body_instructions.extend(arm_instructions);

        prev_scope = compilation_state.scope();
        compilation_state.exit_scope();

        match_body_instructions.push(Instruction::new(
            compilation_state.get_global_uuid(),
            format!("jump"),
            vec![compilation_state.scope().to_string()],
            "".to_string(),
            prev_scope,
        ));
    });

    thing_to_compare_against_instructions.extend(match_conditional_evaluation_instructions);
    thing_to_compare_against_instructions.extend(match_body_instructions);

    Ok(thing_to_compare_against_instructions)
}

#[cfg(test)]
mod tests {
    use crate::instruction::Instruction;
    use crate::{
        common::compilation_state::CompilationState,
        translate::expression::match_expression::handle_match_expression,
    };
    use syn::{parse_quote, ExprMatch};

    #[test]
    fn test_handle_match_expression() {
        let mut compilation_state = CompilationState::new();
        let expr: ExprMatch = parse_quote! { match instance_of_struct {
            Struct::Variant1 => log!("Variant1"),
            Struct::Variant2 => log!("Variant2"),
        } };
        let instructions = handle_match_expression(&expr, &mut compilation_state).unwrap();

        assert_eq!(
            instructions,
            vec![
                Instruction::new(
                    1,
                    "assign".to_string(),
                    vec!["instance_of_struct".to_string()],
                    "THING_TO_COMPARE_AGAINST_0".to_string(),
                    0
                ),
                Instruction::new(
                    3,
                    "evaluate".to_string(),
                    vec![
                        "equal_to".to_string(),
                        "THING_TO_COMPARE_AGAINST_0".to_string(),
                        "Struct::Variant1".to_string()
                    ],
                    "CONDITIONAL_JUMP_CHECK_2".to_string(),
                    0
                ),
                Instruction::new(
                    5,
                    "jump".to_string(),
                    vec!["CONDITIONAL_JUMP_CHECK_2".to_string(), "4".to_string()],
                    "".to_string(),
                    0
                ),
                Instruction::new(
                    9,
                    "evaluate".to_string(),
                    vec![
                        "equal_to".to_string(),
                        "THING_TO_COMPARE_AGAINST_0".to_string(),
                        "Struct::Variant2".to_string()
                    ],
                    "CONDITIONAL_JUMP_CHECK_8".to_string(),
                    0
                ),
                Instruction::new(
                    11,
                    "jump".to_string(),
                    vec!["CONDITIONAL_JUMP_CHECK_8".to_string(), "10".to_string()],
                    "".to_string(),
                    0
                ),
                Instruction::new(
                    6,
                    "print".to_string(),
                    vec!["\"Variant1\"".to_string()],
                    "".to_string(),
                    4
                ),
                Instruction::new(
                    7,
                    "jump".to_string(),
                    vec!["0".to_string()],
                    "".to_string(),
                    4
                ),
                Instruction::new(
                    12,
                    "print".to_string(),
                    vec!["\"Variant2\"".to_string()],
                    "".to_string(),
                    10
                ),
                Instruction::new(
                    13,
                    "jump".to_string(),
                    vec!["0".to_string()],
                    "".to_string(),
                    10
                ),
            ]
        );
    }
}