summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/ast/ast.c74
-rw-r--r--src/ast/ast.h1
-rw-r--r--src/codegen/codegen.c3
-rw-r--r--src/codegen/codegen_utils.c68
-rw-r--r--src/parser/parser_type.c27
5 files changed, 149 insertions, 24 deletions
diff --git a/src/ast/ast.c b/src/ast/ast.c
index b20d9c2..0799845 100644
--- a/src/ast/ast.c
+++ b/src/ast/ast.c
@@ -59,6 +59,8 @@ Type *type_new(TypeKind kind)
t->args = NULL;
t->arg_count = 0;
t->is_const = 0;
+ t->is_explicit_struct = 0;
+ t->is_raw = 0;
t->array_size = 0;
return t;
}
@@ -283,6 +285,36 @@ static char *type_to_string_impl(Type *t)
}
case TYPE_FUNCTION:
+ if (t->is_raw)
+ {
+ // fn*(Args)->Ret
+ char *ret = type_to_string(t->inner);
+ char *res = xmalloc(strlen(ret) + 64);
+ sprintf(res, "fn*(");
+
+ for (int i = 0; i < t->arg_count; i++)
+ {
+ if (i > 0)
+ {
+ char *tmp = xmalloc(strlen(res) + 3);
+ sprintf(tmp, "%s, ", res);
+ free(res);
+ res = tmp;
+ }
+ char *arg = type_to_string(t->args[i]);
+ char *tmp = xmalloc(strlen(res) + strlen(arg) + 1);
+ sprintf(tmp, "%s%s", res, arg);
+ free(res);
+ res = tmp;
+ free(arg);
+ }
+ char *tmp = xmalloc(strlen(res) + strlen(ret) + 5); // ) -> Ret
+ sprintf(tmp, "%s) -> %s", res, ret);
+ free(res);
+ res = tmp;
+ free(ret);
+ return res;
+ }
if (t->inner)
{
free(type_to_string(t->inner));
@@ -410,6 +442,19 @@ static char *type_to_c_string_impl(Type *t)
case TYPE_POINTER:
{
char *inner = type_to_c_string(t->inner);
+ char *ptr_token = strstr(inner, "(*");
+ if (ptr_token)
+ {
+ long prefix_len = ptr_token - inner + 2; // "void (*"
+ char *res = xmalloc(strlen(inner) + 2);
+ strncpy(res, inner, prefix_len);
+ res[prefix_len] = 0;
+ strcat(res, "*");
+ strcat(res, ptr_token + 2);
+ free(inner);
+ return res;
+ }
+
if (t->is_restrict)
{
char *res = xmalloc(strlen(inner) + 16);
@@ -441,6 +486,35 @@ static char *type_to_c_string_impl(Type *t)
}
case TYPE_FUNCTION:
+ if (t->is_raw)
+ {
+ char *ret = type_to_c_string(t->inner);
+ char *res = xmalloc(strlen(ret) + 64); // heuristic start buffer
+ sprintf(res, "%s (*)(", ret);
+
+ for (int i = 0; i < t->arg_count; i++)
+ {
+ if (i > 0)
+ {
+ char *tmp = xmalloc(strlen(res) + 3);
+ sprintf(tmp, "%s, ", res);
+ free(res);
+ res = tmp;
+ }
+ char *arg = type_to_c_string(t->args[i]);
+ char *tmp = xmalloc(strlen(res) + strlen(arg) + 1);
+ sprintf(tmp, "%s%s", res, arg);
+ free(res);
+ res = tmp;
+ free(arg);
+ }
+ char *tmp = xmalloc(strlen(res) + 2);
+ sprintf(tmp, "%s)", res);
+ free(res);
+ res = tmp;
+ free(ret);
+ return res;
+ }
if (t->inner)
{
free(type_to_c_string(t->inner));
diff --git a/src/ast/ast.h b/src/ast/ast.h
index 1614f3c..12d8f2b 100644
--- a/src/ast/ast.h
+++ b/src/ast/ast.h
@@ -64,6 +64,7 @@ typedef struct Type
int arg_count;
int is_const;
int is_explicit_struct; // for example, "struct Foo" vs "Foo"
+ int is_raw; // Raw function pointer (fn*)
union
{
int array_size; // For fixed-size arrays [T; N].
diff --git a/src/codegen/codegen.c b/src/codegen/codegen.c
index 689c4dc..7c58943 100644
--- a/src/codegen/codegen.c
+++ b/src/codegen/codegen.c
@@ -549,7 +549,8 @@ void codegen_expression(ParserContext *ctx, ASTNode *node, FILE *out)
}
}
- if (node->call.callee->type_info && node->call.callee->type_info->kind == TYPE_FUNCTION)
+ if (node->call.callee->type_info && node->call.callee->type_info->kind == TYPE_FUNCTION &&
+ !node->call.callee->type_info->is_raw)
{
fprintf(out, "({ z_closure_T _c = ");
codegen_expression(ctx, node->call.callee, out);
diff --git a/src/codegen/codegen_utils.c b/src/codegen/codegen_utils.c
index cdb2110..6283bce 100644
--- a/src/codegen/codegen_utils.c
+++ b/src/codegen/codegen_utils.c
@@ -40,19 +40,33 @@ char *strip_template_suffix(const char *name)
return xstrdup(name);
}
-// Helper to emit variable declarations with array types.
-void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, const char *var_name)
+// Helper to emit C declaration (handle arrays, function pointers correctly)
+void emit_c_decl(FILE *out, const char *type_str, const char *name)
{
- (void)ctx;
-
char *bracket = strchr(type_str, '[');
char *generic = strchr(type_str, '<');
+ char *fn_ptr = strstr(type_str, "(*");
- if (generic && (!bracket || generic < bracket))
+ if (fn_ptr)
+ {
+ char *end_paren = strchr(fn_ptr, ')');
+ if (end_paren)
+ {
+ int prefix_len = end_paren - type_str;
+ fprintf(out, "%.*s%s%s", prefix_len, type_str, name, end_paren);
+ }
+ else
+ {
+ // Fallback if malformed (shouldn't happen)
+ int prefix_len = fn_ptr - type_str + 2;
+ fprintf(out, "%.*s%s%s", prefix_len, type_str, name, fn_ptr + 2);
+ }
+ }
+ else if (generic && (!bracket || generic < bracket))
{
// Strip generic part for C output
int base_len = generic - type_str;
- fprintf(out, "%.*s %s", base_len, type_str, var_name);
+ fprintf(out, "%.*s %s", base_len, type_str, name);
if (bracket)
{
@@ -62,14 +76,21 @@ void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, con
else if (bracket)
{
int base_len = bracket - type_str;
- fprintf(out, "%.*s %s%s", base_len, type_str, var_name, bracket);
+ fprintf(out, "%.*s %s%s", base_len, type_str, name, bracket);
}
else
{
- fprintf(out, "%s %s", type_str, var_name);
+ fprintf(out, "%s %s", type_str, name);
}
}
+// Helper to emit variable declarations with array types.
+void emit_var_decl_type(ParserContext *ctx, FILE *out, const char *type_str, const char *var_name)
+{
+ (void)ctx;
+ emit_c_decl(out, type_str, var_name);
+}
+
// Find struct definition
ASTNode *find_struct_def_codegen(ParserContext *ctx, const char *name)
{
@@ -649,7 +670,20 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override)
ret_str = xstrdup("void");
}
- fprintf(out, "%s %s(", ret_str, name_override ? name_override : func->func.name);
+ char *ret_suffix = NULL;
+ char *fn_ptr = strstr(ret_str, "(*)");
+
+ if (fn_ptr)
+ {
+ int prefix_len = fn_ptr - ret_str + 2; // Include "(*"
+ fprintf(out, "%.*s%s(", prefix_len, ret_str,
+ name_override ? name_override : func->func.name);
+ ret_suffix = fn_ptr + 2;
+ }
+ else
+ {
+ fprintf(out, "%s %s(", ret_str, name_override ? name_override : func->func.name);
+ }
free(ret_str);
// Args
@@ -683,16 +717,7 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override)
}
// check if array type
- char *bracket = strchr(type_str, '[');
- if (bracket)
- {
- int base_len = bracket - type_str;
- fprintf(out, "%.*s %s%s", base_len, type_str, name, bracket);
- }
- else
- {
- fprintf(out, "%s %s", type_str, name);
- }
+ emit_c_decl(out, type_str, name);
free(type_str);
}
if (func->func.is_varargs)
@@ -705,6 +730,11 @@ void emit_func_signature(FILE *out, ASTNode *func, const char *name_override)
}
}
fprintf(out, ")");
+
+ if (ret_suffix)
+ {
+ fprintf(out, "%s", ret_suffix);
+ }
}
// Invalidate a moved-from variable by zeroing it out to prevent double-free
diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c
index 5774571..0585baa 100644
--- a/src/parser/parser_type.c
+++ b/src/parser/parser_type.c
@@ -751,14 +751,31 @@ Type *parse_type_formal(ParserContext *ctx, Lexer *l)
}
}
+ Type *t = NULL;
+
// Example: fn(int, int) -> int
if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "fn", 2) == 0 &&
lexer_peek(l).len == 2)
{
lexer_next(l); // eat 'fn'
+
+ int star_count = 0;
+ while (lexer_peek(l).type == TOK_OP && strncmp(lexer_peek(l).start, "*", 1) == 0)
+ {
+ lexer_next(l);
+ star_count++;
+ }
+
Type *fn_type = type_new(TYPE_FUNCTION);
+ fn_type->is_raw = (star_count > 0);
fn_type->is_varargs = 0;
+ Type *wrapped = fn_type;
+ for (int i = 1; i < star_count; i++)
+ {
+ wrapped = type_new_ptr(wrapped);
+ }
+
expect(l, TOK_LPAREN, "Expected '(' for function type");
// Parse Arguments
@@ -794,11 +811,13 @@ Type *parse_type_formal(ParserContext *ctx, Lexer *l)
fn_type->inner = type_new(TYPE_VOID);
}
- return fn_type;
+ t = wrapped;
+ }
+ else
+ {
+ // Handles: int, Struct, Generic<T>, [Slice], (Tuple)
+ t = parse_type_base(ctx, l);
}
-
- // Handles: int, Struct, Generic<T>, [Slice], (Tuple)
- Type *t = parse_type_base(ctx, l);
// Handles: T*, T**, etc.
while (lexer_peek(l).type == TOK_OP && *lexer_peek(l).start == '*')