mod transformers;
use std::collections::HashMap;
use tinyjson::JsonValue;
use std::fs;
pub static VERSION: &str = "1.0.0";
#[derive(Debug, Clone)]
pub enum Value {
Str(String),
Int(i64),
Bool(bool),
List(Vec<Value>),
Map(HashMap<String, Value>),
Null,
}
#[derive(Debug)]
pub enum IRError {
ParseError(String),
InvalidRoot,
UnknownLanguage(String),
}
impl std::fmt::Display for IRError {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
match self {
IRError::ParseError(e) => write!(f, "JSON parsing error: {}", e),
IRError::InvalidRoot => write!(f, "IR must be a JSON object"),
IRError::UnknownLanguage(l) => write!(f, "Unknown language: {}, available: Python, JavaScript, Lua", l),
}
}
}
pub struct IR {
pub ir: String,
}
impl IR {
pub fn new(ir: String) -> Self {
Self { ir }
}
fn json_to_value(v: JsonValue) -> Value {
match v {
JsonValue::String(s) => Value::Str(s),
JsonValue::Number(n) => Value::Int(n as i64),
JsonValue::Boolean(b) => Value::Bool(b),
JsonValue::Array(arr) => {
Value::List(arr.into_iter().map(Self::json_to_value).collect())
}
JsonValue::Object(map) => {
Value::Map(
map.into_iter()
.map(|(k, v)| (k, Self::json_to_value(v)))
.collect()
)
}
JsonValue::Null => Value::Null,
}
}
pub fn transpile(&self, lang: &str) -> Result<String, IRError> {
let json: JsonValue = self.ir
.parse()
.map_err(|e: tinyjson::JsonParseError| IRError::ParseError(e.to_string()))?;
let obj_map = match json {
JsonValue::Object(map) => map,
_ => return Err(IRError::InvalidRoot),
};
let ir_data: HashMap<String, Value> = obj_map
.into_iter()
.map(|(k, v)| (k, Self::json_to_value(v)))
.collect();
match lang {
"Python" => Ok(transformers::python_backend::Python::new(&ir_data).generate()),
"JavaScript" => Ok(transformers::js_backend::JavaScript::new(&ir_data).generate()),
"Lua" => Ok(transformers::lua_backend::Lua::new(&ir_data).generate()),
_ => Err(IRError::UnknownLanguage(lang.to_string())),
}
}
}
pub fn from_file(path: &str) -> Result<IR, IRError> {
let content: &str = &fs::read_to_string(path).map_err(|e| IRError::ParseError(e.to_string()))?;
Ok(IR::new(content.to_string()))
}