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 let val = match pattern {
179 Pattern::Int(v) => *v,
180 Pattern::Trit(t) => *t as i64,
181 Pattern::Float(f) => *f as i64,
182 };
183 self.push(&format!("case {val}: "));
184 self.emit_stmt(arm);
185 self.push("break;\n");
186 }
187 self.indent -= 1;
188 self.push("}\n");
189 }
190 Stmt::WhileTernary { condition, on_pos, on_zero, on_neg } => {
191 let cond = self.emit_expr(condition);
192 self.push(&format!("while (1) {{\n"));
194 self.indent += 1;
195 self.push(&format!("trit __cond = {cond};\n"));
196 self.push("if (__cond > 0) ");
197 self.emit_stmt(on_pos);
198 self.push("else if (__cond == 0) ");
199 self.emit_stmt(on_zero);
200 self.push("else ");
201 self.emit_stmt(on_neg);
202 self.indent -= 1;
203 self.push("}\n");
204 }
205 Stmt::Loop { body } => {
206 self.push("for (;;) ");
207 self.emit_stmt(body);
208 }
209 Stmt::ForIn { var, iter, body } => {
210 let iter_expr = self.emit_expr(iter);
212 self.push(&format!("/* for {var} in {iter_expr}: tensor iteration omitted in C backend */\n"));
213 let _ = body;
214 }
215 Stmt::Break => self.push("break;\n"),
216 Stmt::Continue => self.push("continue;\n"),
217 Stmt::Use { .. } => { }
218 Stmt::FromImport { .. } => { }
219 Stmt::Send { target, message } => {
220 let t = self.emit_expr(target);
221 let m = self.emit_expr(message);
222 self.push(&format!("/* send {m} to agent {t} — actor model not implemented in C backend */\n"));
223 }
224 Stmt::FieldSet { object, field, value } => {
225 let val = self.emit_expr(value);
226 self.push(&format!("{object}.{field} = {val};\n"));
227 }
228 Stmt::Decorated { stmt, .. } => self.emit_stmt(stmt),
229 Stmt::IndexSet { object, row, col, value } => {
230 let r = self.emit_expr(row);
231 let c = self.emit_expr(col);
232 let val = self.emit_expr(value);
233 self.push(&format!("{object}[{r}][{c}] = {val};\n"));
234 }
235 Stmt::Set { name, value } => {
236 let val = self.emit_expr(value);
237 self.push(&format!("{name} = {val};\n"));
238 }
239 }
240 }
241
242 fn emit_expr(&self, expr: &Expr) -> String {
245 match expr {
246 Expr::TritLiteral(v) => format!("((trit){v})"),
247 Expr::IntLiteral(v) => format!("{v}"),
248 Expr::StringLiteral(s) => format!("\"{}\"", s.replace('"', "\\\"")),
249 Expr::Ident(name) => name.clone(),
250
251 Expr::BinaryOp { op, lhs, rhs } => {
252 let l = self.emit_expr(lhs);
253 let r = self.emit_expr(rhs);
254 match op {
255 BinOp::Add => format!("trit_add({l}, {r})"),
256 BinOp::Sub => format!("trit_add({l}, trit_neg({r}))"),
257 BinOp::Mul => format!("trit_mul({l}, {r})"),
258 BinOp::Equal => format!("trit_consensus({l}, {r})"),
259 BinOp::NotEqual => format!("trit_neg(trit_consensus({l}, {r}))"),
260 BinOp::And => format!("trit_mul({l}, {r})"),
261 BinOp::Or => format!("trit_consensus({l}, {r})"),
262 BinOp::Less => format!("(({l}) < ({r}) ? 1 : (({l}) == ({r}) ? 0 : -1))"),
263 BinOp::Greater => format!("(({l}) > ({r}) ? 1 : (({l}) == ({r}) ? 0 : -1))"),
264 BinOp::LessEqual => format!("(({l}) <= ({r}) ? 1 : -1)"),
265 BinOp::GreaterEqual=> format!("(({l}) >= ({r}) ? 1 : -1)"),
266 BinOp::Div => format!("(({l}) / ({r}))"),
267 BinOp::Mod => format!("(({l}) % ({r}))"),
268 }
269 }
270
271 Expr::UnaryOp { op: UnOp::Neg, expr } => {
272 let inner = self.emit_expr(expr);
273 format!("trit_neg({inner})")
274 }
275
276 Expr::Call { callee, args } => {
277 let a: Vec<String> = args.iter().map(|a| self.emit_expr(a)).collect();
278 let args_str = a.join(", ");
279 match callee.as_str() {
281 "consensus" => format!("trit_consensus({args_str})"),
282 "invert" => format!("trit_invert({args_str})"),
283 "truth" => "trit_truth()".into(),
284 "hold" => "trit_hold()".into(),
285 "conflict" => "trit_conflict()".into(),
286 "abs" => format!("trit_abs({args_str})"),
287 "min" => format!("trit_min({args_str})"),
288 "max" => format!("trit_max({args_str})"),
289 _ => format!("{}({args_str})", self.mangle_name(callee)),
290 }
291 }
292
293 Expr::Cast { expr, .. } => self.emit_expr(expr),
294
295 Expr::FieldAccess { object, field } => {
296 let obj = self.emit_expr(object);
297 format!("{obj}.{field}")
298 }
299
300 Expr::Propagate { expr } => {
301 let inner = self.emit_expr(expr);
308 format!("__TERN_PROPAGATE({inner})")
309 }
310
311 Expr::Spawn { agent_name, .. } =>
312 format!("/* spawn {agent_name} — actor model not implemented in C backend */ 0"),
313 Expr::Await { target } => {
314 let t = self.emit_expr(target);
315 format!("/* await {t} — actor model not implemented in C backend */ 0")
316 }
317 Expr::NodeId => "/* nodeid */ 0".into(),
318 Expr::Index { object, row, col } => {
319 let obj = self.emit_expr(object);
320 let r = self.emit_expr(row);
321 let c = self.emit_expr(col);
322 format!("{obj}[{r}][{c}]")
323 }
324 Expr::FloatLiteral(v) => format!("{v}"),
325 Expr::TritTensorLiteral(elems) => {
326 let parts: Vec<String> = elems.iter().map(|e| e.to_string()).collect();
327 format!("/* trittensor{{{}}} */ 0", parts.join(", "))
328 }
329 Expr::StructLiteral { name, fields } => {
330 let f: Vec<String> = fields.iter()
331 .map(|(fname, val)| format!(".{fname} = {}", self.emit_expr(val)))
332 .collect();
333 format!("({}){{ {} }}", name, f.join(", "))
334 }
335 }
336 }
337
338 fn c_type(&self, ty: &Type) -> &'static str {
341 match ty {
342 Type::Trit => "trit",
343 Type::Int => "int64_t",
344 Type::Bool => "int8_t",
345 Type::Float => "double",
346 Type::String => "const char*",
347 Type::TritTensor { .. } => "trit*",
348 Type::IntTensor { .. } => "int64_t*",
349 Type::FloatTensor { .. } => "double*",
350 Type::Named(_) => "trit", Type::AgentRef => "int", }
353 }
354
355 fn c_params(&self, params: &[(String, Type)]) -> String {
356 if params.is_empty() {
357 return "void".into();
358 }
359 params.iter()
360 .map(|(name, ty)| format!("{} {name}", self.c_type(ty)))
361 .collect::<Vec<_>>()
362 .join(", ")
363 }
364
365 fn mangle_name(&self, name: &str) -> String {
367 match name {
368 "main" => "tern_main".into(),
369 other => other.to_string(),
370 }
371 }
372
373 fn push(&mut self, s: &str) {
374 let indent = " ".repeat(self.indent);
375 for line in s.split_inclusive('\n') {
376 if line == "\n" {
377 self.output.push('\n');
378 } else {
379 self.output.push_str(&indent);
380 self.output.push_str(line);
381 }
382 }
383 }
384}
385
386impl Default for CTranspiler {
387 fn default() -> Self { Self::new() }
388}
389
390#[cfg(test)]
393mod tests {
394 use super::*;
395 use ternlang_core::{Parser, StdlibLoader};
396
397 fn transpile(src: &str) -> String {
398 let mut parser = Parser::new(src);
399 let mut prog = parser.parse_program().expect("parse failed");
400 StdlibLoader::resolve(&mut prog);
401 CTranspiler::new().emit(&prog)
402 }
403
404 #[test]
405 fn emits_valid_c_header() {
406 let c = transpile("fn main() -> trit { return 1; }");
407 assert!(c.contains("typedef int8_t trit;"), "missing trit typedef");
408 assert!(c.contains("trit_consensus"), "missing consensus primitive");
409 }
410
411 #[test]
412 fn simple_return_emits_return_stmt() {
413 let c = transpile("fn main() -> trit { return 1; }");
414 assert!(c.contains("return 1;"), "missing return 1");
415 }
416
417 #[test]
418 fn consensus_call_maps_to_primitive() {
419 let c = transpile("fn main() -> trit { return consensus(1, -1); }");
420 assert!(c.contains("trit_consensus("), "consensus not mapped to trit_consensus");
421 }
422
423 #[test]
424 fn function_forward_declared() {
425 let c = transpile("fn helper() -> trit { return 0; } fn main() -> trit { return helper(); }");
426 let fwd_pos = c.find("trit helper(void);").unwrap_or(usize::MAX);
429 let body_pos = c.find("trit helper(void) {").unwrap_or(usize::MAX);
430 assert!(fwd_pos < body_pos, "forward declaration must precede body");
431 }
432
433 #[test]
434 fn match_emits_switch() {
435 let c = transpile(r#"
436fn main() -> trit {
437 let x: trit = 1;
438 match x {
439 1 => { return 1; }
440 0 => { return 0; }
441 -1 => { return -1; }
442 }
443}
444"#);
445 assert!(c.contains("switch"), "match should emit switch");
446 assert!(c.contains("case 1:"), "missing case 1");
447 assert!(c.contains("case 0:"), "missing case 0");
448 assert!(c.contains("case -1:"), "missing case -1");
449 }
450
451 #[test]
452 fn struct_emits_typedef_struct() {
453 let c = transpile(r#"
454struct Point { x: trit, y: trit }
455fn main() -> trit { return 0; }
456"#);
457 assert!(c.contains("typedef struct {"), "missing typedef struct");
458 assert!(c.contains("trit x;"), "missing field x");
459 }
460
461 #[test]
462 fn c_entry_point_calls_tern_main() {
463 let c = transpile("fn main() -> trit { return 1; }");
464 assert!(c.contains("int main(void)"), "missing C main");
465 assert!(c.contains("tern_main()"), "missing tern_main call");
466 }
467
468 #[test]
469 fn propagate_emits_helper_macro() {
470 let c = transpile(r#"
471fn check() -> trit { return -1; }
472fn main() -> trit { return check()?; }
473"#);
474 assert!(c.contains("__TERN_PROPAGATE"), "missing propagate macro");
475 }
476
477}