1pub use flutmax_ast as ast;
14pub use flutmax_codegen as codegen;
15pub use flutmax_decompile as decompile;
16pub use flutmax_objdb as objdb;
17pub use flutmax_parser as parser;
18pub use flutmax_sema as sema;
19
20pub fn compile(source: &str) -> Result<String, String> {
27 let ast = flutmax_parser::parse(source).map_err(|e| e.to_string())?;
28 let graph = flutmax_codegen::build_graph(&ast).map_err(|e| format!("{:?}", e))?;
29 flutmax_codegen::generate(&graph).map_err(|e| format!("{:?}", e))
30}
31
32pub fn decompile(maxpat_json: &str) -> Result<String, String> {
39 flutmax_decompile::decompile(maxpat_json).map_err(|e| format!("{:?}", e))
40}
41
42pub fn parse_to_json(source: &str) -> Result<String, String> {
46 let ast = flutmax_parser::parse(source).map_err(|e| e.to_string())?;
47 ast_to_json(&ast)
48}
49
50pub fn decompile_multi(
52 maxpat_json: &str,
53 name: &str,
54) -> Result<flutmax_decompile::DecompileResult, String> {
55 flutmax_decompile::decompile_multi(maxpat_json, name).map_err(|e| format!("{:?}", e))
56}
57
58fn ast_to_json(program: &flutmax_ast::Program) -> Result<String, String> {
60 let mut obj = serde_json::Map::new();
62
63 let in_decls: Vec<serde_json::Value> = program
65 .in_decls
66 .iter()
67 .map(|d| {
68 serde_json::json!({
69 "index": d.index,
70 "name": d.name,
71 "port_type": format!("{:?}", d.port_type),
72 })
73 })
74 .collect();
75 obj.insert("in_decls".into(), serde_json::Value::Array(in_decls));
76
77 let out_decls: Vec<serde_json::Value> = program
79 .out_decls
80 .iter()
81 .map(|d| {
82 serde_json::json!({
83 "index": d.index,
84 "name": d.name,
85 "port_type": format!("{:?}", d.port_type),
86 })
87 })
88 .collect();
89 obj.insert("out_decls".into(), serde_json::Value::Array(out_decls));
90
91 let wires: Vec<serde_json::Value> = program
93 .wires
94 .iter()
95 .map(|w| {
96 serde_json::json!({
97 "name": w.name,
98 "expr": format!("{:?}", w.value),
99 "attrs": w.attrs.iter().map(|a| {
100 serde_json::json!({"key": a.key, "value": format!("{:?}", a.value)})
101 }).collect::<Vec<_>>(),
102 })
103 })
104 .collect();
105 obj.insert("wires".into(), serde_json::Value::Array(wires));
106
107 let out_assigns: Vec<serde_json::Value> = program
109 .out_assignments
110 .iter()
111 .map(|a| {
112 serde_json::json!({
113 "index": a.index,
114 "value": format!("{:?}", a.value),
115 })
116 })
117 .collect();
118 obj.insert(
119 "out_assignments".into(),
120 serde_json::Value::Array(out_assigns),
121 );
122
123 serde_json::to_string_pretty(&serde_json::Value::Object(obj)).map_err(|e| e.to_string())
124}
125
126#[cfg(test)]
127mod tests {
128 use super::*;
129
130 #[test]
131 fn test_compile() {
132 let result = compile("wire osc = cycle~(440);\nout audio: signal = osc;");
133 assert!(result.is_ok(), "compile failed: {:?}", result.err());
134 let json = result.unwrap();
135 assert!(json.contains("cycle~"));
136 }
137
138 #[test]
139 fn test_compile_error() {
140 let result = compile("wire osc = ;");
141 assert!(result.is_err());
142 }
143
144 #[test]
145 fn test_parse_to_json() {
146 let result =
147 parse_to_json("in freq: float;\nwire osc = cycle~(freq);\nout audio: signal = osc;");
148 assert!(result.is_ok());
149 let json = result.unwrap();
150 assert!(json.contains("freq"));
151 assert!(json.contains("cycle~"));
152 }
153
154 #[test]
155 fn test_roundtrip() {
156 let source = "in freq: float;\nwire osc = cycle~(freq);\nout audio: signal = osc;\n";
157 let maxpat = compile(source).unwrap();
158 let decompiled = decompile(&maxpat).unwrap();
159 assert!(decompiled.contains("cycle~"));
160 }
161}