summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--plugins/befunge.c11
-rw-r--r--plugins/brainfuck.c4
-rw-r--r--plugins/forth.c5
-rw-r--r--plugins/lisp.c36
-rw-r--r--plugins/regex.c5
-rw-r--r--plugins/sql.c4
-rw-r--r--src/analysis/typecheck.c2
-rw-r--r--src/ast/ast.c6
-rw-r--r--src/ast/ast.h16
-rw-r--r--src/codegen/codegen.c26
-rw-r--r--src/codegen/codegen.h4
-rw-r--r--src/codegen/codegen_decl.c98
-rw-r--r--src/codegen/codegen_main.c11
-rw-r--r--src/codegen/codegen_utils.c19
-rw-r--r--src/lsp/json_rpc.c16
-rw-r--r--src/lsp/lsp_analysis.c27
-rw-r--r--src/lsp/lsp_index.c2
-rw-r--r--src/lsp/lsp_main.c2
-rw-r--r--src/main.c17
-rw-r--r--src/parser/parser.h5
-rw-r--r--src/parser/parser_core.c4
-rw-r--r--src/parser/parser_expr.c375
-rw-r--r--src/parser/parser_stmt.c101
-rw-r--r--src/parser/parser_type.c15
-rw-r--r--src/parser/parser_utils.c147
-rw-r--r--src/plugins/plugin_manager.c2
-rw-r--r--src/repl/repl.c94
-rw-r--r--src/utils/utils.c2
-rw-r--r--src/zen/zen_facts.c222
-rw-r--r--src/zprep.h4
30 files changed, 747 insertions, 535 deletions
diff --git a/plugins/befunge.c b/plugins/befunge.c
index 844e27f..92165f4 100644
--- a/plugins/befunge.c
+++ b/plugins/befunge.c
@@ -80,7 +80,8 @@ void befunge_transpile(const char *input_body, const ZApi *api)
if (op >= '0' && op <= '9')
{
fprintf(out,
- " if(string_mode) { stack[sp++] = '%c'; } else { stack[sp++] = %c; }\n",
+ " if(string_mode) { stack[sp++] = '%c'; } else { "
+ "stack[sp++] = %c; }\n",
op, op);
}
else if (op == '"')
@@ -119,13 +120,13 @@ void befunge_transpile(const char *input_body, const ZApi *api)
}
else if (op == '/')
{
- fprintf(out,
- " { long a=stack[--sp]; stack[sp-1]= (a!=0)?stack[sp-1]/a:0; }\n");
+ fprintf(out, " { long a=stack[--sp]; stack[sp-1]= "
+ "(a!=0)?stack[sp-1]/a:0; }\n");
}
else if (op == '%')
{
- fprintf(out,
- " { long a=stack[--sp]; stack[sp-1]= (a!=0)?stack[sp-1]%%a:0; }\n");
+ fprintf(out, " { long a=stack[--sp]; stack[sp-1]= "
+ "(a!=0)?stack[sp-1]%%a:0; }\n");
}
else if (op == '!')
{
diff --git a/plugins/brainfuck.c b/plugins/brainfuck.c
index e800da7..576029b 100644
--- a/plugins/brainfuck.c
+++ b/plugins/brainfuck.c
@@ -4,8 +4,8 @@
void bf_transpile(const char *input_body, const ZApi *api)
{
FILE *out = api->out;
- fprintf(out,
- "{\n static unsigned char tape[30000] = {0};\n unsigned char *ptr = tape;\n");
+ fprintf(out, "{\n static unsigned char tape[30000] = {0};\n unsigned "
+ "char *ptr = tape;\n");
const char *c = input_body;
while (*c)
{
diff --git a/plugins/forth.c b/plugins/forth.c
index 9d39c6d..90e05c6 100644
--- a/plugins/forth.c
+++ b/plugins/forth.c
@@ -1,9 +1,9 @@
#include "zprep_plugin.h"
+#include <math.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <math.h>
static long stack[256];
static int sp = 0;
@@ -598,7 +598,8 @@ void process_forth_source(char *src, char **out_ptr)
void load_prelude()
{
- char prelude[] = ": squared fdup f* ; : hypot squared fswap squared f+ fsqrt ; : over swap dup "
+ char prelude[] = ": squared fdup f* ; : hypot squared fswap squared f+ fsqrt "
+ "; : over swap dup "
"rot rot ; : panic 0 1 - exit ; ";
char dummy_buf[1024];
dummy_buf[0] = '\0';
diff --git a/plugins/lisp.c b/plugins/lisp.c
index 7147928..439dd16 100644
--- a/plugins/lisp.c
+++ b/plugins/lisp.c
@@ -1,9 +1,9 @@
#include "zprep_plugin.h"
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
static void skip_whitespace(const char **p)
{
@@ -421,36 +421,42 @@ void lisp_transpile(const char *input_body, const ZApi *api)
FILE *h = api->hoist_out;
fprintf(h, "/* Lisp Runtime */\n");
fprintf(h, "typedef enum { L_NUM, L_PAIR, L_NIL } LType;\n");
- fprintf(h, "typedef struct LVal { LType type; union { long num; struct { struct LVal *car; "
+ fprintf(h, "typedef struct LVal { LType type; union { long num; struct { "
+ "struct LVal *car; "
"struct LVal *cdr; } pair; }; } *LVal;\n");
fprintf(h, "static struct LVal _nil = { L_NIL }; static LVal LNIL = &_nil;\n");
fprintf(h, "static LVal nil = &_nil;\n"); // Use static for file scope
fprintf(h, "static LVal l_num(long n) { LVal v = malloc(sizeof(struct LVal)); "
"v->type=L_NUM; v->num=n; return v; }\n");
fprintf(h, "static LVal l_nil() { return LNIL; }\n");
- fprintf(h, "static LVal l_cons(LVal a, LVal b) { LVal v = malloc(sizeof(struct LVal)); "
+ fprintf(h, "static LVal l_cons(LVal a, LVal b) { LVal v = "
+ "malloc(sizeof(struct LVal)); "
"v->type=L_PAIR; v->pair.car=a; v->pair.cdr=b; return v; }\n");
- fprintf(
- h,
- "static LVal l_car(LVal v) { return (v && v->type==L_PAIR) ? v->pair.car : LNIL; }\n");
- fprintf(
- h,
- "static LVal l_cdr(LVal v) { return (v && v->type==L_PAIR) ? v->pair.cdr : LNIL; }\n");
+ fprintf(h, "static LVal l_car(LVal v) { return (v && v->type==L_PAIR) ? "
+ "v->pair.car : LNIL; }\n");
+ fprintf(h, "static LVal l_cdr(LVal v) { return (v && v->type==L_PAIR) ? "
+ "v->pair.cdr : LNIL; }\n");
fprintf(h, "static int l_truthy(LVal v) { return (v && v->type!=L_NIL); }\n");
- fprintf(h, "static LVal l_add(LVal a, LVal b) { long x=(a&&a->type==L_NUM)?a->num:0; long "
+ fprintf(h, "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); }\n");
- fprintf(h, "static LVal l_sub(LVal a, LVal b) { long x=(a&&a->type==L_NUM)?a->num:0; long "
+ fprintf(h, "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); }\n");
- fprintf(h, "static LVal l_mul(LVal a, LVal b) { long x=(a&&a->type==L_NUM)?a->num:0; long "
+ fprintf(h, "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); }\n");
- fprintf(h, "static LVal l_div(LVal a, LVal b) { long x=(a&&a->type==L_NUM)?a->num:0; long "
+ fprintf(h, "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); }\n");
- fprintf(h, "static LVal l_lt(LVal a, LVal b) { long x=(a&&a->type==L_NUM)?a->num:0; long "
+ fprintf(h, "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 (x<y)?l_num(1):LNIL; }\n");
fprintf(h, "static void l_print(LVal v) { \n");
fprintf(h, " if(!v || v->type==L_NIL) printf(\"nil\");\n");
fprintf(h, " else if(v->type==L_NUM) printf(\"%%ld\", v->num);\n");
- fprintf(h, " else if(v->type==L_PAIR) { printf(\"(\"); l_print(v->pair.car); printf(\" . "
+ fprintf(h, " else if(v->type==L_PAIR) { printf(\"(\"); "
+ "l_print(v->pair.car); printf(\" . "
"\"); l_print(v->pair.cdr); printf(\")\"); }\n");
fprintf(h, "}\n");
diff --git a/plugins/regex.c b/plugins/regex.c
index d7a8a97..b56515c 100644
--- a/plugins/regex.c
+++ b/plugins/regex.c
@@ -1,9 +1,9 @@
#include "zprep_plugin.h"
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
static void emit_match_logic(const char *pattern, FILE *out, int *label_counter);
@@ -111,7 +111,8 @@ static void emit_match_logic(const char *pattern, FILE *out, int * /*label_count
}
else
{
- fprintf(out, " if (*c == 0) return 0;\n"); // End of input for single char
+ fprintf(out,
+ " if (*c == 0) return 0;\n"); // End of input for single char
}
fprintf(out, " int match = 0;\n");
diff --git a/plugins/sql.c b/plugins/sql.c
index 0c563e2..130317f 100644
--- a/plugins/sql.c
+++ b/plugins/sql.c
@@ -1,14 +1,14 @@
#include "zprep_plugin.h"
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
typedef struct Col
{
char name[32];
- char type[32];
+ char type[32];
struct Col *next;
} Col;
diff --git a/src/analysis/typecheck.c b/src/analysis/typecheck.c
index 4a172d8..903cb75 100644
--- a/src/analysis/typecheck.c
+++ b/src/analysis/typecheck.c
@@ -1,8 +1,8 @@
+#include "typecheck.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "typecheck.h"
// ** Internal Helpers **
diff --git a/src/ast/ast.c b/src/ast/ast.c
index 4688bf7..f34370e 100644
--- a/src/ast/ast.c
+++ b/src/ast/ast.c
@@ -1,9 +1,9 @@
-#include <stdlib.h>
-#include <string.h>
#include "ast.h"
-#include "zprep.h"
#include "../parser/parser.h"
+#include "zprep.h"
+#include <stdlib.h>
+#include <string.h>
typedef struct TraitReg
{
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 67dc2f3..0da2c0d 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -2,8 +2,8 @@
#ifndef AST_H
#define AST_H
-#include <stdlib.h>
#include "zprep.h"
+#include <stdlib.h>
// Forward declarations.
struct ASTNode;
@@ -129,12 +129,13 @@ struct ASTNode
int line; // Source line number for debugging.
// Type information.
- char *resolved_type; // Legacy string representation (for example: "int", "User*").
- // > Yes, 'legacy' is a thing, this is the third iteration
- // > of this project (for now).
+ char *resolved_type; // Legacy string representation (for example: "int",
+ // "User*"). > Yes, 'legacy' is a thing, this is the
+ // third iteration > of this project (for now).
Type *type_info; // Formal type object (for inference/generics).
Token token;
- Token definition_token; // For LSP: Location where the symbol used in this node was defined.
+ Token definition_token; // For LSP: Location where the symbol used in this
+ // node was defined.
union
{
@@ -375,8 +376,9 @@ struct ASTNode
char *generic_param;
char *parent;
int is_union;
- int is_packed; // @packed attribute.
- int align; // @align(N) attribute, 0 = default.
+ int is_packed; // @packed attribute.
+ int align; // @align(N) attribute, 0 = default.
+ int is_incomplete; // Forward declaration (prototype)
} strct;
struct
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c
index abffe84..1592806 100644
--- a/src/codegen/codegen.c
+++ b/src/codegen/codegen.c
@@ -1,10 +1,10 @@
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
#include "codegen.h"
#include "zprep.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
#include "../plugins/plugin_manager.h"
#include "ast.h"
@@ -436,7 +436,9 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
case NODE_LAMBDA:
if (node->lambda.num_captures > 0)
{
- fprintf(out, "({ struct Lambda_%d_Ctx *ctx = malloc(sizeof(struct Lambda_%d_Ctx));\n",
+ fprintf(out,
+ "({ struct Lambda_%d_Ctx *ctx = malloc(sizeof(struct "
+ "Lambda_%d_Ctx));\n",
node->lambda.lambda_id, node->lambda.lambda_id);
for (int i = 0; i < node->lambda.num_captures; i++)
{
@@ -818,7 +820,9 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
if (is_slice_struct)
{
- fprintf(out, "(Slice_%s){ .data = _arr.data + _start, .len = _len, .cap = _len }; })",
+ fprintf(out,
+ "(Slice_%s){ .data = _arr.data + _start, .len = _len, .cap = "
+ "_len }; })",
tname);
}
else
@@ -863,7 +867,8 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
fprintf(out, " _try = ");
codegen_expression(ctx, node->try_stmt.expr, out);
fprintf(out,
- "; if (_try.tag == %s_Err_Tag) return (%s_Err(_try.data.Err)); _try.data.Ok; })",
+ "; if (_try.tag == %s_Err_Tag) return (%s_Err(_try.data.Err)); "
+ "_try.data.Ok; })",
type_name, type_name);
break;
}
@@ -1901,7 +1906,8 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
emit_auto_type(ctx, node->repl_print.expr, node->token, out);
fprintf(out, " _zval = (");
codegen_expression(ctx, node->repl_print.expr, out);
- fprintf(out, "); fprintf(stdout, _z_str(_zval), _zval); fprintf(stdout, \"\\n\"); }\n");
+ fprintf(out, "); fprintf(stdout, _z_str(_zval), _zval); fprintf(stdout, "
+ "\"\\n\"); }\n");
break;
}
case NODE_AWAIT:
@@ -1922,8 +1928,8 @@ void codegen_node_single(ParserContext *ctx, ASTNode *node, FILE *out)
ret_type = node->resolved_type;
}
- // Fallback: If type is still Async/void* (likely from Future type, not Result type), try to
- // infer
+ // Fallback: If type is still Async/void* (likely from Future type, not
+ // Result type), try to infer
if (strcmp(ret_type, "Async") == 0 || strcmp(ret_type, "void*") == 0)
{
char *inf = infer_type(ctx, node);
diff --git a/src/codegen/codegen.h b/src/codegen/codegen.h
index a7f3df3..d489fb3 100644
--- a/src/codegen/codegen.h
+++ b/src/codegen/codegen.h
@@ -2,10 +2,10 @@
#ifndef CODEGEN_H
#define CODEGEN_H
-#include <stdio.h>
-#include "../zprep.h"
#include "../ast/ast.h"
#include "../parser/parser.h"
+#include "../zprep.h"
+#include <stdio.h>
// Main codegen entry points.
void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out);
diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c
index 8c8af97..b009a64 100644
--- a/src/codegen/codegen_decl.c
+++ b/src/codegen/codegen_decl.c
@@ -1,11 +1,11 @@
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include "codegen.h"
-#include "../zprep.h"
#include "../ast/ast.h"
#include "../parser/parser.h"
+#include "../zprep.h"
+#include "codegen.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
// Emit C preamble with standard includes and type definitions.
void emit_preamble(FILE *out)
@@ -14,15 +14,16 @@ void emit_preamble(FILE *out)
{
// Freestanding preamble.
// It actually needs more work, but yk.
- fputs(
- "#include <stddef.h>\n#include <stdint.h>\n#include <stdbool.h>\n#include <stdarg.h>\n",
- out);
+ fputs("#include <stddef.h>\n#include <stdint.h>\n#include "
+ "<stdbool.h>\n#include <stdarg.h>\n",
+ out);
fputs("#ifdef __TINYC__\n#define __auto_type __typeof__\n#endif\n", out);
fputs("typedef size_t usize;\ntypedef char* string;\n", out);
fputs("#define U0 void\n#define I8 int8_t\n#define U8 uint8_t\n#define I16 "
"int16_t\n#define U16 uint16_t\n",
out);
- fputs("#define I32 int32_t\n#define U32 uint32_t\n#define I64 int64_t\n#define U64 "
+ fputs("#define I32 int32_t\n#define U32 uint32_t\n#define I64 "
+ "int64_t\n#define U64 "
"uint64_t\n",
out);
fputs("#define F32 float\n#define F64 double\n", out);
@@ -36,7 +37,9 @@ void emit_preamble(FILE *out)
fputs("typedef struct { void *func; void *ctx; } z_closure_T;\n", out);
fputs("__attribute__((weak)) void* z_malloc(usize sz) { return NULL; }\n", out);
- fputs("__attribute__((weak)) void* z_realloc(void* ptr, usize sz) { return NULL; }\n", out);
+ fputs("__attribute__((weak)) void* z_realloc(void* ptr, usize sz) { return "
+ "NULL; }\n",
+ out);
fputs("__attribute__((weak)) void z_free(void* ptr) { }\n", out);
fputs("__attribute__((weak)) void z_print(const char* fmt, ...) { }\n", out);
fputs("__attribute__((weak)) void z_panic(const char* msg) { while(1); }\n", out);
@@ -44,7 +47,8 @@ void emit_preamble(FILE *out)
else
{
// Standard hosted preamble.
- fputs("#include <stdio.h>\n#include <stdlib.h>\n#include <stddef.h>\n#include <string.h>\n",
+ fputs("#include <stdio.h>\n#include <stdlib.h>\n#include "
+ "<stddef.h>\n#include <string.h>\n",
out);
fputs("#include <stdarg.h>\n#include <stdint.h>\n#include <stdbool.h>\n", out);
fputs("#include <unistd.h>\n#include <fcntl.h>\n", out); // POSIX functions
@@ -56,7 +60,8 @@ void emit_preamble(FILE *out)
fputs("#define U0 void\n#define I8 int8_t\n#define U8 uint8_t\n#define I16 "
"int16_t\n#define U16 uint16_t\n",
out);
- fputs("#define I32 int32_t\n#define U32 uint32_t\n#define I64 int64_t\n#define U64 "
+ fputs("#define I32 int32_t\n#define U32 uint32_t\n#define I64 "
+ "int64_t\n#define U64 "
"uint64_t\n",
out);
fputs("#define F32 float\n#define F64 double\n", out);
@@ -69,25 +74,32 @@ void emit_preamble(FILE *out)
out);
// Memory Mapping.
- fputs("#define z_malloc malloc\n#define z_realloc realloc\n#define z_free free\n#define "
+ fputs("#define z_malloc malloc\n#define z_realloc realloc\n#define z_free "
+ "free\n#define "
"z_print printf\n",
out);
- fputs(
- "void z_panic(const char* msg) { fprintf(stderr, \"Panic: %s\\n\", msg); exit(1); }\n",
- out);
+ fputs("void z_panic(const char* msg) { fprintf(stderr, \"Panic: %s\\n\", "
+ "msg); exit(1); }\n",
+ out);
- fputs("void _z_autofree_impl(void *p) { void **pp = (void**)p; if(*pp) { z_free(*pp); *pp "
+ fputs("void _z_autofree_impl(void *p) { void **pp = (void**)p; if(*pp) { "
+ "z_free(*pp); *pp "
"= NULL; } }\n",
out);
- fputs("#define assert(cond, ...) if (!(cond)) { fprintf(stderr, \"Assertion failed: \" "
+ fputs("#define assert(cond, ...) if (!(cond)) { fprintf(stderr, "
+ "\"Assertion failed: \" "
"__VA_ARGS__); exit(1); }\n",
out);
- fputs("string _z_readln_raw() { char *line = NULL; size_t len = 0; if(getline(&line, &len, "
- "stdin) == -1) return NULL; if(strlen(line) > 0 && line[strlen(line)-1] == '\\n') "
+ fputs("string _z_readln_raw() { char *line = NULL; size_t len = 0; "
+ "if(getline(&line, &len, "
+ "stdin) == -1) return NULL; if(strlen(line) > 0 && "
+ "line[strlen(line)-1] == '\\n') "
"line[strlen(line)-1] = 0; return line; }\n",
out);
- fputs("int _z_scan_helper(const char *fmt, ...) { char *l = _z_readln_raw(); if(!l) return "
- "0; va_list ap; va_start(ap, fmt); int r = vsscanf(l, fmt, ap); va_end(ap); "
+ fputs("int _z_scan_helper(const char *fmt, ...) { char *l = "
+ "_z_readln_raw(); if(!l) return "
+ "0; va_list ap; va_start(ap, fmt); int r = vsscanf(l, fmt, ap); "
+ "va_end(ap); "
"z_free(l); return r; }\n",
out);
@@ -235,6 +247,13 @@ void emit_struct_defs(ParserContext *ctx, ASTNode *node, FILE *out)
}
if (node->type == NODE_STRUCT)
{
+ if (node->strct.is_incomplete)
+ {
+ // Forward declaration - no body needed (typedef handles it)
+ node = node->next;
+ continue;
+ }
+
if (node->strct.is_union)
{
fprintf(out, "union %s {", node->strct.name);
@@ -763,35 +782,40 @@ void print_type_defs(ParserContext *ctx, FILE *out, ASTNode *nodes)
fprintf(out, "typedef struct { void **data; int len; int cap; } Vec;\n");
fprintf(out, "#define Vec_new() (Vec){.data=0, .len=0, .cap=0}\n");
- fprintf(
- out,
- "void _z_vec_push(Vec *v, void *item) { if(v->len >= v->cap) { v->cap = v->cap?v->cap*2:8; "
- "v->data = z_realloc(v->data, v->cap * sizeof(void*)); } v->data[v->len++] = item; }\n");
+ fprintf(out, "void _z_vec_push(Vec *v, void *item) { if(v->len >= v->cap) { "
+ "v->cap = v->cap?v->cap*2:8; "
+ "v->data = z_realloc(v->data, v->cap * sizeof(void*)); } "
+ "v->data[v->len++] = item; }\n");
fprintf(out, "#define Vec_push(v, i) _z_vec_push(&(v), (void*)(long)(i))\n");
- fprintf(out, "static inline Vec _z_make_vec(int count, ...) { Vec v = {0}; v.cap = count > 8 ? "
- "count : 8; v.data = z_malloc(v.cap * sizeof(void*)); v.len = 0; va_list args; "
+ fprintf(out, "static inline Vec _z_make_vec(int count, ...) { Vec v = {0}; v.cap = "
+ "count > 8 ? "
+ "count : 8; v.data = z_malloc(v.cap * sizeof(void*)); v.len = 0; va_list "
+ "args; "
"va_start(args, count); for(int i=0; i<count; i++) { v.data[v.len++] = "
"va_arg(args, void*); } va_end(args); return v; }\n");
if (g_config.is_freestanding)
{
- fprintf(out, "#define _z_check_bounds(index, limit) ({ __auto_type _i = (index); if(_i < 0 "
+ fprintf(out, "#define _z_check_bounds(index, limit) ({ __auto_type _i = "
+ "(index); if(_i < 0 "
"|| _i >= (limit)) { z_panic(\"index out of bounds\"); } _i; })\n");
}
else
{
- fprintf(out, "#define _z_check_bounds(index, limit) ({ __auto_type _i = (index); if(_i < 0 "
- "|| _i >= (limit)) { fprintf(stderr, \"Index out of bounds: %%ld (limit "
+ fprintf(out, "#define _z_check_bounds(index, limit) ({ __auto_type _i = "
+ "(index); if(_i < 0 "
+ "|| _i >= (limit)) { fprintf(stderr, \"Index out of bounds: "
+ "%%ld (limit "
"%%d)\\n\", (long)_i, (int)(limit)); exit(1); } _i; })\n");
}
SliceType *c = ctx->used_slices;
while (c)
{
- fprintf(
- out,
- "typedef struct Slice_%s Slice_%s;\nstruct Slice_%s { %s *data; int len; int cap; };\n",
- c->name, c->name, c->name, c->name);
+ fprintf(out,
+ "typedef struct Slice_%s Slice_%s;\nstruct Slice_%s { %s *data; "
+ "int len; int cap; };\n",
+ c->name, c->name, c->name, c->name);
c = c->next;
}
@@ -814,8 +838,8 @@ void print_type_defs(ParserContext *ctx, FILE *out, ASTNode *nodes)
}
fprintf(out, "\n");
- // FIRST: Emit typedefs for ALL structs and enums in the current compilation unit (local
- // definitions)
+ // FIRST: Emit typedefs for ALL structs and enums in the current compilation
+ // unit (local definitions)
ASTNode *local = nodes;
while (local)
{
diff --git a/src/codegen/codegen_main.c b/src/codegen/codegen_main.c
index 0e10869..c9c69f6 100644
--- a/src/codegen/codegen_main.c
+++ b/src/codegen/codegen_main.c
@@ -1,10 +1,10 @@
+#include "../ast/ast.h"
+#include "../zprep.h"
+#include "codegen.h"
#include <stdio.h>
-#include <string.h>
#include <stdlib.h>
-#include "codegen.h"
-#include "../zprep.h"
-#include "../ast/ast.h"
+#include <string.h>
// Helper: Check if a struct depends on another struct/enum by-value.
static int struct_depends_on(ASTNode *s1, const char *target_name)
@@ -191,7 +191,8 @@ void codegen_node(ParserContext *ctx, ASTNode *node, FILE *out)
if (node->type == NODE_ROOT)
{
ASTNode *kids = node->root.children;
- // Recursive Unwrap of Nested Roots (if accidentally wrapped multiple times).
+ // Recursive Unwrap of Nested Roots (if accidentally wrapped multiple
+ // times).
while (kids && kids->type == NODE_ROOT)
{
kids = kids->root.children;
diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c
index fac6c6d..5dcbf19 100644
--- a/src/codegen/codegen_utils.c
+++ b/src/codegen/codegen_utils.c
@@ -1,12 +1,12 @@
-#include <stdio.h>
-#include <string.h>
-#include <stdlib.h>
-#include <ctype.h>
-#include "codegen.h"
-#include "../zprep.h"
#include "../ast/ast.h"
#include "../parser/parser.h"
+#include "../zprep.h"
+#include "codegen.h"
+#include <ctype.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
// Global state
ASTNode *global_user_structs = NULL;
@@ -44,7 +44,7 @@ ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name)
ASTNode *s = global_user_structs;
while (s)
{
- if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0)
+ if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0 && !s->strct.is_incomplete)
{
return s;
}
@@ -55,7 +55,8 @@ ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name)
StructRef *sr = ctx->parsed_structs_list;
while (sr)
{
- if (sr->node && sr->node->type == NODE_STRUCT && strcmp(sr->node->strct.name, name) == 0)
+ if (sr->node && sr->node->type == NODE_STRUCT && strcmp(sr->node->strct.name, name) == 0 &&
+ !sr->node->strct.is_incomplete)
{
return sr->node;
}
@@ -64,7 +65,7 @@ ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name)
s = ctx->instantiated_structs;
while (s)
{
- if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0)
+ if (s->type == NODE_STRUCT && strcmp(s->strct.name, name) == 0 && !s->strct.is_incomplete)
{
return s;
}
diff --git a/src/lsp/json_rpc.c b/src/lsp/json_rpc.c
index 008a147..903da71 100644
--- a/src/lsp/json_rpc.c
+++ b/src/lsp/json_rpc.c
@@ -1,8 +1,8 @@
+#include "json_rpc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "json_rpc.h"
// Basic JSON parsing helpers
char *get_json_string(const char *json, const char *key)
@@ -27,8 +27,9 @@ char *get_json_string(const char *json, const char *key)
return res;
}
-// Extract nested "text" from params/contentChanges/0/text or params/textDocument/text
-// This is very hacky for MVP. proper JSON library needed.
+// Extract nested "text" from params/contentChanges/0/text or
+// params/textDocument/text This is very hacky for MVP. proper JSON library
+// needed.
char *get_text_content(const char *json)
{
@@ -116,10 +117,11 @@ void handle_request(const char *json_str)
{
if (strstr(json_str, "\"method\":\"initialize\""))
{
- const char *response =
- "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"capabilities\":{\"textDocumentSync\":1,"
- "\"definitionProvider\":true,\"hoverProvider\":true,\"completionProvider\":{"
- "\"triggerCharacters\":[\".\"]}}}}";
+ const char *response = "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{"
+ "\"capabilities\":{\"textDocumentSync\":1,"
+ "\"definitionProvider\":true,\"hoverProvider\":true,"
+ "\"completionProvider\":{"
+ "\"triggerCharacters\":[\".\"]}}}}";
fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", strlen(response), response);
fflush(stdout);
return;
diff --git a/src/lsp/lsp_analysis.c b/src/lsp/lsp_analysis.c
index 7a22906..d455894 100644
--- a/src/lsp/lsp_analysis.c
+++ b/src/lsp/lsp_analysis.c
@@ -1,12 +1,11 @@
+#include "json_rpc.h"
+#include "lsp_index.h"
+#include "parser.h"
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include "parser.h"
-#include "parser.h"
-#include "json_rpc.h"
-#include "lsp_index.h"
static LSPIndex *g_index = NULL;
@@ -101,7 +100,8 @@ void lsp_check_file(const char *uri, const char *json_src)
{
p += sprintf(p,
- "{\"range\":{\"start\":{\"line\":%d,\"character\":%d},\"end\":{\"line\":%d,"
+ "{\"range\":{\"start\":{\"line\":%d,\"character\":%d},\"end\":"
+ "{\"line\":%d,"
"\"character\":%d}},\"severity\":1,\"message\":\"%s\"}",
d->line, d->col, d->line, d->col + 1, d->message);
@@ -146,8 +146,10 @@ void lsp_goto_definition(const char *uri, int line, int col)
// Found reference, return definition
char resp[1024];
sprintf(resp,
- "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"uri\":\"%s\",\"range\":{\"start\":{"
- "\"line\":%d,\"character\":%d},\"end\":{\"line\":%d,\"character\":%d}}}}",
+ "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"uri\":\"%s\","
+ "\"range\":{\"start\":{"
+ "\"line\":%d,\"character\":%d},\"end\":{\"line\":%d,\"character\":%"
+ "d}}}}",
uri, r->def_line, r->def_col, r->def_line, r->def_col);
fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", strlen(resp), resp);
@@ -158,8 +160,10 @@ void lsp_goto_definition(const char *uri, int line, int col)
// Already at definition? Return itself.
char resp[1024];
sprintf(resp,
- "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"uri\":\"%s\",\"range\":{\"start\":{"
- "\"line\":%d,\"character\":%d},\"end\":{\"line\":%d,\"character\":%d}}}}",
+ "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"uri\":\"%s\","
+ "\"range\":{\"start\":{"
+ "\"line\":%d,\"character\":%d},\"end\":{\"line\":%d,\"character\":%"
+ "d}}}}",
uri, r->start_line, r->start_col, r->end_line, r->end_col);
fprintf(stdout, "Content-Length: %ld\r\n\r\n%s", strlen(resp), resp);
@@ -206,7 +210,8 @@ void lsp_hover(const char *uri, int line, int col)
char *json = malloc(16384);
// content: { kind: markdown, value: text }
sprintf(json,
- "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"contents\":{\"kind\":\"markdown\","
+ "{\"jsonrpc\":\"2.0\",\"id\":1,\"result\":{\"contents\":{\"kind\":"
+ "\"markdown\","
"\"value\":\"```c\\n%s\\n```\"}}}",
text);
diff --git a/src/lsp/lsp_index.c b/src/lsp/lsp_index.c
index 23d81ac..d952b77 100644
--- a/src/lsp/lsp_index.c
+++ b/src/lsp/lsp_index.c
@@ -1,8 +1,8 @@
+#include "lsp_index.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "lsp_index.h"
LSPIndex *lsp_index_new()
{
diff --git a/src/lsp/lsp_main.c b/src/lsp/lsp_main.c
index 9a3489b..fbe5312 100644
--- a/src/lsp/lsp_main.c
+++ b/src/lsp/lsp_main.c
@@ -1,9 +1,9 @@
+#include "json_rpc.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include "json_rpc.h"
// Simple Main Loop for LSP.
int lsp_main(int argc, char **argv)
diff --git a/src/main.c b/src/main.c
index a455943..33333be 100644
--- a/src/main.c
+++ b/src/main.c
@@ -1,12 +1,12 @@
+#include "codegen/codegen.h"
+#include "parser/parser.h"
+#include "plugins/plugin_manager.h"
+#include "repl/repl.h"
+#include "zprep.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
-#include "zprep.h"
-#include "parser/parser.h"
-#include "codegen/codegen.h"
-#include "repl/repl.h"
-#include "plugins/plugin_manager.h"
// Forward decl for LSP
int lsp_main(int argc, char **argv);
@@ -79,8 +79,8 @@ int main(int argc, char **argv)
}
else if (command[0] == '-')
{
- // implicit build or run? assume build if starts with flag, but usually command first
- // If file provided directly: "zc file.zc" -> build
+ // implicit build or run? assume build if starts with flag, but usually
+ // command first If file provided directly: "zc file.zc" -> build
if (strchr(command, '.'))
{
// treat as filename
@@ -234,7 +234,8 @@ int main(int argc, char **argv)
}
// Checking mode?
- // analyze(root); // Implicit in parsing or separate step? Assuming separate if check_mode
+ // analyze(root); // Implicit in parsing or separate step? Assuming separate
+ // if check_mode
if (g_config.mode_check)
{
diff --git a/src/parser/parser.h b/src/parser/parser.h
index b3213c9..4aeb2c8 100644
--- a/src/parser/parser.h
+++ b/src/parser/parser.h
@@ -114,6 +114,8 @@ typedef struct VarMutability
typedef struct Instantiation
{
char *name;
+ char *template_name;
+ char *concrete_arg;
ASTNode *struct_node;
struct Instantiation *next;
} Instantiation;
@@ -286,7 +288,8 @@ void add_symbol_with_token(ParserContext *ctx, const char *n, const char *t, Typ
Type *find_symbol_type_info(ParserContext *ctx, const char *n);
char *find_symbol_type(ParserContext *ctx, const char *n);
Symbol *find_symbol_entry(ParserContext *ctx, const char *n);
-Symbol *find_symbol_in_all(ParserContext *ctx, const char *n); // LSP flat lookup
+Symbol *find_symbol_in_all(ParserContext *ctx,
+ const char *n); // LSP flat lookup
char *find_similar_symbol(ParserContext *ctx, const char *name);
// Function registry
diff --git a/src/parser/parser_core.c b/src/parser/parser_core.c
index 1b40cf4..1a47275 100644
--- a/src/parser/parser_core.c
+++ b/src/parser/parser_core.c
@@ -1,9 +1,9 @@
+#include "parser.h"
+#include "zprep.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include "parser.h"
-#include "zprep.h"
static ASTNode *generate_derive_impls(ParserContext *ctx, ASTNode *strct, char **traits, int count);
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index e12c837..469d623 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -1,10 +1,10 @@
+#include "../zen/zen_facts.h"
+#include "parser.h"
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include "parser.h"
-#include "../zen/zen_facts.h"
Type *get_field_type(ParserContext *ctx, Type *struct_type, const char *field_name);
@@ -1411,7 +1411,8 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
Type *st = type_new(TYPE_STRUCT);
st->name = xstrdup(struct_name);
node->type_info = st;
- return node; // Struct init cannot be called/indexed usually, return early
+ return node; // Struct init cannot be called/indexed usually, return
+ // early
}
}
@@ -1456,7 +1457,6 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
else
{
// readln(vars...) -> _z_scan_helper("fmt", &vars...)
- // 1. Build Format String
char fmt[256];
fmt[0] = 0;
for (int i = 0; i < ac; i++)
@@ -1505,14 +1505,12 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
}
}
- // 2. Build Call Node
node = ast_create(NODE_EXPR_CALL);
ASTNode *callee = ast_create(NODE_EXPR_VAR);
callee->var_ref.name = xstrdup("_z_scan_helper");
node->call.callee = callee;
node->type_info = type_new(TYPE_INT); // Returns count
- // 3. Build Args List: "fmt" then &arg1, &arg2...
ASTNode *fmt_node = ast_create(NODE_EXPR_LITERAL);
fmt_node->literal.type_kind = 2; // string
fmt_node->literal.string_val = xstrdup(fmt);
@@ -1532,218 +1530,216 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
node->call.args = head;
}
free(acc);
-
}
- else
- if (sig && lexer_peek(l).type == TOK_LPAREN)
- {
- lexer_next(l);
- ASTNode *head = NULL, *tail = NULL;
- int args_provided = 0;
- char **arg_names = NULL;
- int has_named = 0;
+ else if (sig && lexer_peek(l).type == TOK_LPAREN)
+ {
+ lexer_next(l);
+ ASTNode *head = NULL, *tail = NULL;
+ int args_provided = 0;
+ char **arg_names = NULL;
+ int has_named = 0;
- if (lexer_peek(l).type != TOK_RPAREN)
+ if (lexer_peek(l).type != TOK_RPAREN)
+ {
+ while (1)
{
- while (1)
- {
- char *arg_name = NULL;
+ char *arg_name = NULL;
- Token t1 = lexer_peek(l);
- if (t1.type == TOK_IDENT)
+ Token t1 = lexer_peek(l);
+ if (t1.type == TOK_IDENT)
+ {
+ Token t2 = lexer_peek2(l);
+ if (t2.type == TOK_COLON)
{
- Token t2 = lexer_peek2(l);
- if (t2.type == TOK_COLON)
- {
- arg_name = token_strdup(t1);
- has_named = 1;
- lexer_next(l);
- lexer_next(l);
- }
+ arg_name = token_strdup(t1);
+ has_named = 1;
+ lexer_next(l);
+ lexer_next(l);
}
+ }
- ASTNode *arg = parse_expression(ctx, l);
- if (!head)
- {
- head = arg;
- }
- else
- {
- tail->next = arg;
- }
- tail = arg;
- args_provided++;
+ ASTNode *arg = parse_expression(ctx, l);
+ if (!head)
+ {
+ head = arg;
+ }
+ else
+ {
+ tail->next = arg;
+ }
+ tail = arg;
+ args_provided++;
- arg_names = xrealloc(arg_names, args_provided * sizeof(char *));
- arg_names[args_provided - 1] = arg_name;
+ arg_names = xrealloc(arg_names, args_provided * sizeof(char *));
+ arg_names[args_provided - 1] = arg_name;
- arg_names = xrealloc(arg_names, args_provided * sizeof(char *));
- arg_names[args_provided - 1] = arg_name;
+ arg_names = xrealloc(arg_names, args_provided * sizeof(char *));
+ arg_names[args_provided - 1] = arg_name;
- if (lexer_peek(l).type == TOK_COMMA)
- {
- lexer_next(l);
- }
- else
- {
- break;
- }
+ if (lexer_peek(l).type == TOK_COMMA)
+ {
+ lexer_next(l);
}
- }
- if (lexer_next(l).type != TOK_RPAREN)
- {
- zpanic("Expected )");
- }
- for (int i = args_provided; i < sig->total_args; i++)
- {
- if (sig->defaults[i])
+ else
{
- ASTNode *def = ast_create(NODE_RAW_STMT);
- def->raw_stmt.content = xstrdup(sig->defaults[i]);
- if (!head)
- {
- head = def;
- }
- else
- {
- tail->next = def;
- }
- tail = def;
+ break;
}
}
- node = ast_create(NODE_EXPR_CALL);
- node->token = t; // Set source token
- ASTNode *callee = ast_create(NODE_EXPR_VAR);
- callee->var_ref.name = acc;
- node->call.callee = callee;
- node->call.args = head;
- node->call.arg_names = has_named ? arg_names : NULL;
- node->call.arg_count = args_provided;
- if (sig)
- {
- node->definition_token = sig->decl_token;
- }
- if (sig->is_async)
- {
- Type *async_type = type_new(TYPE_STRUCT);
- async_type->name = xstrdup("Async");
- node->type_info = async_type;
- node->resolved_type = xstrdup("Async");
- }
- else if (sig->ret_type)
- {
- node->type_info = sig->ret_type;
- node->resolved_type = type_to_string(sig->ret_type);
- }
- else
+ }
+ if (lexer_next(l).type != TOK_RPAREN)
+ {
+ zpanic("Expected )");
+ }
+ for (int i = args_provided; i < sig->total_args; i++)
+ {
+ if (sig->defaults[i])
{
- node->resolved_type = xstrdup("void");
+ ASTNode *def = ast_create(NODE_RAW_STMT);
+ def->raw_stmt.content = xstrdup(sig->defaults[i]);
+ if (!head)
+ {
+ head = def;
+ }
+ else
+ {
+ tail->next = def;
+ }
+ tail = def;
}
}
- else if (!sig && !find_symbol_entry(ctx, acc) && lexer_peek(l).type == TOK_LPAREN)
+ node = ast_create(NODE_EXPR_CALL);
+ node->token = t; // Set source token
+ ASTNode *callee = ast_create(NODE_EXPR_VAR);
+ callee->var_ref.name = acc;
+ node->call.callee = callee;
+ node->call.args = head;
+ node->call.arg_names = has_named ? arg_names : NULL;
+ node->call.arg_count = args_provided;
+ if (sig)
{
- lexer_next(l); // eat (
- ASTNode *head = NULL, *tail = NULL;
- char **arg_names = NULL;
- int args_provided = 0;
- int has_named = 0;
+ node->definition_token = sig->decl_token;
+ }
+ if (sig->is_async)
+ {
+ Type *async_type = type_new(TYPE_STRUCT);
+ async_type->name = xstrdup("Async");
+ node->type_info = async_type;
+ node->resolved_type = xstrdup("Async");
+ }
+ else if (sig->ret_type)
+ {
+ node->type_info = sig->ret_type;
+ node->resolved_type = type_to_string(sig->ret_type);
+ }
+ else
+ {
+ node->resolved_type = xstrdup("void");
+ }
+ }
+ else if (!sig && !find_symbol_entry(ctx, acc) && lexer_peek(l).type == TOK_LPAREN)
+ {
+ lexer_next(l); // eat (
+ ASTNode *head = NULL, *tail = NULL;
+ char **arg_names = NULL;
+ int args_provided = 0;
+ int has_named = 0;
- if (lexer_peek(l).type != TOK_RPAREN)
+ if (lexer_peek(l).type != TOK_RPAREN)
+ {
+ while (1)
{
- while (1)
- {
- char *arg_name = NULL;
+ char *arg_name = NULL;
- // Check for named argument: name: value
- Token t1 = lexer_peek(l);
- if (t1.type == TOK_IDENT)
+ // Check for named argument: name: value
+ Token t1 = lexer_peek(l);
+ if (t1.type == TOK_IDENT)
+ {
+ Token t2 = lexer_peek2(l);
+ if (t2.type == TOK_COLON)
{
- Token t2 = lexer_peek2(l);
- if (t2.type == TOK_COLON)
- {
- arg_name = token_strdup(t1);
- has_named = 1;
- lexer_next(l);
- lexer_next(l);
- }
+ arg_name = token_strdup(t1);
+ has_named = 1;
+ lexer_next(l);
+ lexer_next(l);
}
+ }
- ASTNode *arg = parse_expression(ctx, l);
- if (!head)
- {
- head = arg;
- }
- else
- {
- tail->next = arg;
- }
- tail = arg;
- args_provided++;
+ ASTNode *arg = parse_expression(ctx, l);
+ if (!head)
+ {
+ head = arg;
+ }
+ else
+ {
+ tail->next = arg;
+ }
+ tail = arg;
+ args_provided++;
- arg_names = xrealloc(arg_names, args_provided * sizeof(char *));
- arg_names[args_provided - 1] = arg_name;
+ arg_names = xrealloc(arg_names, args_provided * sizeof(char *));
+ arg_names[args_provided - 1] = arg_name;
- if (lexer_peek(l).type == TOK_COMMA)
- {
- lexer_next(l);
- }
- else
- {
- break;
- }
+ if (lexer_peek(l).type == TOK_COMMA)
+ {
+ lexer_next(l);
+ }
+ else
+ {
+ break;
}
}
- if (lexer_next(l).type != TOK_RPAREN)
- {
- zpanic("Expected )");
- }
-
- node = ast_create(NODE_EXPR_CALL);
- node->token = t;
- ASTNode *callee = ast_create(NODE_EXPR_VAR);
- callee->var_ref.name = acc;
- node->call.callee = callee;
- node->call.args = head;
- node->call.arg_names = has_named ? arg_names : NULL;
- node->call.arg_count = args_provided;
- // Unknown return type - let codegen infer it
- node->resolved_type = xstrdup("unknown");
- // Fall through to Postfix
}
- else
+ if (lexer_next(l).type != TOK_RPAREN)
{
- node = ast_create(NODE_EXPR_VAR);
- node->token = t; // Set source token
- node->var_ref.name = acc;
- node->type_info = find_symbol_type_info(ctx, acc);
+ zpanic("Expected )");
+ }
- Symbol *sym = find_symbol_entry(ctx, acc);
- if (sym)
- {
- sym->is_used = 1;
- node->definition_token = sym->decl_token;
- }
+ node = ast_create(NODE_EXPR_CALL);
+ node->token = t;
+ ASTNode *callee = ast_create(NODE_EXPR_VAR);
+ callee->var_ref.name = acc;
+ node->call.callee = callee;
+ node->call.args = head;
+ node->call.arg_names = has_named ? arg_names : NULL;
+ node->call.arg_count = args_provided;
+ // Unknown return type - let codegen infer it
+ node->resolved_type = xstrdup("unknown");
+ // Fall through to Postfix
+ }
+ else
+ {
+ node = ast_create(NODE_EXPR_VAR);
+ node->token = t; // Set source token
+ node->var_ref.name = acc;
+ node->type_info = find_symbol_type_info(ctx, acc);
- char *type_str = find_symbol_type(ctx, acc);
+ Symbol *sym = find_symbol_entry(ctx, acc);
+ if (sym)
+ {
+ sym->is_used = 1;
+ node->definition_token = sym->decl_token;
+ }
+
+ char *type_str = find_symbol_type(ctx, acc);
- if (type_str)
+ if (type_str)
+ {
+ node->resolved_type = type_str;
+ node->var_ref.suggestion = NULL;
+ }
+ else
+ {
+ node->resolved_type = xstrdup("unknown");
+ if (should_suppress_undef_warning(ctx, acc))
{
- node->resolved_type = type_str;
node->var_ref.suggestion = NULL;
}
else
{
- node->resolved_type = xstrdup("unknown");
- if (should_suppress_undef_warning(ctx, acc))
- {
- node->var_ref.suggestion = NULL;
- }
- else
- {
- node->var_ref.suggestion = find_similar_symbol(ctx, acc);
- }
+ node->var_ref.suggestion = find_similar_symbol(ctx, acc);
}
}
+ }
}
else if (t.type == TOK_LPAREN)
@@ -2421,7 +2417,8 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
lhs = ast_create(NODE_AWAIT);
lhs->unary.operand = operand;
// Type inference: await Async<T> yields T
- // If operand is a call to an async function, look up its ret_type (not Async)
+ // If operand is a call to an async function, look up its ret_type (not
+ // Async)
if (operand->type == NODE_EXPR_CALL && operand->call.callee->type == NODE_EXPR_VAR)
{
FuncSig *sig = find_func(ctx, operand->call.callee->var_ref.name);
@@ -2924,8 +2921,9 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
// Clean up string for registration (e.g. "int" from "int*")
char *inner_str = type_to_string(inner);
- // Strip * if it somehow managed to keep one, though parse_type_formal
- // should handle it For now assume type_to_string gives base type
+ // Strip * if it somehow managed to keep one, though
+ // parse_type_formal should handle it For now assume type_to_string
+ // gives base type
register_slice(ctx, inner_str);
}
}
@@ -3050,7 +3048,8 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
FuncSig *sig = find_func(ctx, mangled);
if (sig)
{
- // It is a method! Create a Function Type Info to carry the return type
+ // It is a method! Create a Function Type Info to carry the return
+ // type
Type *ft = type_new(TYPE_FUNCTION);
ft->name = xstrdup(mangled);
ft->inner = sig->ret_type; // Return type
@@ -3164,7 +3163,7 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
}
}
}
-
+
if (strcmp(bin->binary.op, "=") == 0 || strcmp(bin->binary.op, "+=") == 0 ||
strcmp(bin->binary.op, "-=") == 0 || strcmp(bin->binary.op, "*=") == 0 ||
strcmp(bin->binary.op, "/=") == 0)
@@ -3183,13 +3182,14 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
if (!is_var_mutable(ctx, lhs->var_ref.name))
{
zpanic_at(op,
- "Cannot assign to immutable variable '%s' (use 'var mut' to make it "
+ "Cannot assign to immutable variable '%s' (use 'var mut' "
+ "to make it "
"mutable)",
lhs->var_ref.name);
}
}
}
-
+
int is_compound = 0;
size_t op_len = strlen(bin->binary.op);
@@ -3318,7 +3318,8 @@ ASTNode *parse_expr_prec(ParserContext *ctx, Lexer *l, Precedence min_prec)
set_callee->var_ref.name = set_name;
set_call->call.callee = set_callee;
- // Clone argument list (Shallow copy of arg nodes to preserve chain for get)
+ // Clone argument list (Shallow copy of arg nodes to preserve chain
+ // for get)
ASTNode *lhs_args = lhs->call.args;
ASTNode *new_head = NULL;
ASTNode *new_tail = NULL;
diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c
index 619caaf..30c9e90 100644
--- a/src/parser/parser_stmt.c
+++ b/src/parser/parser_stmt.c
@@ -1,13 +1,13 @@
-// parser_stmt.c - Statement and Declaration parsing
+
+#include "parser.h"
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
#include <unistd.h>
-#include "parser.h"
-#include "../plugins/plugin_manager.h"
#include "../ast/ast.h"
+#include "../plugins/plugin_manager.h"
#include "../zen/zen_facts.h"
#include "zprep_plugin.h"
@@ -83,7 +83,8 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async)
curr_func_ret = ret;
// Auto-prefix function name if in module context
- // Don't prefix generic templates or functions inside impl blocks (already mangled)
+ // Don't prefix generic templates or functions inside impl blocks (already
+ // mangled)
if (ctx->current_module_prefix && !gen_param && !ctx->current_impl_struct)
{
char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name) + 2);
@@ -111,8 +112,8 @@ ASTNode *parse_function(ParserContext *ctx, Lexer *l, int is_async)
}
// Check for unused parameters
- // The current scope contains arguments (since parse_block creates a new child scope for body)
- // Only check if we parsed a body (not a prototype) function
+ // The current scope contains arguments (since parse_block creates a new child
+ // scope for body) Only check if we parsed a body (not a prototype) function
if (body && ctx->current_scope)
{
Symbol *sym = ctx->current_scope->symbols;
@@ -1168,8 +1169,9 @@ ASTNode *parse_var_decl(ParserContext *ctx, Lexer *l)
type_obj->name = xstrdup(type);
}
- // fprintf(stderr, "DEBUG PVarDecl: Var '%s' inferred type '%s' (init->type_info
- // present: %d)\n", name, type, init && init->type_info ? 1 : 0);
+ // fprintf(stderr, "DEBUG PVarDecl: Var '%s' inferred type '%s'
+ // (init->type_info present: %d)\n", name, type, init && init->type_info ?
+ // 1 : 0);
}
}
@@ -1372,7 +1374,8 @@ ASTNode *parse_return(ParserContext *ctx, Lexer *l)
int handled = 0;
// 1. Check for Tuple Literal Return: return (a, b);
- // Condition: Function returns Tuple_..., starts with '(', and contains ',' at top level
+ // Condition: Function returns Tuple_..., starts with '(', and contains ',' at
+ // top level
if (curr_func_ret && strncmp(curr_func_ret, "Tuple_", 6) == 0 &&
lexer_peek(l).type == TOK_LPAREN)
{
@@ -1409,7 +1412,8 @@ ASTNode *parse_return(ParserContext *ctx, Lexer *l)
}
}
- // If we find a comma at depth 1 (inside the first parens), it's a tuple literal!
+ // If we find a comma at depth 1 (inside the first parens), it's a tuple
+ // literal!
if (depth == 1 && t.type == TOK_COMMA)
{
is_tuple_lit = 1;
@@ -1772,7 +1776,8 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline,
clean_expr++; // Skip leading spaces
}
- // Mark the variable as used (fixes "Unused variable" warnings for f-string interpolation)
+ // Mark the variable as used (fixes "Unused variable" warnings for f-string
+ // interpolation)
Symbol *sym = find_symbol_entry(ctx, clean_expr);
if (sym)
{
@@ -1806,7 +1811,8 @@ char *process_printf_sugar(ParserContext *ctx, const char *content, int newline,
}
// ============================================================
- // Rewrite the expression to handle pointer access (header_ptr.magic -> header_ptr->magic)
+ // Rewrite the expression to handle pointer access (header_ptr.magic ->
+ // header_ptr->magic)
char *wrapped_expr = xmalloc(strlen(expr) + 5);
sprintf(wrapped_expr, "#{%s}", expr);
char *rw_expr = rewrite_expr_methods(ctx, wrapped_expr);
@@ -2672,9 +2678,9 @@ ASTNode *parse_trait(ParserContext *ctx, Lexer *l)
// Parse method signature: fn name(args...) -> ret;
// Re-use parse_function but stop at semicolon?
- // Actually trait methods might have default impls later, but for now just signatures.
- // Let's parse full function but body might be empty/null?
- // Or simpler: just parse signature manually.
+ // Actually trait methods might have default impls later, but for now just
+ // signatures. Let's parse full function but body might be empty/null? Or
+ // simpler: just parse signature manually.
Token ft = lexer_next(l);
if (ft.type != TOK_IDENT || strncmp(ft.start, "fn", 2) != 0)
@@ -2995,8 +3001,8 @@ ASTNode *parse_impl(ParserContext *ctx, Lexer *l)
free(f->func.args);
f->func.args = na;
- // FIX: Register the MANGLED name so calls like String_from(...) find the return
- // type
+ // FIX: Register the MANGLED name so calls like String_from(...) find
+ // the return type
register_func(ctx, mangled, f->func.arg_count, f->func.defaults,
f->func.arg_types, f->func.ret_type_info, f->func.is_varargs, 0,
f->token);
@@ -3077,6 +3083,25 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
register_generic(ctx, name);
}
+ // Check for prototype (forward declaration)
+ if (lexer_peek(l).type == TOK_SEMICOLON)
+ {
+ lexer_next(l);
+ ASTNode *n = ast_create(NODE_STRUCT);
+ n->strct.name = name;
+ n->strct.is_template = (gp != NULL);
+ n->strct.generic_param = gp;
+ n->strct.is_union = is_union;
+ n->strct.fields = NULL;
+ n->strct.is_incomplete = 1;
+
+ if (!gp)
+ {
+ add_to_struct_list(ctx, n);
+ }
+ return n;
+ }
+
lexer_next(l); // eat {
ASTNode *h = 0, *tl = 0;
@@ -3139,10 +3164,11 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union)
}
else
{
- // If definition not found (e.g. user struct defined later), we can't embed fields
- // yet. Compiler limitation: 'use' requires struct to be defined before. Fallback:
- // Emit a placeholder field so compilation doesn't crash, but layout will be wrong.
- // printf("Warning: Could not find struct '%s' for embedding.\n", use_name);
+ // If definition not found (e.g. user struct defined later), we can't
+ // embed fields yet. Compiler limitation: 'use' requires struct to be
+ // defined before. Fallback: Emit a placeholder field so compilation
+ // doesn't crash, but layout will be wrong. printf("Warning: Could not
+ // find struct '%s' for embedding.\n", use_name);
}
free(use_name);
continue;
@@ -3528,7 +3554,9 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
Token t = lexer_next(l);
if (t.type != TOK_STRING)
{
- zpanic("Expected string (filename) after 'from' in selective import, got type %d", t.type);
+ zpanic("Expected string (filename) after 'from' in selective import, got "
+ "type %d",
+ t.type);
}
int ln = t.len - 2; // Remove quotes
char *fn = xmalloc(ln + 1);
@@ -3648,9 +3676,10 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
// C Header: Emit include and return (don't parse)
if (strlen(fn) > 2 && strcmp(fn + strlen(fn) - 2, ".h") == 0)
{
- // We can iterate over registered modules to check if we missed setting is_c_header?
- // But we handled 'as' above. If no 'as', we need to check if we should register it?
- // Usually 'import "foo.h" as f' is required for namespacing.
+ // We can iterate over registered modules to check if we missed setting
+ // is_c_header? But we handled 'as' above. If no 'as', we need to check if
+ // we should register it? Usually 'import "foo.h" as f' is required for
+ // namespacing.
// Emit #include
// TODO: Where to emit? parser doesn't emit code usually.
@@ -3726,7 +3755,8 @@ ASTNode *parse_import(ParserContext *ctx, Lexer *l)
}
if (module_base_name)
- { // This was only used for selective import registration, not for ctx->current_module_prefix
+ { // This was only used for selective import
+ // registration, not for ctx->current_module_prefix
free(module_base_name);
}
@@ -3776,12 +3806,13 @@ ASTNode *parse_comptime(ParserContext *ctx, Lexer *l)
// Stdout capture wrapper
// We assume the user writes C code that fits in main(), or includes headers.
- // For simplicity V1: We provide standard headers and wrap content in main if it doesn't look
- // like definitions? Actually failure mode: User defines functions. Better: User provides body
- // of main() or definitions. Heuristic: If we wrap in main, we can't define functions inside
- // main (standard C). Proposal: User code runs AS IS. User must provide main(). Wait, user
- // example: printf("..."); If I just paste printf("..."), it needs a main. Let's wrap in main()
- // by default.
+ // For simplicity V1: We provide standard headers and wrap content in main if
+ // it doesn't look like definitions? Actually failure mode: User defines
+ // functions. Better: User provides body of main() or definitions. Heuristic:
+ // If we wrap in main, we can't define functions inside main (standard C).
+ // Proposal: User code runs AS IS. User must provide main(). Wait, user
+ // example: printf("..."); If I just paste printf("..."), it needs a main.
+ // Let's wrap in main() by default.
fprintf(f, "#include <stdio.h>\n#include <stdlib.h>\n#include <string.h>\n");
fprintf(f, "int main() {\n%s\nreturn 0;\n}\n", code);
fclose(f);
@@ -3832,8 +3863,8 @@ ASTNode *parse_comptime(ParserContext *ctx, Lexer *l)
// 6. Parse Output (Recursively)
Lexer new_l;
lexer_init(&new_l, output_src);
- // Note: Recursive call. We leak output_src intentionally so AST tokens remain valid.
- // In a long running process we would manage this in an Arena.
+ // Note: Recursive call. We leak output_src intentionally so AST tokens remain
+ // valid. In a long running process we would manage this in an Arena.
return parse_program_nodes(ctx, &new_l);
}
diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c
index a5f8d86..04a7de9 100644
--- a/src/parser/parser_type.c
+++ b/src/parser/parser_type.c
@@ -1,10 +1,10 @@
+#include "../ast/ast.h"
+#include "parser.h"
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include "parser.h"
-#include "../ast/ast.h"
Type *parse_type_base(ParserContext *ctx, Lexer *l)
{
@@ -252,7 +252,8 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
if (si)
{
// This is a selectively imported symbol
- // Resolve to the actual struct name which was prefixed during module parsing
+ // Resolve to the actual struct name which was prefixed during module
+ // parsing
free(name);
name = xmalloc(strlen(si->source_module) + strlen(si->symbol) + 2);
sprintf(name, "%s_%s", si->source_module, si->symbol);
@@ -262,7 +263,8 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
// If we're IN a module and no selective import matched, apply module prefix
if (ctx->current_module_prefix && !is_known_generic(ctx, name))
{
- // Auto-prefix struct name if in module context (unless it's a known primitive/generic)
+ // Auto-prefix struct name if in module context (unless it's a known
+ // primitive/generic)
char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name) + 2);
sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, name);
free(name);
@@ -278,7 +280,8 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
lexer_next(l); // eat <
Type *arg = parse_type_formal(ctx, l);
- // Handle nested generics like Vec<Vec<int>> where >> is tokenized as one op
+ // Handle nested generics like Vec<Vec<int>> where >> is tokenized as one
+ // op
Token next_tok = lexer_peek(l);
if (next_tok.type == TOK_RANGLE)
{
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index 88823de..fcaab7f 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -1,10 +1,13 @@
+#include "../codegen/codegen.h"
+#include "parser.h"
+#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include "parser.h"
-#include "../codegen/codegen.h"
+
+void instantiate_methods(ParserContext *ctx, GenericImplTemplate *it,
+ const char *mangled_struct_name, const char *arg);
Token expect(Lexer *l, TokenType type, const char *msg)
{
@@ -376,6 +379,18 @@ void register_impl_template(ParserContext *ctx, const char *sname, const char *p
t->impl_node = node;
t->next = ctx->impl_templates;
ctx->impl_templates = t;
+
+ // Late binding: Check if any existing instantiations match this new impl
+ // template
+ Instantiation *inst = ctx->instantiations;
+ while (inst)
+ {
+ if (inst->template_name && strcmp(inst->template_name, sname) == 0)
+ {
+ instantiate_methods(ctx, t, inst->name, inst->concrete_arg);
+ }
+ inst = inst->next;
+ }
}
void add_to_struct_list(ParserContext *ctx, ASTNode *node)
@@ -917,7 +932,8 @@ char *replace_type_str(const char *src, const char *param, const char *concrete,
size_t plen = strlen(suffix);
if (slen > plen && strcmp(src + slen - plen, suffix) == 0)
{
- // Ends with _T -> Replace suffix with _int (sanitize for pointers like JsonValue*)
+ // Ends with _T -> Replace suffix with _int (sanitize for pointers like
+ // JsonValue*)
char *clean_concrete = sanitize_mangled_name(concrete);
char *ret = xmalloc(slen - plen + strlen(clean_concrete) + 2);
strncpy(ret, src, slen - plen);
@@ -1145,7 +1161,8 @@ Type *replace_type_formal(Type *t, const char *p, const char *c, const char *os,
return n;
}
-// Helper to replace generic params in mangled names (e.g. Option_V_None -> Option_int_None)
+// Helper to replace generic params in mangled names (e.g. Option_V_None ->
+// Option_int_None)
char *replace_mangled_part(const char *src, const char *param, const char *concrete)
{
if (!src || !param || !concrete)
@@ -1165,8 +1182,8 @@ char *replace_mangled_part(const char *src, const char *param, const char *concr
// Check if param matches here
if (strncmp(curr, param, plen) == 0)
{
- // Check boundaries: Must be delimited by quoted boundaries, OR underscores, OR string
- // ends
+ // Check boundaries: Must be delimited by quoted boundaries, OR
+ // underscores, OR string ends
int valid = 1;
// Check Prev: Start of string OR Underscore
@@ -1631,7 +1648,8 @@ ASTNode *copy_fields_replacing(ParserContext *ctx, ASTNode *fields, const char *
if (n->field.type && strchr(n->field.type, '_'))
{
- // Parse potential generic: e.g. "MapEntry_int" -> instantiate("MapEntry", "int")
+ // Parse potential generic: e.g. "MapEntry_int" -> instantiate("MapEntry",
+ // "int")
char *underscore = strrchr(n->field.type, '_');
if (underscore && underscore > n->field.type)
{
@@ -1676,6 +1694,67 @@ ASTNode *copy_fields_replacing(ParserContext *ctx, ASTNode *fields, const char *
return n;
}
+void instantiate_methods(ParserContext *ctx, GenericImplTemplate *it,
+ const char *mangled_struct_name, const char *arg)
+{
+ if (check_impl(ctx, "Methods", mangled_struct_name))
+ {
+ return; // Simple dedupe check
+ }
+
+ ASTNode *backup_next = it->impl_node->next;
+ it->impl_node->next = NULL; // Break link to isolate node
+ ASTNode *new_impl = copy_ast_replacing(it->impl_node, it->generic_param, arg, it->struct_name,
+ mangled_struct_name);
+ it->impl_node->next = backup_next; // Restore
+
+ new_impl->impl.struct_name = xstrdup(mangled_struct_name);
+ ASTNode *meth = new_impl->impl.methods;
+ while (meth)
+ {
+ char *suffix = strchr(meth->func.name, '_');
+ if (suffix)
+ {
+ char *new_name = xmalloc(strlen(mangled_struct_name) + strlen(suffix) + 1);
+ sprintf(new_name, "%s%s", mangled_struct_name, suffix);
+ free(meth->func.name);
+ meth->func.name = new_name;
+ register_func(ctx, new_name, meth->func.arg_count, meth->func.defaults,
+ meth->func.arg_types, meth->func.ret_type_info, meth->func.is_varargs, 0,
+ meth->token);
+ }
+
+ // Handle generic return types in methods (e.g., Option<T> -> Option_int)
+ if (meth->func.ret_type && strchr(meth->func.ret_type, '_'))
+ {
+ char *ret_copy = xstrdup(meth->func.ret_type);
+ char *underscore = strrchr(ret_copy, '_');
+ if (underscore && underscore > ret_copy)
+ {
+ *underscore = '\0';
+ char *template_name = ret_copy;
+
+ // Check if this looks like a generic (e.g., "Option_V" or "Result_V")
+ GenericTemplate *gt = ctx->templates;
+ while (gt)
+ {
+ if (strcmp(gt->name, template_name) == 0)
+ {
+ // Found matching template, instantiate it
+ instantiate_generic(ctx, template_name, arg);
+ break;
+ }
+ gt = gt->next;
+ }
+ }
+ free(ret_copy);
+ }
+
+ meth = meth->next;
+ }
+ add_instantiated_func(ctx, new_impl);
+}
+
void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg)
{
// Ignore generic placeholders
@@ -1719,6 +1798,8 @@ void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg)
Instantiation *ni = xmalloc(sizeof(Instantiation));
ni->name = xstrdup(m);
+ ni->template_name = xstrdup(tpl);
+ ni->concrete_arg = xstrdup(arg);
ni->struct_node = NULL; // Placeholder to break cycles
ni->next = ctx->instantiations;
ctx->instantiations = ni;
@@ -1780,55 +1861,7 @@ void instantiate_generic(ParserContext *ctx, const char *tpl, const char *arg)
{
if (strcmp(it->struct_name, tpl) == 0)
{
- ASTNode *backup_next = it->impl_node->next;
- it->impl_node->next = NULL; // Break link to isolate node
- ASTNode *new_impl = copy_ast_replacing(it->impl_node, it->generic_param, arg, tpl, m);
- it->impl_node->next = backup_next; // Restore
-
- new_impl->impl.struct_name = xstrdup(m);
- ASTNode *meth = new_impl->impl.methods;
- while (meth)
- {
- char *suffix = strchr(meth->func.name, '_');
- if (suffix)
- {
- char *new_name = xmalloc(strlen(m) + strlen(suffix) + 1);
- sprintf(new_name, "%s%s", m, suffix);
- free(meth->func.name);
- meth->func.name = new_name;
- register_func(ctx, new_name, meth->func.arg_count, meth->func.defaults,
- meth->func.arg_types, meth->func.ret_type_info,
- meth->func.is_varargs, 0, meth->token);
- }
-
- if (meth->func.ret_type && strchr(meth->func.ret_type, '_'))
- {
- char *ret_copy = xstrdup(meth->func.ret_type);
- char *underscore = strrchr(ret_copy, '_');
- if (underscore && underscore > ret_copy)
- {
- *underscore = '\0';
- char *template_name = ret_copy;
-
- // Check if this looks like a generic (e.g., "Option_V" or "Result_V")
- GenericTemplate *gt = ctx->templates;
- while (gt)
- {
- if (strcmp(gt->name, template_name) == 0)
- {
- // Found matching template, instantiate it
- instantiate_generic(ctx, template_name, arg);
- break;
- }
- gt = gt->next;
- }
- }
- free(ret_copy);
- }
-
- meth = meth->next;
- }
- add_instantiated_func(ctx, new_impl);
+ instantiate_methods(ctx, it, m, arg);
}
it = it->next;
}
diff --git a/src/plugins/plugin_manager.c b/src/plugins/plugin_manager.c
index a135e06..12c85cd 100644
--- a/src/plugins/plugin_manager.c
+++ b/src/plugins/plugin_manager.c
@@ -1,9 +1,9 @@
#include "plugin_manager.h"
+#include <dlfcn.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <dlfcn.h>
// Linked list node for plugins.
typedef struct PluginNode
diff --git a/src/repl/repl.c b/src/repl/repl.c
index e57c5b3..9027efd 100644
--- a/src/repl/repl.c
+++ b/src/repl/repl.c
@@ -1,11 +1,11 @@
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
#include "repl.h"
-#include "zprep.h"
#include "ast.h"
#include "parser/parser.h"
+#include "zprep.h"
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
ASTNode *parse_program(ParserContext *ctx, Lexer *l);
@@ -819,8 +819,10 @@ void run_repl(const char *self_path)
fclose(f);
char cmd[2048];
sprintf(cmd,
- "%s build -q --emit-c -o /tmp/zprep_repl_out %s 2>/dev/null; sed "
- "-n '/^int main() {$/,/^}$/p' /tmp/zprep_repl_out.c 2>/dev/null | "
+ "%s build -q --emit-c -o /tmp/zprep_repl_out %s "
+ "2>/dev/null; sed "
+ "-n '/^int main() {$/,/^}$/p' /tmp/zprep_repl_out.c "
+ "2>/dev/null | "
"tail -n +3 | head -n -2 | sed 's/^ //'",
self_path, tmp_path);
system(cmd);
@@ -892,13 +894,15 @@ void run_repl(const char *self_path)
const char *name;
const char *doc;
} docs[] = {
- {"Vec",
- "Vec<T> - Dynamic array (generic)\n Fields: data: T*, len: usize, cap: "
- "usize\n Methods: new, push, pop, get, set, insert, remove, contains, "
- "clear, free, clone, reverse, first, last, length, is_empty, eq"},
+ {"Vec", "Vec<T> - Dynamic array (generic)\n Fields: data: T*, "
+ "len: usize, cap: "
+ "usize\n Methods: new, push, pop, get, set, insert, "
+ "remove, contains, "
+ "clear, free, clone, reverse, first, last, length, "
+ "is_empty, eq"},
{"Vec.new", "fn Vec<T>::new() -> Vec<T>\n Creates an empty vector."},
- {"Vec.push",
- "fn push(self, item: T)\n Appends item to the end. Auto-grows capacity."},
+ {"Vec.push", "fn push(self, item: T)\n Appends item to the end. "
+ "Auto-grows capacity."},
{"Vec.pop", "fn pop(self) -> T\n Removes and returns the last element. "
"Panics if empty."},
{"Vec.get", "fn get(self, idx: usize) -> T\n Returns element at index. "
@@ -915,16 +919,17 @@ void run_repl(const char *self_path)
{"Vec.free", "fn free(self)\n Frees memory. Sets data to null."},
{"Vec.clone", "fn clone(self) -> Vec<T>\n Returns a shallow copy."},
{"Vec.reverse", "fn reverse(self)\n Reverses elements in place."},
- {"Vec.first",
- "fn first(self) -> T\n Returns first element. Panics if empty."},
+ {"Vec.first", "fn first(self) -> T\n Returns first element. "
+ "Panics if empty."},
{"Vec.last",
"fn last(self) -> T\n Returns last element. Panics if empty."},
{"Vec.length", "fn length(self) -> usize\n Returns number of elements."},
{"Vec.is_empty",
"fn is_empty(self) -> bool\n Returns true if length is 0."},
- {"String",
- "String - Mutable string (alias for char*)\n Methods: len, split, trim, "
- "contains, starts_with, ends_with, to_upper, to_lower, substring, find"},
+ {"String", "String - Mutable string (alias for char*)\n "
+ "Methods: len, split, trim, "
+ "contains, starts_with, ends_with, to_upper, "
+ "to_lower, substring, find"},
{"String.len", "fn len(self) -> usize\n Returns string length."},
{"String.contains", "fn contains(self, substr: string) -> bool\n Returns "
"true if string contains substr."},
@@ -938,19 +943,20 @@ void run_repl(const char *self_path)
"substr, or -1 if not found."},
{"println", "println \"format string {expr}\"\n Prints to stdout with "
"newline. Auto-formats {expr} values."},
- {"print",
- "print \"format string {expr}\"\n Prints to stdout without newline."},
+ {"print", "print \"format string {expr}\"\n Prints to stdout "
+ "without newline."},
{"eprintln",
"eprintln \"format string\"\n Prints to stderr with newline."},
{"eprint", "eprint \"format string\"\n Prints to stderr without newline."},
- {"guard",
- "guard condition else action\n Early exit pattern. Executes action if "
- "condition is false.\n Example: guard ptr != NULL else return;"},
+ {"guard", "guard condition else action\n Early exit pattern. "
+ "Executes action if "
+ "condition is false.\n Example: guard ptr != NULL "
+ "else return;"},
{"defer", "defer statement\n Executes statement at end of scope.\n "
"Example: defer free(ptr);"},
{"sizeof", "sizeof(type) or sizeof(expr)\n Returns size in bytes."},
- {"typeof",
- "typeof(expr)\n Returns the type of expression (compile-time)."},
+ {"typeof", "typeof(expr)\n Returns the type of expression "
+ "(compile-time)."},
{"malloc", "void *malloc(size_t size)\n Allocates size bytes. Returns "
"pointer or NULL. Free with free()."},
{"free", "void free(void *ptr)\n Frees memory allocated by "
@@ -963,16 +969,16 @@ void run_repl(const char *self_path)
"n bytes from src to dest. Returns dest. No overlap."},
{"memmove", "void *memmove(void *dest, const void *src, size_t n)\n "
"Copies n bytes, handles overlapping regions."},
- {"memset",
- "void *memset(void *s, int c, size_t n)\n Sets n bytes of s to value c."},
+ {"memset", "void *memset(void *s, int c, size_t n)\n Sets n "
+ "bytes of s to value c."},
{"strlen", "size_t strlen(const char *s)\n Returns length of string (not "
"including null terminator)."},
{"strcpy", "char *strcpy(char *dest, const char *src)\n Copies src to "
"dest including null terminator. No bounds check."},
{"strncpy", "char *strncpy(char *dest, const char *src, size_t n)\n "
"Copies up to n chars. May not null-terminate."},
- {"strcat",
- "char *strcat(char *dest, const char *src)\n Appends src to dest."},
+ {"strcat", "char *strcat(char *dest, const char *src)\n Appends "
+ "src to dest."},
{"strcmp", "int strcmp(const char *s1, const char *s2)\n Compares "
"strings. Returns 0 if equal, <0 or >0 otherwise."},
{"strncmp", "int strncmp(const char *s1, const char *s2, size_t n)\n "
@@ -991,11 +997,11 @@ void run_repl(const char *self_path)
"Safe sprintf with size limit."},
{"fprintf", "int fprintf(FILE *f, const char *fmt, ...)\n Prints "
"formatted output to file stream."},
- {"scanf",
- "int scanf(const char *fmt, ...)\n Reads formatted input from stdin."},
- {"fopen",
- "FILE *fopen(const char *path, const char *mode)\n Opens file. Modes: "
- "\"r\", \"w\", \"a\", \"rb\", \"wb\". Returns NULL on error."},
+ {"scanf", "int scanf(const char *fmt, ...)\n Reads formatted "
+ "input from stdin."},
+ {"fopen", "FILE *fopen(const char *path, const char *mode)\n Opens file. "
+ "Modes: "
+ "\"r\", \"w\", \"a\", \"rb\", \"wb\". Returns NULL on error."},
{"fclose", "int fclose(FILE *f)\n Closes file. Returns 0 on success."},
{"fread", "size_t fread(void *ptr, size_t size, size_t n, FILE *f)\n "
"Reads n items of size bytes. Returns items read."},
@@ -1005,15 +1011,16 @@ void run_repl(const char *self_path)
"chars. Includes newline. Returns s or NULL."},
{"fputs", "int fputs(const char *s, FILE *f)\n Writes string to file. "
"Returns non-negative or EOF."},
- {"exit", "void exit(int status)\n Terminates program with status code. 0 "
+ {"exit", "void exit(int status)\n Terminates program with "
+ "status code. 0 "
"= success."},
- {"atoi",
- "int atoi(const char *s)\n Converts string to int. Returns 0 on error."},
+ {"atoi", "int atoi(const char *s)\n Converts string to int. "
+ "Returns 0 on error."},
{"atof", "double atof(const char *s)\n Converts string to double."},
{"abs", "int abs(int n)\n Returns absolute value."},
{"rand", "int rand(void)\n Returns pseudo-random int in [0, RAND_MAX]."},
- {"srand",
- "void srand(unsigned seed)\n Seeds the random number generator."},
+ {"srand", "void srand(unsigned seed)\n Seeds the random number "
+ "generator."},
{"qsort", "void qsort(void *base, size_t n, size_t size, int(*cmp)(const "
"void*, const void*))\n Quicksorts array in-place."},
{NULL, NULL}};
@@ -1033,7 +1040,8 @@ void run_repl(const char *self_path)
// Fallback: try man pages, show only SYNOPSIS.
char man_cmd[256];
sprintf(man_cmd,
- "man 3 %s 2>/dev/null | sed -n '/^SYNOPSIS/,/^[A-Z]/p' | head -10",
+ "man 3 %s 2>/dev/null | sed -n '/^SYNOPSIS/,/^[A-Z]/p' | "
+ "head -10",
sym);
FILE *mp = popen(man_cmd, "r");
if (mp)
@@ -1197,10 +1205,10 @@ void run_repl(const char *self_path)
{
// Use printf for label, then print "{expr}" for value.
char wbuf[1024];
- sprintf(
- wbuf,
- "printf(\"\\033[90mwatch:%s = \\033[0m\"); print \"{%s}\"; printf(\"\\n\"); ",
- watches[i], watches[i]);
+ sprintf(wbuf,
+ "printf(\"\\033[90mwatch:%s = \\033[0m\"); print \"{%s}\"; "
+ "printf(\"\\n\"); ",
+ watches[i], watches[i]);
strcat(full_code, wbuf);
}
}
diff --git a/src/utils/utils.c b/src/utils/utils.c
index 08ae799..4af811f 100644
--- a/src/utils/utils.c
+++ b/src/utils/utils.c
@@ -1,6 +1,6 @@
-#include "zprep.h"
#include "parser.h"
+#include "zprep.h"
char *g_current_filename = "unknown";
ParserContext *g_parser_ctx = NULL;
diff --git a/src/zen/zen_facts.c b/src/zen/zen_facts.c
index 441a180..6120e71 100644
--- a/src/zen/zen_facts.c
+++ b/src/zen/zen_facts.c
@@ -1,8 +1,8 @@
+#include "zen_facts.h"
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <unistd.h>
-#include "zen_facts.h"
// We keep it low by default.
#define ZEN_PROBABILITY 10
@@ -16,257 +16,339 @@ typedef struct
static const ZenFact facts[] = {
{TRIGGER_GOTO,
- "Edsger W. Dijkstra considered 'Go To Statement Harmful' in 1968, advocating for structured "
+ "Edsger W. Dijkstra considered 'Go To Statement Harmful' in 1968, "
+ "advocating for structured "
"programming.",
"https://homepages.cwi.nl/~storm/teaching/reader/Dijkstra68.pdf"},
{TRIGGER_GOTO,
- "Goto can be useful for error cleanup patterns in C (and Zen C), mimicking 'defer' or "
+ "Goto can be useful for error cleanup patterns in C (and Zen C), "
+ "mimicking 'defer' or "
"'finally' blocks.",
NULL},
{TRIGGER_POINTER_ARITH,
- "In C, `arr[i]` is just `*(arr + i)`. Fun fact: `i[arr]` is also valid syntax!",
+ "In C, `arr[i]` is just `*(arr + i)`. Fun fact: `i[arr]` is also valid "
+ "syntax!",
"https://c-faq.com/aryptr/aryptr2.html"},
{TRIGGER_POINTER_ARITH,
- "Pointer arithmetic scales by the size of the type. `ptr + 1` increases the address by "
+ "Pointer arithmetic scales by the size of the type. `ptr + 1` increases "
+ "the address by "
"`sizeof(*ptr)` bytes.",
NULL},
{TRIGGER_BITWISE, "Use `(x & (x - 1)) == 0` to check if an integer is a power of two.",
"https://graphics.stanford.edu/~seander/bithacks.html"},
{TRIGGER_BITWISE,
- "XOR swap algorithm: `x ^= y; y ^= x; x ^= y;` swaps variables without a temporary (but "
+ "XOR swap algorithm: `x ^= y; y ^= x; x ^= y;` swaps variables without a "
+ "temporary (but "
"optimized code is usually faster).",
NULL},
{TRIGGER_RECURSION, "To understand recursion, you must first understand recursion.", NULL},
{TRIGGER_RECURSION,
- "Tail Call Optimization (TCO) allows some recursive calls to consume no additional stack "
+ "Tail Call Optimization (TCO) allows some recursive calls to consume no "
+ "additional stack "
"space.",
"https://en.wikipedia.org/wiki/Tail_call"},
{TRIGGER_TERNARY,
- "The ternary operator `?:` is the only operator in C that takes three operands.", NULL},
+ "The ternary operator `?:` is the only operator in C that takes three "
+ "operands.",
+ NULL},
{TRIGGER_ASM,
- "With great power comes great responsibility. Inline assembly is compiler-specific and "
+ "With great power comes great responsibility. Inline assembly is "
+ "compiler-specific and "
"fragile.",
NULL},
{TRIGGER_WHILE_TRUE,
- "The Halting Problem proves it is impossible to determine if an arbitrary program will "
+ "The Halting Problem proves it is impossible to determine if an arbitrary "
+ "program will "
"eventually stop.",
"https://en.wikipedia.org/wiki/Halting_problem"},
{TRIGGER_MACRO,
- "Macros are handled by the preprocessor, doing simple text replacement before compilation "
+ "Macros are handled by the preprocessor, doing simple text replacement "
+ "before compilation "
"begins.",
NULL},
{TRIGGER_VOID_PTR,
- "A `void*` is a generic pointer type. You cannot dereference it directly without casting.",
+ "A `void*` is a generic pointer type. You cannot dereference it directly "
+ "without casting.",
NULL},
{TRIGGER_POINTER_ARITH,
- "Subtracting two pointers returns a `ptrdiff_t`, a signed integer type capable of holding the "
+ "Subtracting two pointers returns a `ptrdiff_t`, a signed integer type "
+ "capable of holding the "
"difference.",
NULL},
{TRIGGER_MAIN,
- "In C, `main` implicitly returns 0 if no return statement is found (C99+). Zen C follows "
+ "In C, `main` implicitly returns 0 if no return statement is found "
+ "(C99+). Zen C follows "
"suit.",
NULL},
{TRIGGER_FORMAT_STRING,
- "printf format strings are a mini-language interpreted at runtime. Be careful with user "
+ "printf format strings are a mini-language interpreted at runtime. Be "
+ "careful with user "
"input!",
NULL},
{TRIGGER_BITWISE,
- "The `!!` idiom (double negation) is a standard way to normalize any non-zero value to "
+ "The `!!` idiom (double negation) is a standard way to normalize any "
+ "non-zero value to "
"exactly 1.",
NULL},
{TRIGGER_GLOBAL,
- "Duff's Device interleaves a switch statement with a do-while loop to unroll copy loops.",
+ "Duff's Device interleaves a switch statement with a do-while loop to "
+ "unroll copy loops.",
"https://en.wikipedia.org/wiki/Duff%27s_device"},
{TRIGGER_GLOBAL,
- "In C, `sizeof` is an operator, not a function. Parentheses are only required for type names.",
+ "In C, `sizeof` is an operator, not a function. Parentheses are only "
+ "required for type names.",
NULL},
{TRIGGER_GLOBAL,
- "Digraphs and Trigraphs were added for keyboards missing symbols. `\\?\\?=` is `#`, and `<:` "
+ "Digraphs and Trigraphs were added for keyboards missing symbols. "
+ "`\\?\\?=` is `#`, and `<:` "
"is `[`.",
"https://en.wikipedia.org/wiki/Digraphs_and_trigraphs"},
{TRIGGER_GLOBAL,
- "Function designators convert to pointers automatically. `foo`, `&foo`, and `*foo` all "
+ "Function designators convert to pointers automatically. `foo`, `&foo`, "
+ "and `*foo` all "
"resolve to the same address.",
NULL},
{TRIGGER_GLOBAL,
- "The comma operator evaluates operands left-to-right and returns the last. `x = (1, 2, 3)` "
+ "The comma operator evaluates operands left-to-right and returns the "
+ "last. `x = (1, 2, 3)` "
"sets x to 3.",
NULL},
{TRIGGER_GLOBAL,
- "Multi-character constants like 'ABCD' are valid C. Their integer value is "
+ "Multi-character constants like 'ABCD' are valid C. Their integer value "
+ "is "
"implementation-defined.",
NULL},
{TRIGGER_GLOBAL,
- "Bit-fields allow packing struct members into specific bit widths. `int x : 3;` uses only 3 "
+ "Bit-fields allow packing struct members into specific bit widths. `int x "
+ ": 3;` uses only 3 "
"bits.",
NULL},
{TRIGGER_GLOBAL,
- "Array indexing is commutative: `5[arr]` is semantically identical to `arr[5]`.", NULL},
+ "Array indexing is commutative: `5[arr]` is semantically identical to "
+ "`arr[5]`.",
+ NULL},
{TRIGGER_GLOBAL,
- "The `restrict` keyword promises the compiler that a pointer is the only access to that "
+ "The `restrict` keyword promises the compiler that a pointer is the only "
+ "access to that "
"memory.",
NULL},
{TRIGGER_GLOBAL,
- "A struct's size can be larger than the sum of its members due to alignment padding.", NULL},
+ "A struct's size can be larger than the sum of its members due to "
+ "alignment padding.",
+ NULL},
{TRIGGER_GLOBAL,
- "In C, `void*` arithmetic is a GCC extension (treating size as 1). Standard C forbids it.",
+ "In C, `void*` arithmetic is a GCC extension (treating size as 1). "
+ "Standard C forbids it.",
NULL},
{TRIGGER_GLOBAL,
- "The C standard guarantees that `NULL` equals `(void*)0`, but the bit pattern may not be all "
+ "The C standard guarantees that `NULL` equals `(void*)0`, but the bit "
+ "pattern may not be all "
"zeros.",
NULL},
{TRIGGER_GLOBAL,
- "`sizeof('a')` is 4 in C (int) but 1 in C++ (char). A subtle difference between the "
+ "`sizeof('a')` is 4 in C (int) but 1 in C++ (char). A subtle difference "
+ "between the "
"languages.",
NULL},
{TRIGGER_GLOBAL,
- "Static local variables are initialized only once, even if the function is called multiple "
+ "Static local variables are initialized only once, even if the function "
+ "is called multiple "
"times.",
NULL},
{TRIGGER_GLOBAL,
- "The `volatile` keyword prevents compiler optimizations on a variable, useful for hardware "
+ "The `volatile` keyword prevents compiler optimizations on a variable, "
+ "useful for hardware "
"registers.",
NULL},
{TRIGGER_GLOBAL,
- "In C99+, Variable Length Arrays (VLAs) can have runtime-determined sizes. Use with caution!",
+ "In C99+, Variable Length Arrays (VLAs) can have runtime-determined "
+ "sizes. Use with caution!",
NULL},
- {TRIGGER_GLOBAL, "The `_Alignof` operator (C11) returns the alignment requirement of a type.",
+ {TRIGGER_GLOBAL,
+ "The `_Alignof` operator (C11) returns the alignment requirement of a "
+ "type.",
NULL},
{TRIGGER_GLOBAL,
- "Compound literals like `(int[]){1, 2, 3}` create anonymous arrays with automatic storage.",
+ "Compound literals like `(int[]){1, 2, 3}` create anonymous arrays with "
+ "automatic storage.",
NULL},
{TRIGGER_GLOBAL,
- "Designated initializers: `.field = val` lets you initialize struct fields out of order.",
+ "Designated initializers: `.field = val` lets you initialize struct "
+ "fields out of order.",
NULL},
{TRIGGER_GLOBAL,
- "The `#` stringification operator in macros turns arguments into string literals.", NULL},
+ "The `#` stringification operator in macros turns arguments into string "
+ "literals.",
+ NULL},
{TRIGGER_GLOBAL, "The `##` token-pasting operator concatenates tokens in macro expansions.",
NULL},
{TRIGGER_GLOBAL,
- "Flexible array members: `int data[];` at struct end allows variable-size structs.", NULL},
+ "Flexible array members: `int data[];` at struct end allows variable-size "
+ "structs.",
+ NULL},
{TRIGGER_GLOBAL,
- "Anonymous structs/unions (C11) allow direct member access without field names.", NULL},
+ "Anonymous structs/unions (C11) allow direct member access without field "
+ "names.",
+ NULL},
+ {TRIGGER_GLOBAL,
+ "`_Generic` (C11) provides compile-time type dispatch, like a simpler "
+ "form of overloading.",
+ NULL},
{TRIGGER_GLOBAL,
- "`_Generic` (C11) provides compile-time type dispatch, like a simpler form of overloading.",
+ "The `register` keyword is a hint to the compiler, but modern compilers "
+ "ignore it.",
NULL},
{TRIGGER_GLOBAL,
- "The `register` keyword is a hint to the compiler, but modern compilers ignore it.", NULL},
- {TRIGGER_GLOBAL, "Integer promotion: `char` and `short` are promoted to `int` in expressions.",
+ "Integer promotion: `char` and `short` are promoted to `int` in "
+ "expressions.",
NULL},
{TRIGGER_GLOBAL,
- "Signed integer overflow is undefined behavior in C. Use unsigned for wrap-around arithmetic.",
+ "Signed integer overflow is undefined behavior in C. Use unsigned for "
+ "wrap-around arithmetic.",
NULL},
{TRIGGER_GLOBAL,
- "The order of evaluation for function arguments is unspecified in C. Never rely on it!", NULL},
- {TRIGGER_GLOBAL, "In C, you can take the address of a label with `&&label` (GCC extension).",
+ "The order of evaluation for function arguments is unspecified in C. "
+ "Never rely on it!",
NULL},
{TRIGGER_GLOBAL,
- "The `inline` keyword is only a suggestion. Compilers decide whether to actually inline.",
+ "In C, you can take the address of a label with `&&label` (GCC "
+ "extension).",
NULL},
{TRIGGER_GLOBAL,
- "`setjmp`/`longjmp` provide non-local jumps, but are dangerous and rarely needed.", NULL},
+ "The `inline` keyword is only a suggestion. Compilers decide whether to "
+ "actually inline.",
+ NULL},
{TRIGGER_GLOBAL,
- "The `#pragma once` directive is non-standard but widely supported for include guards.", NULL},
+ "`setjmp`/`longjmp` provide non-local jumps, but are dangerous and rarely "
+ "needed.",
+ NULL},
+ {TRIGGER_GLOBAL,
+ "The `#pragma once` directive is non-standard but widely supported for "
+ "include guards.",
+ NULL},
{TRIGGER_GLOBAL,
- "A `char` can be signed or unsigned depending on the platform. Use `signed char` or `unsigned "
+ "A `char` can be signed or unsigned depending on the platform. Use "
+ "`signed char` or `unsigned "
"char` to be explicit.",
NULL},
{TRIGGER_GLOBAL,
- "The `const` keyword doesn't make data immutable - you can cast it away (but shouldn't).",
+ "The `const` keyword doesn't make data immutable - you can cast it away "
+ "(but shouldn't).",
NULL},
{TRIGGER_GLOBAL,
- "C has no native boolean type before C99. `_Bool` was added in C99, `bool` via stdbool.h.",
+ "C has no native boolean type before C99. `_Bool` was added in C99, "
+ "`bool` via stdbool.h.",
NULL},
{TRIGGER_GLOBAL,
- "Empty parameter lists in C mean 'unspecified arguments', not 'no arguments'. Use `(void)` "
+ "Empty parameter lists in C mean 'unspecified arguments', not 'no "
+ "arguments'. Use `(void)` "
"for none.",
NULL},
{TRIGGER_GLOBAL,
- "The `extern` keyword declares a variable without defining it, linking to another translation "
+ "The `extern` keyword declares a variable without defining it, linking to "
+ "another translation "
"unit.",
NULL},
{TRIGGER_GLOBAL,
- "K&R style function definitions predate ANSI C and put parameter types after the parentheses.",
+ "K&R style function definitions predate ANSI C and put parameter types "
+ "after the parentheses.",
NULL},
{TRIGGER_GLOBAL,
- "The IOCCC (Obfuscated C Code Contest) showcases creative abuse of C syntax since 1984.",
+ "The IOCCC (Obfuscated C Code Contest) showcases creative abuse of C "
+ "syntax since 1984.",
"https://www.ioccc.org"},
{TRIGGER_GLOBAL,
- "Dennis Ritchie developed C at Bell Labs between 1969-1973. It replaced B, which was "
+ "Dennis Ritchie developed C at Bell Labs between 1969-1973. It replaced "
+ "B, which was "
"typeless.",
NULL},
{TRIGGER_GLOBAL, "The name 'C' simply comes from being the successor to the B language.", NULL},
{TRIGGER_GLOBAL,
- "Plan 9 C allows `structure.member` notation even if `member` is inside an anonymous inner "
+ "Plan 9 C allows `structure.member` notation even if `member` is inside "
+ "an anonymous inner "
"struct. C11 finally adopted this!",
"https://9p.io/sys/doc/comp.html"},
{TRIGGER_GLOBAL,
- "In Plan 9 C, arrays of zero length `int data[0]` were valid long before C99 flexible array "
+ "In Plan 9 C, arrays of zero length `int data[0]` were valid long before "
+ "C99 flexible array "
"members.",
NULL},
{TRIGGER_GLOBAL,
- "Plan 9 C headers are 'idempotent' — they contain their own include guards, so you never see "
+ "Plan 9 C headers are 'idempotent' — they contain their own include "
+ "guards, so you never see "
"`#ifndef HEADER_H` boilerplate.",
NULL},
{TRIGGER_GLOBAL,
- "In Plan 9, the `nil` pointer is distinct from 0. Accessing `nil` causes a hardware trap, not "
+ "In Plan 9, the `nil` pointer is distinct from 0. Accessing `nil` causes "
+ "a hardware trap, not "
"just undefined behavior.",
NULL},
{TRIGGER_GLOBAL,
- "Ken Thompson, creator of B and C, also designed UTF-8 encoding on a placemat in a New Jersey "
+ "Ken Thompson, creator of B and C, also designed UTF-8 encoding on a "
+ "placemat in a New Jersey "
"diner.",
"https://www.cl.cam.ac.uk/~mgk25/ucs/utf-8-history.txt"},
{TRIGGER_GLOBAL,
- "C11 introduced `_Noreturn` to tell the compiler a function (like `exit`) will never return "
+ "C11 introduced `_Noreturn` to tell the compiler a function (like `exit`) "
+ "will never return "
"control to the caller.",
NULL},
{TRIGGER_GLOBAL,
- "A 'Sequence Point' is a juncture where all side effects of previous evaluations must be "
+ "A 'Sequence Point' is a juncture where all side effects of previous "
+ "evaluations must be "
"complete. Violation = UB.",
"https://en.wikipedia.org/wiki/Sequence_point"},
{TRIGGER_GLOBAL,
- "VLAs were mandatory in C99, but made optional in C11 because they are hard to implement "
+ "VLAs were mandatory in C99, but made optional in C11 because they are "
+ "hard to implement "
"safely.",
NULL},
{TRIGGER_GLOBAL,
- "Pre-ANSI C (K&R) didn't have `void`. Functions returning nothing actually returned an "
+ "Pre-ANSI C (K&R) didn't have `void`. Functions returning nothing "
+ "actually returned an "
"undefined `int`.",
NULL},
{TRIGGER_GLOBAL,
- "Adjacent string literals are concatenated automatically. `\"Hello \" \"World\"` becomes "
+ "Adjacent string literals are concatenated automatically. `\"Hello \" "
+ "\"World\"` becomes "
"`\"Hello World\"`.",
NULL},
{TRIGGER_GLOBAL,
- "The `auto` keyword exists in C! It declares automatic storage duration, but is almost never "
+ "The `auto` keyword exists in C! It declares automatic storage duration, "
+ "but is almost never "
"used since it's the default.",
NULL},
{TRIGGER_GLOBAL,
- "Bitwise operators have lower precedence than comparisons! `val & MASK == 0` is `val & (MASK "
+ "Bitwise operators have lower precedence than comparisons! `val & MASK == "
+ "0` is `val & (MASK "
"== 0)`. Always parenthesize!",
NULL},
{TRIGGER_GLOBAL,
- "The 'as-if' rule allows compilers to transform code however they want, as long as observable "
+ "The 'as-if' rule allows compilers to transform code however they want, "
+ "as long as observable "
"behavior remains the same.",
"https://en.cppreference.com/w/c/language/as_if"},
{TRIGGER_GLOBAL,
- "Tail Recursion Elimination (TRE) isn't guaranteed by the C standard, but most compilers do "
+ "Tail Recursion Elimination (TRE) isn't guaranteed by the C standard, but "
+ "most compilers do "
"it at -O2.",
NULL},
{TRIGGER_GLOBAL,
- "GCC's `__builtin_expect` allows you to tell the branch predictor which path is more likely "
+ "GCC's `__builtin_expect` allows you to tell the branch predictor which "
+ "path is more likely "
"(the `likely()` macro).",
NULL},
{TRIGGER_GLOBAL, "The actual inspiration for this project was this video.",
diff --git a/src/zprep.h b/src/zprep.h
index 8a85c9f..299ec13 100644
--- a/src/zprep.h
+++ b/src/zprep.h
@@ -2,11 +2,11 @@
#ifndef ZPREP_H
#define ZPREP_H
+#include <ctype.h>
+#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
-#include <ctype.h>
-#include <stdarg.h>
// ** ANSI COLORS **
#define COLOR_RESET "\033[0m"