1use ternlang_core::ast::*;
32
33const C_HEADER: &str = r#"/* Generated by ternlang-codegen — do not edit. */
36#include <stdint.h>
37#include <stdio.h>
38
39typedef int8_t trit;
40
41/* Ternary primitives */
42static inline trit trit_neg(trit a) { return (trit)(-a); }
43static inline trit trit_add(trit a, trit b) {
44 int s = (int)a + (int)b;
45 if (s > 1) return 1;
46 if (s < -1) return -1;
47 return (trit)s;
48}
49static inline trit trit_mul(trit a, trit b) { return (trit)((int)a * (int)b); }
50static inline trit trit_consensus(trit a, trit b) { return trit_add(a, b); }
51static inline trit trit_invert(trit a) { return trit_neg(a); }
52static inline trit trit_truth() { return 1; }
53static inline trit trit_hold() { return 0; }
54static inline trit trit_conflict() { return -1; }
55static inline trit trit_abs(trit a){ return a < 0 ? (trit)-a : a; }
56static inline trit trit_min(trit a, trit b) { return a < b ? a : b; }
57static inline trit trit_max(trit a, trit b) { return a > b ? a : b; }
58
59"#;
60
61pub struct CTranspiler {
64 indent: usize,
65 output: String,
66}
67
68impl CTranspiler {
69 pub fn new() -> Self {
70 Self { indent: 0, output: String::new() }
71 }
72
73 pub fn emit(mut self, program: &Program) -> String {
75 self.output.push_str(C_HEADER);
76
77 for s in &program.structs {
79 self.emit_struct_decl(s);
80 }
81 if !program.structs.is_empty() { self.output.push('\n'); }
82
83 for f in &program.functions {
85 self.emit_fn_forward(f);
86 }
87 if !program.functions.is_empty() { self.output.push('\n'); }
88
89 for f in &program.functions {
91 self.emit_function(f);
92 self.output.push('\n');
93 }
94
95 self.output.push_str(
97 "int main(void) {\n trit result = tern_main();\n printf(\"trit: %d\\n\", (int)result);\n return result == -1 ? 1 : 0;\n}\n"
98 );
99
100 self.output
101 }
102
103 fn emit_struct_decl(&mut self, s: &StructDef) {
106 self.push(&format!("typedef struct {{\n"));
107 self.indent += 1;
108 for (field, ty) in &s.fields {
109 self.push(&format!("{} {};\n", self.c_type(ty), field));
110 }
111 self.indent -= 1;
112 self.push(&format!("}} {};\n", s.name));
113 }
114
115 fn emit_fn_forward(&mut self, f: &Function) {
118 let params = self.c_params(&f.params);
119 let name = self.mangle_name(&f.name);
120 self.push(&format!("{} {}({});\n", self.c_type(&f.return_type), name, params));
121 }
122
123 fn emit_function(&mut self, f: &Function) {
126 let params = self.c_params(&f.params);
127 let name = self.mangle_name(&f.name);
128 self.push(&format!("{} {}({}) {{\n", self.c_type(&f.return_type), name, params));
129 self.indent += 1;
130 for stmt in &f.body {
131 self.emit_stmt(stmt);
132 }
133 self.indent -= 1;
134 self.push("}\n");
135 }
136
137 fn emit_stmt(&mut self, stmt: &Stmt) {
140 match stmt {
141 Stmt::Let { name, ty, value } => {
142 let cty = self.c_type(ty);
143 let val = self.emit_expr(value);
144 self.push(&format!("{cty} {name} = {val};\n"));
145 }
146 Stmt::Return(expr) => {
147 let val = self.emit_expr(expr);
148 self.push(&format!("return {val};\n"));
149 }
150 Stmt::Expr(expr) => {
151 let val = self.emit_expr(expr);
152 self.push(&format!("{val};\n"));
153 }
154 Stmt::Block(stmts) => {
155 self.push("{\n");
156 self.indent += 1;
157 for s in stmts { self.emit_stmt(s); }
158 self.indent -= 1;
159 self.push("}\n");
160 }
161 Stmt::IfTernary { condition, on_pos, on_zero, on_neg } => {
162 let cond = self.emit_expr(condition);
163 self.push(&format!("if ({cond} > 0) "));
164 self.emit_stmt(on_pos);
165 self.push("else if (0 == (int)");
166 let cond2 = self.emit_expr(condition);
168 self.push(&format!("{cond2}) "));
169 self.emit_stmt(on_zero);
170 self.push("else ");
171 self.emit_stmt(on_neg);
172 }
173 Stmt::Match { condition, arms } => {
174 let cond = self.emit_expr(condition);
175 self.push(&format!("switch ((int){cond}) {{\n"));
176 self.indent += 1;
177 for (pattern, arm) in arms {
178 if matches!(pattern, Pattern::Wildcard) {
179 self.push("default: ");
180 self.emit_stmt(arm);
181 self.push("break;\n");
182 continue;
183 }
184 let val = match pattern {
185 Pattern::Int(v) => *v,
186 Pattern::Trit(t) => *t as i64,
187 Pattern::Float(f) => *f as i64,
188 Pattern::Wildcard => unreachable!(),
189 };
190 self.push(&format!("case {val}: "));
191 self.emit_stmt(arm);
192 self.push("break;\n");
193 }
194 self.indent -= 1;
195 self.push("}\n");
196 }
197 Stmt::WhileTernary { condition, on_pos, on_zero, on_neg } => {
198 let cond = self.emit_expr(condition);
199 self.push(&format!("while (1) {{\n"));
201 self.indent += 1;
202 self.push(&format!("trit __cond = {cond};\n"));
203 self.push("if (__cond > 0) ");
204 self.emit_stmt(on_pos);
205 self.push("else if (__cond == 0) ");
206 self.emit_stmt(on_zero);
207 self.push("else ");
208 self.emit_stmt(on_neg);
209 self.indent -= 1;
210 self.push("}\n");
211 }
212 Stmt::Loop { body } => {
213 self.push("for (;;) ");
214 self.emit_stmt(body);
215 }
216 Stmt::ForIn { var, iter, body } => {
217 let iter_expr = self.emit_expr(iter);
219 self.push(&format!("/* for {var} in {iter_expr}: tensor iteration omitted in C backend */\n"));
220 let _ = body;
221 }
222 Stmt::Break => self.push("break;\n"),
223 Stmt::Continue => self.push("continue;\n"),
224 Stmt::Use { .. } => { }
225 Stmt::FromImport { .. } => { }
226 Stmt::Send { target, message } => {
227 let t = self.emit_expr(target);
228 let m = self.emit_expr(message);
229 self.push(&format!("/* send {m} to agent {t} — actor model not implemented in C backend */\n"));
230 }
231 Stmt::FieldSet { object, field, value } => {
232 let val = self.emit_expr(value);
233 self.push(&format!("{object}.{field} = {val};\n"));
234 }
235 Stmt::Decorated { stmt, .. } => self.emit_stmt(stmt),
236 Stmt::IndexSet { object, row, col, value } => {
237 let r = self.emit_expr(row);
238 let c = self.emit_expr(col);
239 let val = self.emit_expr(value);
240 self.push(&format!("{object}[{r}][{c}] = {val};\n"));
241 }
242 Stmt::Set { name, value } => {
243 let val = self.emit_expr(value);
244 self.push(&format!("{name} = {val};\n"));
245 }
246 }
247 }
248
249 fn emit_expr(&self, expr: &Expr) -> String {
252 match expr {
253 Expr::TritLiteral(v) => format!("((trit){v})"),
254 Expr::IntLiteral(v) => format!("{v}"),
255 Expr::StringLiteral(s) => format!("\"{}\"", s.replace('"', "\\\"")),
256 Expr::Ident(name) => name.clone(),
257
258 Expr::BinaryOp { op, lhs, rhs } => {
259 let l = self.emit_expr(lhs);
260 let r = self.emit_expr(rhs);
261 match op {
262 BinOp::Add => format!("trit_add({l}, {r})"),
263 BinOp::Sub => format!("trit_add({l}, trit_neg({r}))"),
264 BinOp::Mul => format!("trit_mul({l}, {r})"),
265 BinOp::Equal => format!("trit_consensus({l}, {r})"),
266 BinOp::NotEqual => format!("trit_neg(trit_consensus({l}, {r}))"),
267 BinOp::And => format!("trit_mul({l}, {r})"),
268 BinOp::Or => format!("trit_consensus({l}, {r})"),
269 BinOp::Less => format!("(({l}) < ({r}) ? 1 : (({l}) == ({r}) ? 0 : -1))"),
270 BinOp::Greater => format!("(({l}) > ({r}) ? 1 : (({l}) == ({r}) ? 0 : -1))"),
271 BinOp::LessEqual => format!("(({l}) <= ({r}) ? 1 : -1)"),
272 BinOp::GreaterEqual=> format!("(({l}) >= ({r}) ? 1 : -1)"),
273 BinOp::Div => format!("(({l}) / ({r}))"),
274 BinOp::Mod => format!("(({l}) % ({r}))"),
275 }
276 }
277
278 Expr::UnaryOp { op: UnOp::Neg, expr } => {
279 let inner = self.emit_expr(expr);
280 format!("trit_neg({inner})")
281 }
282
283 Expr::Call { callee, args } => {
284 let a: Vec<String> = args.iter().map(|a| self.emit_expr(a)).collect();
285 let args_str = a.join(", ");
286 match callee.as_str() {
288 "consensus" => format!("trit_consensus({args_str})"),
289 "invert" => format!("trit_invert({args_str})"),
290 "truth" => "trit_truth()".into(),
291 "hold" => "trit_hold()".into(),
292 "conflict" => "trit_conflict()".into(),
293 "abs" => format!("trit_abs({args_str})"),
294 "min" => format!("trit_min({args_str})"),
295 "max" => format!("trit_max({args_str})"),
296 _ => format!("{}({args_str})", self.mangle_name(callee)),
297 }
298 }
299
300 Expr::Cast { expr, .. } => self.emit_expr(expr),
301
302 Expr::FieldAccess { object, field } => {
303 let obj = self.emit_expr(object);
304 format!("{obj}.{field}")
305 }
306
307 Expr::Propagate { expr } => {
308 let inner = self.emit_expr(expr);
315 format!("__TERN_PROPAGATE({inner})")
316 }
317
318 Expr::Spawn { agent_name, .. } =>
319 format!("/* spawn {agent_name} — actor model not implemented in C backend */ 0"),
320 Expr::Await { target } => {
321 let t = self.emit_expr(target);
322 format!("/* await {t} — actor model not implemented in C backend */ 0")
323 }
324 Expr::NodeId => "/* nodeid */ 0".into(),
325 Expr::Index { object, row, col } => {
326 let obj = self.emit_expr(object);
327 let r = self.emit_expr(row);
328 let c = self.emit_expr(col);
329 format!("{obj}[{r}][{c}]")
330 }
331 Expr::FloatLiteral(v) => format!("{v}"),
332 Expr::TritTensorLiteral(elems) => {
333 let parts: Vec<String> = elems.iter().map(|e| e.to_string()).collect();
334 format!("/* trittensor{{{}}} */ 0", parts.join(", "))
335 }
336 Expr::StructLiteral { name, fields } => {
337 let f: Vec<String> = fields.iter()
338 .map(|(fname, val)| format!(".{fname} = {}", self.emit_expr(val)))
339 .collect();
340 format!("({}){{ {} }}", name, f.join(", "))
341 }
342 }
343 }
344
345 fn c_type(&self, ty: &Type) -> &'static str {
348 match ty {
349 Type::Trit => "trit",
350 Type::Int => "int64_t",
351 Type::Bool => "int8_t",
352 Type::Float => "double",
353 Type::String => "const char*",
354 Type::TritTensor { .. } => "trit*",
355 Type::IntTensor { .. } => "int64_t*",
356 Type::FloatTensor { .. } => "double*",
357 Type::Named(_) => "trit", Type::AgentRef => "int", }
360 }
361
362 fn c_params(&self, params: &[(String, Type)]) -> String {
363 if params.is_empty() {
364 return "void".into();
365 }
366 params.iter()
367 .map(|(name, ty)| format!("{} {name}", self.c_type(ty)))
368 .collect::<Vec<_>>()
369 .join(", ")
370 }
371
372 fn mangle_name(&self, name: &str) -> String {
374 match name {
375 "main" => "tern_main".into(),
376 other => other.to_string(),
377 }
378 }
379
380 fn push(&mut self, s: &str) {
381 let indent = " ".repeat(self.indent);
382 for line in s.split_inclusive('\n') {
383 if line == "\n" {
384 self.output.push('\n');
385 } else {
386 self.output.push_str(&indent);
387 self.output.push_str(line);
388 }
389 }
390 }
391}
392
393impl Default for CTranspiler {
394 fn default() -> Self { Self::new() }
395}
396
397#[cfg(test)]
400mod tests {
401 use super::*;
402 use ternlang_core::{Parser, StdlibLoader};
403
404 fn transpile(src: &str) -> String {
405 let mut parser = Parser::new(src);
406 let mut prog = parser.parse_program().expect("parse failed");
407 StdlibLoader::resolve(&mut prog);
408 CTranspiler::new().emit(&prog)
409 }
410
411 #[test]
412 fn emits_valid_c_header() {
413 let c = transpile("fn main() -> trit { return 1; }");
414 assert!(c.contains("typedef int8_t trit;"), "missing trit typedef");
415 assert!(c.contains("trit_consensus"), "missing consensus primitive");
416 }
417
418 #[test]
419 fn simple_return_emits_return_stmt() {
420 let c = transpile("fn main() -> trit { return 1; }");
421 assert!(c.contains("return 1;"), "missing return 1");
422 }
423
424 #[test]
425 fn consensus_call_maps_to_primitive() {
426 let c = transpile("fn main() -> trit { return consensus(1, -1); }");
427 assert!(c.contains("trit_consensus("), "consensus not mapped to trit_consensus");
428 }
429
430 #[test]
431 fn function_forward_declared() {
432 let c = transpile("fn helper() -> trit { return 0; } fn main() -> trit { return helper(); }");
433 let fwd_pos = c.find("trit helper(void);").unwrap_or(usize::MAX);
436 let body_pos = c.find("trit helper(void) {").unwrap_or(usize::MAX);
437 assert!(fwd_pos < body_pos, "forward declaration must precede body");
438 }
439
440 #[test]
441 fn match_emits_switch() {
442 let c = transpile(r#"
443fn main() -> trit {
444 let x: trit = 1;
445 match x {
446 1 => { return 1; }
447 0 => { return 0; }
448 -1 => { return -1; }
449 }
450}
451"#);
452 assert!(c.contains("switch"), "match should emit switch");
453 assert!(c.contains("case 1:"), "missing case 1");
454 assert!(c.contains("case 0:"), "missing case 0");
455 assert!(c.contains("case -1:"), "missing case -1");
456 }
457
458 #[test]
459 fn struct_emits_typedef_struct() {
460 let c = transpile(r#"
461struct Point { x: trit, y: trit }
462fn main() -> trit { return 0; }
463"#);
464 assert!(c.contains("typedef struct {"), "missing typedef struct");
465 assert!(c.contains("trit x;"), "missing field x");
466 }
467
468 #[test]
469 fn c_entry_point_calls_tern_main() {
470 let c = transpile("fn main() -> trit { return 1; }");
471 assert!(c.contains("int main(void)"), "missing C main");
472 assert!(c.contains("tern_main()"), "missing tern_main call");
473 }
474
475 #[test]
476 fn propagate_emits_helper_macro() {
477 let c = transpile(r#"
478fn check() -> trit { return -1; }
479fn main() -> trit { return check()?; }
480"#);
481 assert!(c.contains("__TERN_PROPAGATE"), "missing propagate macro");
482 }
483
484}