simple_ir_transformer 0.0.2

SITER - SImple Ir TransformER
Documentation
use std::collections::HashMap;
use crate::Value;

pub struct JS<'a> {
    pub ir_hm: &'a HashMap<String, Value>,
}

impl<'a> JS<'a> {
    pub fn new(ir_hm: &'a HashMap<String, Value>) -> Self {
        Self { ir_hm }
    }

    // вынесено как ассоциированная функция, как в Python-транспайлере
    fn format_value(v: &Value) -> String {
        match v {
            Value::Str(s)  => format!("\"{}\"", s),
            Value::Int(i)  => i.to_string(),
            Value::Bool(b) => if *b { "true" } else { "false" }.to_string(), // JS: строчные
            Value::Null    => "null".to_string(),                             // JS: null, не None

            Value::List(items) => {
                let inner = items
                    .iter()
                    .map(Self::format_value)
                    .collect::<Vec<_>>()
                    .join(", ");
                format!("[{}]", inner)
            }

            Value::Map(map) => {
                let inner = map
                    .iter()
                    .map(|(k, v)| format!("\"{}\": {}", k, Self::format_value(v)))
                    .collect::<Vec<_>>()
                    .join(", ");
                format!("{{{}}}", inner)
            }
        }
    }

    pub fn transpile(&self) -> String {
        let mut jscode = String::new();

        // импорты — сортировка для детерминированного вывода
        if let Some(Value::List(imports)) = self.ir_hm.get("imports") {
            let mut names: Vec<&str> = imports
                .iter()
                .filter_map(|i| if let Value::Str(s) = i { Some(s.as_str()) } else { None })
                .collect();
            names.sort();
            for name in names {
                jscode.push_str(&format!("const {} = require('{}');\n", name, name));
            }
            jscode.push('\n');
        }

        // переменные
        let mut var_keys: Vec<&String> = self.ir_hm
            .keys()
            .filter(|k| k.starts_with("var:"))
            .collect();
        var_keys.sort();

        for key in var_keys {
            if let Value::Map(map) = &self.ir_hm[key] {
                if let Some(val) = map.get("value") {
                    let name = key.trim_start_matches("var:");
                    jscode.push_str(&format!("const {} = {};\n", name, Self::format_value(val)));
                }
            }
        }

        jscode
    }
}