summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-02-01 14:01:51 +0000
committerZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-02-01 14:01:51 +0000
commitfbfce63744882d48ea2fc514ab1594000254db80 (patch)
treecc7949dab2149d829d3c04e3d542553ed883593f /src
parenteafd8c67012ea253436b79f703dc0702046703f8 (diff)
Related to #138
Diffstat (limited to 'src')
-rw-r--r--src/ast/ast.c56
-rw-r--r--src/ast/ast.h58
-rw-r--r--src/codegen/codegen.c92
-rw-r--r--src/codegen/codegen_decl.c19
-rw-r--r--src/parser/parser_expr.c4
-rw-r--r--src/parser/parser_struct.c6
-rw-r--r--src/parser/parser_type.c62
-rw-r--r--src/parser/parser_utils.c22
8 files changed, 270 insertions, 49 deletions
diff --git a/src/ast/ast.c b/src/ast/ast.c
index 439a9f5..1b35500 100644
--- a/src/ast/ast.c
+++ b/src/ast/ast.c
@@ -259,6 +259,25 @@ static char *type_to_string_impl(Type *t)
return xstrdup("int32_t");
case TYPE_UINT:
return xstrdup("unsigned int");
+
+ // Portable C Types
+ case TYPE_C_INT:
+ return xstrdup("c_int");
+ case TYPE_C_UINT:
+ return xstrdup("c_uint");
+ case TYPE_C_LONG:
+ return xstrdup("c_long");
+ case TYPE_C_ULONG:
+ return xstrdup("c_ulong");
+ case TYPE_C_SHORT:
+ return xstrdup("c_short");
+ case TYPE_C_USHORT:
+ return xstrdup("c_ushort");
+ case TYPE_C_CHAR:
+ return xstrdup("c_char");
+ case TYPE_C_UCHAR:
+ return xstrdup("c_uchar");
+
case TYPE_INT:
return xstrdup("int");
case TYPE_FLOAT:
@@ -461,8 +480,29 @@ static char *type_to_c_string_impl(Type *t)
return xstrdup("int32_t");
case TYPE_UINT:
return xstrdup("unsigned int");
- case TYPE_INT:
+
+ // Portable C Types (Map directly to C types)
+ case TYPE_C_INT:
return xstrdup("int");
+ case TYPE_C_UINT:
+ return xstrdup("unsigned int");
+ case TYPE_C_LONG:
+ return xstrdup("long");
+ case TYPE_C_ULONG:
+ return xstrdup("unsigned long");
+ case TYPE_C_SHORT:
+ return xstrdup("short");
+ case TYPE_C_USHORT:
+ return xstrdup("unsigned short");
+ case TYPE_C_CHAR:
+ return xstrdup("char");
+ case TYPE_C_UCHAR:
+ return xstrdup("unsigned char");
+
+ case TYPE_INT:
+ // 'int' in Zen C maps to 'i32' now for portability.
+ // FFI should use c_int.
+ return xstrdup("int32_t");
case TYPE_FLOAT:
return xstrdup("float");
case TYPE_BITINT:
@@ -519,8 +559,11 @@ static char *type_to_c_string_impl(Type *t)
return res;
}
- char *res = xmalloc(strlen(inner) + 7);
- sprintf(res, "Slice_%s", inner);
+ char *inner_zens = type_to_string(t->inner);
+ char *res = xmalloc(strlen(inner_zens) + 7);
+ sprintf(res, "Slice_%s", inner_zens);
+ free(inner_zens);
+ free(inner);
return res;
}
@@ -561,7 +604,12 @@ static char *type_to_c_string_impl(Type *t)
return xstrdup("z_closure_T");
case TYPE_GENERIC:
- return xstrdup(t->name);
+ // Use type_to_string to get the mangled name (e.g. Option_int) instead of raw C string
+ // composition This ensures consistency with struct definitions.
+ {
+ char *s = type_to_string(t);
+ return s;
+ }
case TYPE_ALIAS:
return type_to_c_string(t->inner);
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 4498d7c..fa67043 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -28,30 +28,40 @@ typedef enum
*/
typedef enum
{
- TYPE_VOID, ///< `void` type.
- TYPE_BOOL, ///< `bool` type.
- TYPE_CHAR, ///< `char` type.
- TYPE_STRING, ///< `string` type.
- TYPE_U0, ///< `u0` type.
- TYPE_I8, ///< `i8` type.
- TYPE_U8, ///< `u8` type.
- TYPE_I16, ///< `i16` type.
- TYPE_U16, ///< `u16` type.
- TYPE_I32, ///< `i32` type.
- TYPE_U32, ///< `u32` type.
- TYPE_I64, ///< `i64` type.
- TYPE_U64, ///< `u64` type.
- TYPE_I128, ///< `i128` type.
- TYPE_U128, ///< `u128` type.
- TYPE_F32, ///< `f32` type.
- TYPE_F64, ///< `f64` type.
- TYPE_INT, ///< `int` (alias, usually i32).
- TYPE_FLOAT, ///< `float` (alias).
- TYPE_USIZE, ///< `usize` (pointer size unsigned).
- TYPE_ISIZE, ///< `isize` (pointer size signed).
- TYPE_BYTE, ///< `byte`.
- TYPE_RUNE, ///< `rune`.
- TYPE_UINT, ///< `uint` (alias).
+ TYPE_VOID, ///< `void` type.
+ TYPE_BOOL, ///< `bool` type.
+ TYPE_CHAR, ///< `char` type.
+ TYPE_STRING, ///< `string` type.
+ TYPE_U0, ///< `u0` type.
+ TYPE_I8, ///< `i8` type.
+ TYPE_U8, ///< `u8` type.
+ TYPE_I16, ///< `i16` type.
+ TYPE_U16, ///< `u16` type.
+ TYPE_I32, ///< `i32` type.
+ TYPE_U32, ///< `u32` type.
+ TYPE_I64, ///< `i64` type.
+ TYPE_U64, ///< `u64` type.
+ TYPE_I128, ///< `i128` type.
+ TYPE_U128, ///< `u128` type.
+ TYPE_F32, ///< `f32` type.
+ TYPE_F64, ///< `f64` type.
+ TYPE_INT, ///< `int` (alias, usually i32).
+ TYPE_FLOAT, ///< `float` (alias).
+ TYPE_USIZE, ///< `usize` (pointer size unsigned).
+ TYPE_ISIZE, ///< `isize` (pointer size signed).
+ TYPE_BYTE, ///< `byte`.
+ TYPE_RUNE, ///< `rune`.
+ TYPE_UINT, ///< `uint` (alias).
+ // Portable C Types (FFI)
+ TYPE_C_INT, ///< `c_int` (int).
+ TYPE_C_UINT, ///< `c_uint` (unsigned int).
+ TYPE_C_LONG, ///< `c_long` (long).
+ TYPE_C_ULONG, ///< `c_ulong` (unsigned long).
+ TYPE_C_SHORT, ///< `c_short` (short).
+ TYPE_C_USHORT, ///< `c_ushort` (unsigned short).
+ TYPE_C_CHAR, ///< `c_char` (char).
+ TYPE_C_UCHAR, ///< `c_uchar` (unsigned char).
+
TYPE_STRUCT, ///< Struct type.
TYPE_ENUM, ///< Enum type.
TYPE_POINTER, ///< Pointer type (*).
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c
index 0496a46..384820b 100644
--- a/src/codegen/codegen.c
+++ b/src/codegen/codegen.c
@@ -1150,14 +1150,102 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
break;
}
case NODE_EXPR_CAST:
- fprintf(out, "((%s)(", node->cast.target_type);
+ {
+ const char *t = node->cast.target_type;
+ const char *mapped = t;
+ if (strcmp(t, "c_int") == 0)
+ {
+ mapped = "int";
+ }
+ else if (strcmp(t, "c_uint") == 0)
+ {
+ mapped = "unsigned int";
+ }
+ else if (strcmp(t, "c_long") == 0)
+ {
+ mapped = "long";
+ }
+ else if (strcmp(t, "c_ulong") == 0)
+ {
+ mapped = "unsigned long";
+ }
+ else if (strcmp(t, "c_short") == 0)
+ {
+ mapped = "short";
+ }
+ else if (strcmp(t, "c_ushort") == 0)
+ {
+ mapped = "unsigned short";
+ }
+ else if (strcmp(t, "c_char") == 0)
+ {
+ mapped = "char";
+ }
+ else if (strcmp(t, "c_uchar") == 0)
+ {
+ mapped = "unsigned char";
+ }
+ else if (strcmp(t, "int") == 0)
+ {
+ mapped = "int32_t";
+ }
+ else if (strcmp(t, "uint") == 0)
+ {
+ mapped = "unsigned int";
+ }
+
+ fprintf(out, "((%s)(", mapped);
codegen_expression(ctx, node->cast.expr, out);
fprintf(out, "))");
break;
+ }
case NODE_EXPR_SIZEOF:
if (node->size_of.target_type)
{
- fprintf(out, "sizeof(%s)", node->size_of.target_type);
+ const char *t = node->size_of.target_type;
+ const char *mapped = t;
+ if (strcmp(t, "c_int") == 0)
+ {
+ mapped = "int";
+ }
+ else if (strcmp(t, "c_uint") == 0)
+ {
+ mapped = "unsigned int";
+ }
+ else if (strcmp(t, "c_long") == 0)
+ {
+ mapped = "long";
+ }
+ else if (strcmp(t, "c_ulong") == 0)
+ {
+ mapped = "unsigned long";
+ }
+ else if (strcmp(t, "c_short") == 0)
+ {
+ mapped = "short";
+ }
+ else if (strcmp(t, "c_ushort") == 0)
+ {
+ mapped = "unsigned short";
+ }
+ else if (strcmp(t, "c_char") == 0)
+ {
+ mapped = "char";
+ }
+ else if (strcmp(t, "c_uchar") == 0)
+ {
+ mapped = "unsigned char";
+ }
+ else if (strcmp(t, "int") == 0)
+ {
+ mapped = "int32_t"; // Strict mapping
+ }
+ else if (strcmp(t, "uint") == 0)
+ {
+ mapped = "unsigned int"; // uint alias
+ }
+
+ fprintf(out, "sizeof(%s)", mapped);
}
else
{
diff --git a/src/codegen/codegen_decl.c b/src/codegen/codegen_decl.c
index 31bd2ee..1623ffc 100644
--- a/src/codegen/codegen_decl.c
+++ b/src/codegen/codegen_decl.c
@@ -1130,12 +1130,23 @@ void print_type_defs(ParserContext *ctx, FILE *out, ASTNode *nodes)
fprintf(out, "typedef struct Tuple_%s Tuple_%s;\nstruct Tuple_%s { ", t->sig, t->sig,
t->sig);
char *s = xstrdup(t->sig);
- char *p = strtok(s, "_");
+ char *current = s;
+ char *next_sep = strstr(current, "__");
int i = 0;
- while (p)
+ while (current)
{
- fprintf(out, "%s v%d; ", p, i++);
- p = strtok(NULL, "_");
+ if (next_sep)
+ {
+ *next_sep = 0;
+ fprintf(out, "%s v%d; ", current, i++);
+ current = next_sep + 2;
+ next_sep = strstr(current, "__");
+ }
+ else
+ {
+ fprintf(out, "%s v%d; ", current, i++);
+ break;
+ }
}
free(s);
fprintf(out, "};\n");
diff --git a/src/parser/parser_expr.c b/src/parser/parser_expr.c
index 7c53d96..5bf0089 100644
--- a/src/parser/parser_expr.c
+++ b/src/parser/parser_expr.c
@@ -1908,7 +1908,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
{
Type *formal_type = parse_type_formal(ctx, l);
concrete_types[arg_count] = type_to_string(formal_type);
- unmangled_types[arg_count] = type_to_c_string(formal_type);
+ unmangled_types[arg_count] = type_to_string(formal_type);
arg_count++;
if (lexer_peek(l).type == TOK_COMMA)
@@ -2944,7 +2944,7 @@ ASTNode *parse_primary(ParserContext *ctx, Lexer *l)
{
if (i > 0)
{
- strcat(sig, "_");
+ strcat(sig, "__");
}
strcat(sig, type_strs[i]);
}
diff --git a/src/parser/parser_struct.c b/src/parser/parser_struct.c
index e53b56c..c89ad34 100644
--- a/src/parser/parser_struct.c
+++ b/src/parser/parser_struct.c
@@ -863,7 +863,7 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union, int is_opaque)
Token field_name = lexer_next(l);
lexer_next(l); // eat :
Type *ft = parse_type_formal(ctx, l);
- char *field_type_str = type_to_string(ft);
+ char *field_type_str = type_to_c_string(ft);
expect(l, TOK_SEMICOLON, "Expected ;");
ASTNode *nf = ast_create(NODE_FIELD);
@@ -947,7 +947,7 @@ ASTNode *parse_struct(ParserContext *ctx, Lexer *l, int is_union, int is_opaque)
Token f_name = lexer_next(l);
expect(l, TOK_COLON, "Expected :");
Type *ft = parse_type_formal(ctx, l);
- char *f_type = type_to_string(ft);
+ char *f_type = type_to_c_string(ft);
ASTNode *f = ast_create(NODE_FIELD);
f->field.name = token_strdup(f_name);
@@ -1120,7 +1120,7 @@ ASTNode *parse_enum(ParserContext *ctx, Lexer *l)
while (lexer_peek(l).type == TOK_COMMA)
{
lexer_next(l); // eat ,
- strcat(sig, "_");
+ strcat(sig, "__");
Type *next_t = parse_type_obj(ctx, l);
char *ns = type_to_string(next_t);
if (strlen(sig) + strlen(ns) + 2 > 510)
diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c
index 49e961c..fcbe12d 100644
--- a/src/parser/parser_type.c
+++ b/src/parser/parser_type.c
@@ -427,13 +427,13 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
if (strcmp(name, "uint") == 0)
{
free(name);
- return type_new(TYPE_UINT);
+ return type_new(TYPE_U32); // Strict uint32_t
}
if (strcmp(name, "int") == 0)
{
free(name);
- return type_new(TYPE_INT);
+ return type_new(TYPE_I32); // Strict int32_t
}
if (strcmp(name, "float") == 0)
{
@@ -467,23 +467,31 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
}
if (strcmp(name, "long") == 0)
{
+ zwarn_at(t, "'long' is treated as portable 'int64_t' in Zen C. Use 'c_long' for "
+ "platform-dependent C long.");
free(name);
return type_new(TYPE_I64);
}
if (strcmp(name, "short") == 0)
{
+ zwarn_at(t, "'short' is treated as portable 'int16_t' in Zen C. Use 'c_short' for "
+ "platform-dependent C short.");
free(name);
return type_new(TYPE_I16);
}
if (strcmp(name, "unsigned") == 0)
{
+ zwarn_at(t, "'unsigned' is treated as portable 'uint32_t' in Zen C. Use 'c_uint' for "
+ "platform-dependent C unsigned int.");
free(name);
- return type_new(TYPE_UINT);
+ return type_new(TYPE_U32);
}
if (strcmp(name, "signed") == 0)
{
+ zwarn_at(t, "'signed' is treated as portable 'int32_t' in Zen C. Use 'c_int' for "
+ "platform-dependent C int.");
free(name);
- return type_new(TYPE_INT);
+ return type_new(TYPE_I32);
}
if (strcmp(name, "int8_t") == 0)
{
@@ -536,6 +544,48 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
return type_new(TYPE_ISIZE);
}
+ // Portable C Types
+ if (strcmp(name, "c_int") == 0)
+ {
+ free(name);
+ return type_new(TYPE_C_INT);
+ }
+ if (strcmp(name, "c_uint") == 0)
+ {
+ free(name);
+ return type_new(TYPE_C_UINT);
+ }
+ if (strcmp(name, "c_long") == 0)
+ {
+ free(name);
+ return type_new(TYPE_C_LONG);
+ }
+ if (strcmp(name, "c_ulong") == 0)
+ {
+ free(name);
+ return type_new(TYPE_C_ULONG);
+ }
+ if (strcmp(name, "c_short") == 0)
+ {
+ free(name);
+ return type_new(TYPE_C_SHORT);
+ }
+ if (strcmp(name, "c_ushort") == 0)
+ {
+ free(name);
+ return type_new(TYPE_C_USHORT);
+ }
+ if (strcmp(name, "c_char") == 0)
+ {
+ free(name);
+ return type_new(TYPE_C_CHAR);
+ }
+ if (strcmp(name, "c_uchar") == 0)
+ {
+ free(name);
+ return type_new(TYPE_C_UCHAR);
+ }
+
// Relaxed Type Check: If explicit 'struct Name', trust the user.
if (explicit_struct)
{
@@ -677,7 +727,7 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
zpanic_at(t, "Expected > after generic");
}
- char *unmangled_arg = type_to_c_string(first_arg);
+ char *unmangled_arg = type_to_string(first_arg);
int is_single_dep = 0;
for (int k = 0; k < ctx->known_generics_count; ++k)
@@ -791,7 +841,7 @@ Type *parse_type_base(ParserContext *ctx, Lexer *l)
if (lexer_peek(l).type == TOK_COMMA)
{
lexer_next(l);
- strcat(sig, "_");
+ strcat(sig, "__");
}
else
{
diff --git a/src/parser/parser_utils.c b/src/parser/parser_utils.c
index 28d2c11..8ea2934 100644
--- a/src/parser/parser_utils.c
+++ b/src/parser/parser_utils.c
@@ -691,16 +691,22 @@ void register_tuple(ParserContext *ctx, const char *sig)
s_def->strct.name = xstrdup(struct_name);
char *s_sig = xstrdup(sig);
- char *tok = strtok(s_sig, "_");
+ char *current = s_sig;
+ char *next_sep = strstr(current, "__");
ASTNode *head = NULL, *tail = NULL;
int i = 0;
- while (tok)
+ while (current)
{
+ if (next_sep)
+ {
+ *next_sep = 0;
+ }
+
ASTNode *f = ast_create(NODE_FIELD);
char fname[32];
sprintf(fname, "v%d", i++);
f->field.name = xstrdup(fname);
- f->field.type = xstrdup(tok);
+ f->field.type = xstrdup(current);
if (!head)
{
@@ -712,7 +718,15 @@ void register_tuple(ParserContext *ctx, const char *sig)
}
tail = f;
- tok = strtok(NULL, "_");
+ if (next_sep)
+ {
+ current = next_sep + 2;
+ next_sep = strstr(current, "__");
+ }
+ else
+ {
+ break;
+ }
}
free(s_sig);
s_def->strct.fields = head;