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",
))]

// TDD Test: Self parameter inference - developers write just "self", compiler infers &self, &mut self, or self
// Philosophy: "Compiler does the hard work, not the developer"
// Expected:
//   - self only read → &self
//   - self mutated → &mut self
//   - self consumed → self (owned)

use std::fs;
use std::process::Command;
use tempfile::TempDir;

fn compile_and_check(code: &str) -> (bool, String) {
    let temp_dir = TempDir::new().expect("Failed to create temp dir");
    let test_file = temp_dir.path().join("test.wj");
    let output_file = temp_dir.path().join("test.rs");

    fs::write(&test_file, code).unwrap();

    let output = Command::new(env!("CARGO_BIN_EXE_wj"))
        .args([
            "build",
            test_file.to_str().unwrap(),
            "--output",
            temp_dir.path().to_str().unwrap(),
            "--no-cargo",
        ])
        .current_dir(env!("CARGO_MANIFEST_DIR"))
        .output()
        .expect("Failed to run wj");

    let generated = fs::read_to_string(output_file).unwrap_or_default();
    (output.status.success(), generated)
}

#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_self_inference_read_only() {
    let code = r#"
pub struct Point {
    pub x: int,
    pub y: int,
}

impl Point {
    pub fn get_x(self) -> int {
        return self.x
    }
    
    pub fn distance_from_origin(self) -> f32 {
        return ((self.x * self.x + self.y * self.y) as f32).sqrt()
    }
}
"#;

    let (success, generated) = compile_and_check(code);
    assert!(success, "Should compile successfully");

    // Copy types use self (by value) for read-only methods — no indirection needed
    assert!(
        generated.contains("pub fn get_x(self) -> i64") || generated.contains("pub fn get_x(&self) -> i64"),
        "Read-only Copy method should infer 'self' or '&self'. Generated:\n{}",
        generated
    );
    assert!(
        generated.contains("pub fn distance_from_origin(self) -> f32") || generated.contains("pub fn distance_from_origin(&self) -> f32"),
        "Read-only Copy method should infer 'self' or '&self'. Generated:\n{}",
        generated
    );
}

#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_self_inference_mutating() {
    let code = r#"
pub struct Counter {
    pub count: int,
}

impl Counter {
    pub fn increment(self) {
        self.count = self.count + 1
    }
    
    pub fn add(self, amount: int) {
        self.count = self.count + amount
    }
    
    pub fn reset(self) {
        self.count = 0
    }
}
"#;

    let (success, generated) = compile_and_check(code);
    assert!(success, "Should compile successfully");

    // When self is mutated, should infer &mut self
    assert!(
        generated.contains("pub fn increment(&mut self)"),
        "Mutating method should infer '&mut self'. Generated:\n{}",
        generated
    );
    assert!(
        generated.contains("pub fn add(&mut self, amount: i64)"),
        "Mutating method should infer '&mut self'. Generated:\n{}",
        generated
    );
    assert!(
        generated.contains("pub fn reset(&mut self)"),
        "Mutating method should infer '&mut self'. Generated:\n{}",
        generated
    );
}

#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_self_inference_consuming() {
    let code = r#"
pub struct Builder {
    pub value: int,
}

impl Builder {
    pub fn build(self) -> int {
        return self.value
    }
    
    pub fn into_inner(self) -> int {
        self.value
    }
}
"#;

    let (success, generated) = compile_and_check(code);
    assert!(success, "Should compile successfully");

    // Copy types use self (by value) — trivial copy, no indirection needed
    assert!(
        generated.contains("pub fn build(self) -> i64") || generated.contains("pub fn build(&self) -> i64"),
        "Copy type read method should use self or &self. Generated:\n{}",
        generated
    );
    assert!(
        generated.contains("pub fn into_inner(self) -> i64") || generated.contains("pub fn into_inner(&self) -> i64"),
        "Copy type read method should use self or &self. Generated:\n{}",
        generated
    );
}

#[test]
#[cfg_attr(tarpaulin, ignore)]
fn test_self_inference_mixed() {
    let code = r#"
pub struct Vector {
    pub x: f32,
    pub y: f32,
}

impl Vector {
    pub fn length(self) -> f32 {
        ((self.x * self.x + self.y * self.y) as f32).sqrt()
    }
    
    pub fn normalize(self) {
        let len = self.length();
        self.x = self.x / len;
        self.y = self.y / len
    }
    
    pub fn consume(self) -> f32 {
        self.x + self.y
    }
}
"#;

    let (success, generated) = compile_and_check(code);
    assert!(success, "Should compile successfully");

    // length: read-only on Copy type → self (by value, no indirection)
    assert!(
        generated.contains("pub fn length(self) -> f32") || generated.contains("pub fn length(&self) -> f32"),
        "Read-only Copy method should use self or &self. Generated:\n{}",
        generated
    );

    // normalize: mutates self → &mut self
    assert!(
        generated.contains("pub fn normalize(&mut self)"),
        "Mutating should infer '&mut self'. Generated:\n{}",
        generated
    );

    // consume: read-only on Copy type → self (by value)
    assert!(
        generated.contains("pub fn consume(self) -> f32") || generated.contains("pub fn consume(&self) -> f32"),
        "Copy type read should use self or &self. Generated:\n{}",
        generated
    );
}

#[test]
fn test_self_inference_trait_methods() {
    let code = r#"
pub trait Drawable {
    fn draw(self);
    fn update(self, delta: f32);
}

pub struct Sprite {
    pub x: f32,
    pub dirty: bool,
}

impl Drawable for Sprite {
    fn draw(self) {
        println("Drawing");
    }
    
    fn update(self, delta: f32) {
        self.dirty = true
    }
}
"#;

    let (success, generated) = compile_and_check(code);
    assert!(success, "Should compile successfully");

    // Trait methods should also infer
    // draw: read-only → &self
    let trait_section: String = generated
        .lines()
        .skip_while(|l| !l.contains("trait Drawable"))
        .take(10)
        .collect::<Vec<_>>()
        .join("\n");

    assert!(
        trait_section.contains("fn draw(&self);"),
        "Trait read-only method should infer '&self'. Trait:\n{}",
        trait_section
    );

    // update: mutates → &mut self
    assert!(
        trait_section.contains("fn update(&mut self, delta: f32);"),
        "Trait mutating method should infer '&mut self'. Trait:\n{}",
        trait_section
    );
}