frg 2.0.2

Compiled programming language with frogs!
use crate::ast;

use super::{TreeCursor, IfStatement, expressions, parse_block, Expression, Statement};

pub fn parse(cursor: &mut TreeCursor, code: &str) -> IfStatement {
    cursor.goto_first_child();
    skip_keywords(cursor);
    let condition = expressions::parse(cursor, code);

    cursor.goto_next_sibling();
    let body = parse_block(cursor, code);

    let mut else_ifs = vec![];
    let mut else_body = vec![];
    while cursor.goto_next_sibling() {
        let node_name = cursor.node().kind();
        match node_name {
            "else_if_statement" => else_ifs.push(parse_else_if(cursor, code)),
            "else_statement" => {
                else_body = parse_else(cursor, code);
                break;
            }
            _ => todo!(),
        }
    }

    cursor.goto_parent();
    IfStatement {
        condition,
        body,
        else_ifs,
        else_body,
    }
}

pub fn transpile(if_state: &IfStatement) -> String {
    let condition = expressions::transpile(&if_state.condition);
    let body = ast::transpile(&if_state.body);
    let mut if_str = format!("if {condition} {{\n{body}\n}}");
    for else_if in &if_state.else_ifs {
        let else_if_condition = expressions::transpile(&else_if.0);
        let else_if_body = ast::transpile(&else_if.1);
        if_str.push_str(&format!(
            " else if {else_if_condition} {{\n{else_if_body}\n}}"
        ));
    }
    if !if_state.else_body.is_empty() {
        let else_body = ast::transpile(&if_state.else_body);
        if_str.push_str(&format!(" else {{\n{else_body}\n}}"));
    }
    if_str
}

fn skip_keywords(cursor: &mut TreeCursor) {
    let mut token = cursor.node().kind();
    while token == "if" || token == "else" {
        if !cursor.goto_next_sibling() {
            break;
        }
        token = cursor.node().kind();
    }
}

fn parse_else_if(cursor: &mut TreeCursor, code: &str) -> (Expression, Vec<Statement>) {
    cursor.goto_first_child();
    skip_keywords(cursor);
    let condition = expressions::parse(cursor, code);

    cursor.goto_next_sibling();
    let body = parse_block(cursor, code);

    cursor.goto_parent();
    (condition, body)
}

fn parse_else(cursor: &mut TreeCursor, code: &str) -> Vec<Statement> {
    cursor.goto_first_child();
    skip_keywords(cursor);
    let body = parse_block(cursor, code);

    cursor.goto_parent();
    body
}