import "../std/plugin.zc" include include include include fn skip_whitespace(p: char**) { let ptr = *p; while (ptr[0] != 0 && isspace((int)ptr[0])) { ptr = &ptr[1]; } *p = ptr; } fn parse_lisp_expr(p: char**, api: ZApi*, depth: int); fn parse_atom(p: char**, api: ZApi*) { let out = api.out; let ptr = *p; let start = ptr; if (ptr[0] == ')') { api.error(api, "Unexpected ')' in Lisp expression"); return; } // Number if (isdigit((int)ptr[0]) || (ptr[0] == '-' && isdigit((int)ptr[1]))) { if (ptr[0] == '-') ptr = &ptr[1]; while (ptr[0] != 0 && isdigit((int)ptr[0])) { ptr = &ptr[1]; } fputs("l_num(", out); fwrite(start, 1, (size_t)(ptr - start), out); fputs(")", out); *p = ptr; return; } if (ptr[0] == '"') { ptr = &ptr[1]; while (ptr[0] != 0 && ptr[0] != '"') { if (ptr[0] == '\\') ptr = &ptr[1]; ptr = &ptr[1]; } if (ptr[0] == '"') ptr = &ptr[1]; fputs("l_nil()", out); *p = ptr; return; } // Symbol while (ptr[0] != 0 && !isspace((int)ptr[0]) && ptr[0] != ')' && ptr[0] != '(') { ptr = &ptr[1]; } fwrite(start, 1, (size_t)(ptr - start), out); *p = ptr; } fn parse_lisp_list(p: char**, api: ZApi*, depth: int) { let out = api.out; let ptr = *p; ptr = &ptr[1]; // consume ( *p = ptr; skip_whitespace(p); ptr = *p; if (ptr[0] == 0) { api.error(api, "Unclosed parenthesis (unexpected EOF) in Lisp list"); return; } let op_start = ptr; while (ptr[0] != 0 && !isspace((int)ptr[0]) && ptr[0] != ')' && ptr[0] != '(') { ptr = &ptr[1]; } let op_len = (int)(ptr - op_start); *p = ptr; // Arithmetic if (op_len == 1 && strchr("+-*/", (int)op_start[0]) != (char*)0) { let op_char = op_start[0]; let func = "l_add"; match (int)op_char { 45 => func = "l_sub", 42 => func = "l_mul", 47 => func = "l_div", _ => (void)0 } fprintf(out, "%s(", func); skip_whitespace(p); parse_lisp_expr(p, api, depth + 1); fputs(", ", out); skip_whitespace(p); parse_lisp_expr(p, api, depth + 1); fputs(")", out); skip_whitespace(p); ptr = *p; while (ptr[0] != 0 && ptr[0] != ')') { if (ptr[0] == '(') { let d = 1; ptr = &ptr[1]; while (d > 0 && ptr[0] != 0) { if (ptr[0] == '(') d = d + 1; if (ptr[0] == ')') d = d - 1; ptr = &ptr[1]; } } else { while (ptr[0] != 0 && !isspace((int)ptr[0]) && ptr[0] != ')') { ptr = &ptr[1]; } } *p = ptr; skip_whitespace(p); ptr = *p; } *p = ptr; } else if (strncmp(op_start, "print", 5) == 0) { skip_whitespace(p); ptr = *p; if (ptr[0] == '"') { fputs("printf(\x22", out); ptr = &ptr[1]; while (ptr[0] != 0 && ptr[0] != '"') { if (ptr[0] == '\\') { fputs("\\", out); ptr = &ptr[1]; if (ptr[0] != 0) { fprintf(out, "%c", (int)ptr[0]); ptr = &ptr[1]; } } else { fprintf(out, "%c", (int)ptr[0]); ptr = &ptr[1]; } } let ln_str: char*; if (op_start[5] == 'l') { ln_str = "\\n"; } else { ln_str = ""; } fprintf(out, "%s\x22)", ln_str); if (ptr[0] == '"') ptr = &ptr[1]; *p = ptr; } else { fputs("l_print(", out); parse_lisp_expr(p, api, depth + 1); let print_stmt: char*; if (op_start[5] == 'l') { print_stmt = " printf(\x22\\n\x22);"; } else { print_stmt = ""; } fprintf(out, ")%s", print_stmt); } } else if (op_len == 5 && strncmp(op_start, "defun", 5) == 0) { skip_whitespace(p); ptr = *p; let nstart = ptr; while (ptr[0] != 0 && !isspace((int)ptr[0]) && ptr[0] != '(') { ptr = &ptr[1]; } let h = api.hoist_out; if (h == (void*)0) h = out; // Fallback to inline if hoisting unavailable // Forward declaration in case of mutual recursion fputs("static LVal ", h); fwrite(nstart, 1, (size_t)(ptr - nstart), h); fputs("(LVal", h); // simplified check for args // (Actually adding full forward decl is complex without parsing params twice, // but the hoist out is usually at top level and the runtime is above it.) fputs("); \n", h); fputs("static LVal ", h); fwrite(nstart, 1, (size_t)(ptr - nstart), h); fputs("(", h); *p = ptr; skip_whitespace(p); ptr = *p; ptr = &ptr[1]; // eat ( *p = ptr; skip_whitespace(p); ptr = *p; let first = 1; while (ptr[0] != 0 && ptr[0] != ')') { if (first == 0) fputs(", ", h); first = 0; fputs("LVal ", h); let astart = ptr; while (ptr[0] != 0 && !isspace((int)ptr[0]) && ptr[0] != ')') { ptr = &ptr[1]; } fwrite(astart, 1, (size_t)(ptr - astart), h); *p = ptr; skip_whitespace(p); ptr = *p; } ptr = &ptr[1]; // eat ) fputs(f") {{ \n return ({{ \n", h); *p = ptr; skip_whitespace(p); ptr = *p; let old_out = api.out; api.out = h; while (ptr[0] != 0 && ptr[0] != ')') { *p = ptr; parse_lisp_expr(p, api, depth + 1); fputs(";\n", h); skip_whitespace(p); ptr = *p; } api.out = old_out; fputs(f"}});\n}}\n", h); *p = ptr; // The defun expression itself in the current stream returns nil fputs("nil", out); } else { fwrite(op_start, 1, (size_t)op_len, out); fputs("(", out); skip_whitespace(p); let first = 1; ptr = *p; while (ptr[0] != 0 && ptr[0] != ')') { if (first == 0) fputs(", ", out); first = 0; *p = ptr; parse_lisp_expr(p, api, depth + 1); skip_whitespace(p); ptr = *p; } fputs(")", out); *p = ptr; } ptr = *p; while (ptr[0] != 0 && ptr[0] != ')') { ptr = &ptr[1]; } if (ptr[0] == ')') ptr = &ptr[1]; *p = ptr; } fn parse_lisp_expr(p: char**, api: ZApi*, depth: int) { skip_whitespace(p); let ptr = *p; if (ptr[0] == 0) return; if (ptr[0] == '(') { parse_lisp_list(p, api, depth); } else { parse_atom(p, api); } } fn lisp_transpile(input_body: char*, api: ZApi*) { let out = api.out; let p = input_body; static let runtime_emitted = 0; if (runtime_emitted == 0 && api.hoist_out != (void*)0) { let h = api.hoist_out; fputs(f"""/* Lisp Runtime */ typedef enum {{ L_NUM, L_PAIR, L_NIL }} LType; typedef struct z_LVal {{ LType type; union {{ long num; struct {{ struct z_LVal *car; struct z_LVal *cdr; }} pair; }}; }} *LVal; static struct z_LVal _nil = {{ L_NIL }}; static LVal LNIL = &_nil; static LVal nil = &_nil; static LVal l_num(long n) {{ LVal v = (LVal)malloc(sizeof(struct z_LVal)); v->type=L_NUM; v->num=n; return v; }} static LVal l_nil() {{ return LNIL; }} static LVal l_cons(LVal a, LVal b) {{ LVal v = (LVal)malloc(sizeof(struct z_LVal)); v->type=L_PAIR; v->pair.car=a; v->pair.cdr=b; return v; }} static LVal l_car(LVal v) {{ return (v && v->type==L_PAIR) ? v->pair.car : LNIL; }} static LVal l_cdr(LVal v) {{ return (v && v->type==L_PAIR) ? v->pair.cdr : LNIL; }} static int l_truthy(LVal v) {{ return (v && v->type!=L_NIL); }} static LVal l_add(LVal a, LVal b) {{ long x=(a&&a->type==L_NUM)?a->num:0; long y=(b&&b->type==L_NUM)?b->num:0; return l_num(x+y); }} static LVal l_sub(LVal a, LVal b) {{ long x=(a&&a->type==L_NUM)?a->num:0; long y=(b&&b->type==L_NUM)?b->num:0; return l_num(x-y); }} static LVal l_mul(LVal a, LVal b) {{ long x=(a&&a->type==L_NUM)?a->num:0; long y=(b&&b->type==L_NUM)?b->num:0; return l_num(x*y); }} static LVal l_div(LVal a, LVal b) {{ long x=(a&&a->type==L_NUM)?a->num:0; long y=(b&&b->type==L_NUM)?b->num:0; return l_num(y?x/y:0); }} static LVal l_lt(LVal a, LVal b) {{ long x=(a&&a->type==L_NUM)?a->num:0; long y=(b&&b->type==L_NUM)?b->num:0; return (xtype==L_NIL) printf("nil"); else if(v->type==L_NUM) printf("%ld", v->num); else if(v->type==L_PAIR) {{ printf("("); l_print(v->pair.car); printf(" . "); l_print(v->pair.cdr); printf(")"); }} }} """, h); runtime_emitted = 1; } fputs(f"({{ \n", out); while (p[0] != 0) { skip_whitespace(&p); if (p[0] == 0) break; parse_lisp_expr(&p, api, 0); fputs(";\n", out); } fputs(f"}});\n", out); } let lisp_plugin = ZPlugin { name: "lisp", handler: lisp_transpile }; @export fn z_plugin_init() -> ZPlugin* { return &lisp_plugin; }