mumu 0.11.1

Lava Mumu is a language for those in the now and that know
Documentation
// FILE: src/parser/core/stmt.rs

#![allow(unused_variables)]

use crate::parser::ast::{Stmt, DestructurePattern, Expr};
use crate::parser::lexer::{Token, TokenKind};
use super::utils::Parser;
use super::precedence::parse_expression;

/// Helper: get the line/col of the current token or return (0,0) at EOF
fn pos(parser: &Parser) -> (usize, usize) {
    parser.current().map(|t| (t.line, t.col)).unwrap_or((0, 0))
}

// Helper for tuple assignment parsing
fn parse_expr_or_tuple(parser: &mut Parser) -> Result<Expr, super::driver::ParseError> {
    let (line, col) = pos(parser);
    let mut exprs = Vec::new();
    exprs.push(parse_expression(parser)?);
    while let Some(Token { kind: TokenKind::Comma, .. }) = parser.current() {
        parser.advance();
        exprs.push(parse_expression(parser)?);
    }
    if exprs.len() == 1 {
        Ok(exprs.remove(0))
    } else {
        Ok(Expr::BracketedArray {
            items: exprs,
            line,
            col,
        })
    }
}

pub fn parse_statement(parser: &mut Parser) -> Result<Stmt, super::driver::ParseError> {
    let (line, col) = pos(parser);

    // 1. Handle keyed destructure assignment (e.g. :a,:b = {a:1,b:2})
    if let Some(Token { kind: TokenKind::Colon, .. }) = parser.current() {
        let mut keys = Vec::new();
        let (colon_line, colon_col) = pos(parser);
        while let Some(Token { kind: TokenKind::Colon, .. }) = parser.current() {
            parser.advance();
            if let Some(Token { kind: TokenKind::Identifier(name), .. }) = parser.current() {
                keys.push(name.clone());
                parser.advance();
                if let Some(Token { kind: TokenKind::Comma, .. }) = parser.current() {
                    parser.advance();
                } else {
                    break;
                }
            } else {
                return Err(super::driver::ParseError {
                    msg: "Expected identifier after ':' in destructure pattern".into(),
                    line: pos(parser).0,
                    col: pos(parser).1,
                });
            }
        }
        parser.expect(&TokenKind::Equals)?;
        let right = parse_expression(parser)?;
        if let Some(Token { kind: TokenKind::Semi, .. }) = parser.current() {
            parser.advance();
        }
        return Ok(Stmt::AssignmentDestructure {
            pattern: DestructurePattern::Keyed(keys),
            right,
            line: colon_line,
            col: colon_col,
        });
    }

    // 2. Handle tuple destructure assignment (e.g. a,b = [1,2])
    let save_pos = parser.pos;
    let mut tuple_vars = Vec::new();
    let mut at_least_one = false;
    let (tuple_line, tuple_col) = pos(parser);
    while let Some(Token { kind: TokenKind::Identifier(id), .. }) = parser.current() {
        tuple_vars.push(id.clone());
        parser.advance();
        at_least_one = true;
        if let Some(Token { kind: TokenKind::Comma, .. }) = parser.current() {
            parser.advance();
        } else {
            break;
        }
    }
    if at_least_one
        && matches!(parser.current(), Some(Token { kind: TokenKind::Equals, .. }))
        && tuple_vars.len() >= 2
    {
        parser.advance();
        let right = parse_expr_or_tuple(parser)?;
        if let Some(Token { kind: TokenKind::Semi, .. }) = parser.current() {
            parser.advance();
        }
        return Ok(Stmt::AssignmentDestructure {
            pattern: DestructurePattern::Tuple(tuple_vars),
            right,
            line: tuple_line,
            col: tuple_col,
        });
    } else {
        parser.pos = save_pos;
    }

    // 3. Handle "extend" (import shared object)
    if let Some(Token { kind: TokenKind::Identifier(id), line, col }) = parser.current() {
        if id == "extend" {
            parser.advance();
            parser.expect(&TokenKind::LParen)?;
            if let Some(Token { kind: TokenKind::StringLiteral(p), line: sl, col: sc }) = parser.current() {
                let path = p.clone();
                parser.advance();
                parser.expect(&TokenKind::RParen)?;
                return Ok(Stmt::ImportSo {
                    path,
                    line: *line,
                    col: *col,
                });
            } else {
                return Err(super::driver::ParseError {
                    msg: "extend => expected string literal".into(),
                    line: pos(parser).0,
                    col: pos(parser).1,
                });
            }
        }
    }

    // 4. Handle block-scoped assignment (x ^= 42)
    if let Some(Token { kind: TokenKind::Identifier(id), line: id_line, col: id_col }) = parser.current() {
        let name = id.clone();
        parser.advance();
        if let Some(Token { kind: TokenKind::CaretEquals, .. }) = parser.current() {
            parser.advance();
            let right = parse_expression(parser)?;
            if let Some(Token { kind: TokenKind::Semi, .. }) = parser.current() {
                parser.advance();
            }
            return Ok(Stmt::AssignmentScoped {
                left: Expr::Ident {
                    name,
                    line: *id_line,
                    col: *id_col,
                },
                right,
                line: *id_line,
                col: *id_col,
            });
        } else {
            parser.pos -= 1;
        }
    }

    // 5. Handle general assignment: allow identifier or index expression (e.g. b[0] = ...)
    let save_pos = parser.pos;
    let expr_linecol = pos(parser);
    if let Ok(left) = parse_expression(parser) {
        if let Some(Token { kind: TokenKind::Equals, .. }) = parser.current() {
            parser.advance(); // Equals
            let right = parse_expression(parser)?;
            if let Some(Token { kind: TokenKind::Semi, .. }) = parser.current() {
                parser.advance();
            }
            return Ok(Stmt::Assignment {
                left,
                right,
                line: expr_linecol.0,
                col: expr_linecol.1,
            });
        }
        parser.pos = save_pos; // reset if not assignment
    }

    // 6. Fallback to expression statement
    let (expr_stmt_line, expr_stmt_col) = pos(parser);
    let left = parse_expression(parser)?;
    if let Some(Token { kind: TokenKind::Semi, .. }) = parser.current() {
        parser.advance();
    }
    Ok(Stmt::ExprStmt {
        expr: left,
        line: expr_stmt_line,
        col: expr_stmt_col,
    })
}