windjammer 0.48.0

A simple language inspired by Go, Ruby, and Elixir that transpiles to Rust - 80% of Rust's power with 20% of the complexity
Documentation
#![cfg(any(
    not(any(
        feature = "parser_tests",
        feature = "analyzer_tests",
        feature = "codegen_tests",
        feature = "interpreter_tests",
        feature = "conformance_tests",
        feature = "integration_tests",
    )),
    feature = "analyzer_tests",
))]

#[path = "common/test_utils.rs"]
mod test_utils;

/// TDD Test: No double .clone().clone() when source already has explicit .clone()
///
/// Bug: When Windjammer source has `stack.item.clone()` (explicit clone because
/// Item is non-Copy), the auto-clone system adds another .clone() because it sees
/// `stack.item` used multiple times. Result: `stack.item.clone().clone()`.
///
/// Root Cause: The auto-clone on FieldAccess adds .clone() to `stack.item`,
/// and then the explicit .clone() MethodCall from the source generates a second one.
///
/// Expected: Only one .clone() should appear.
#[test]
fn test_no_double_clone_on_explicit_clone() {
    let source = r#"
pub struct Item {
    pub id: string,
    pub name: string,
}

pub struct ItemStack {
    pub item: Item,
    pub quantity: i32,
}

pub struct Inventory {
    pub items: Vec<Item>,
}

impl Inventory {
    pub fn add_item(self, item: Item) {
        self.items.push(item)
    }
}

pub struct Trade {
    pub offer: Vec<ItemStack>,
}

impl Trade {
    pub fn execute(self, inv: Inventory) {
        for stack in self.offer {
            inv.add_item(stack.item)
        }
    }
}
"#;

    let generated = test_utils::compile_single(source);
    println!("Generated:\n{}", generated);

    // Should have exactly one .clone(), NOT .clone().clone()
    assert!(
        !generated.contains(".clone().clone()"),
        "Should not have double .clone().clone().\nGenerated:\n{}",
        generated
    );

    // Should still have the single clone (Item is non-Copy)
    assert!(
        generated.contains("stack.item.clone()"),
        "Should have single .clone() for non-Copy field.\nGenerated:\n{}",
        generated
    );
}

#[test]
fn test_no_double_clone_field_used_multiple_times() {
    // Field used multiple times: once with .clone(), once without
    let source = r#"
pub struct Item {
    pub id: string,
    pub name: string,
}

pub struct Container {
    pub items: Vec<Item>,
}

impl Container {
    pub fn process(self) {
        for item in self.items {
            let id = item.id
            let name = item.name
        }
    }
}
"#;

    let generated = test_utils::compile_single(source);
    println!("Generated:\n{}", generated);

    assert!(
        !generated.contains(".clone().clone()"),
        "Should not have double .clone().clone().\nGenerated:\n{}",
        generated
    );
}

#[test]
fn test_no_double_clone_multi_use_in_loop() {
    // Mimics the game code pattern: stack.item used multiple times in same loop,
    // some with explicit .clone(), some for .id.clone()
    let source = r#"
pub struct Item {
    pub id: string,
    pub name: string,
}

pub struct ItemStack {
    pub item: Item,
    pub quantity: i32,
}

pub struct Inventory {
    pub items: Vec<Item>,
}

impl Inventory {
    pub fn add_item(self, item: Item) {
        self.items.push(item)
    }

    pub fn remove_item_by_id(self, id: string, qty: i32) -> bool {
        true
    }
}

pub struct Trade {
    pub offer: Vec<ItemStack>,
}

impl Trade {
    pub fn execute(self, inv: Inventory) {
        for stack in self.offer {
            inv.remove_item_by_id(stack.item.id, stack.quantity)
            inv.add_item(stack.item)
        }
    }
}
"#;

    let generated = test_utils::compile_single(source);
    println!("Generated:\n{}", generated);

    // Should NOT have .clone().clone() anywhere
    assert!(
        !generated.contains(".clone().clone()"),
        "Should not have double .clone().clone().\nGenerated:\n{}",
        generated
    );

    // Should have single .clone() for non-Copy field
    assert!(
        generated.contains("stack.item.clone()"),
        "Should have single .clone() for stack.item.\nGenerated:\n{}",
        generated
    );
}