diff options
| author | suresh <sureshkrishnan.ai@gmail.com> | 2026-01-25 11:43:23 -0500 |
|---|---|---|
| committer | suresh <sureshkrishnan.ai@gmail.com> | 2026-01-25 11:43:23 -0500 |
| commit | 26a0b55ed5bce4ad0ba2af109cfc96da7be2e34c (patch) | |
| tree | 35ba8d7742b8ac727bfc6c4c73ab8b70f6eedb53 /src | |
| parent | 0bb69cb67078dfa921b5b8a42275ef31dfbc9a56 (diff) | |
| parent | 489336b2101bf16edeec7bfc4379408eb19b936e (diff) | |
Merge branch 'main' into JsonType
# Conflicts:
# examples/data/json_config.zc
Diffstat (limited to 'src')
| -rw-r--r-- | src/ast/ast.c | 74 | ||||
| -rw-r--r-- | src/ast/ast.h | 1 | ||||
| -rw-r--r-- | src/codegen/codegen.c | 3 | ||||
| -rw-r--r-- | src/codegen/codegen_utils.c | 68 | ||||
| -rw-r--r-- | src/parser/parser_core.c | 42 | ||||
| -rw-r--r-- | src/parser/parser_stmt.c | 25 | ||||
| -rw-r--r-- | src/parser/parser_type.c | 27 |
7 files changed, 187 insertions, 53 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_core.c b/src/parser/parser_core.c index 3bc6d66..5e685d7 100644 --- a/src/parser/parser_core.c +++ b/src/parser/parser_core.c @@ -337,18 +337,18 @@ ASTNode *parse_program_nodes(ParserContext *ctx, Lexer *l) { s = parse_import(ctx, l); } - else if (t.len == 3 && strncmp(t.start, "var", 3) == 0) + else if (t.len == 3 && strncmp(t.start, "let", 3) == 0) { s = parse_var_decl(ctx, l); } - else if (t.len == 3 && strncmp(t.start, "def", 3) == 0) + else if (t.len == 3 && strncmp(t.start, "var", 3) == 0) { - s = parse_def(ctx, l); + zpanic_at(t, "'var' is deprecated. Use 'let' instead."); } else if (t.len == 5 && strncmp(t.start, "const", 5) == 0) { zpanic_at(t, "'const' for declarations is deprecated. Use 'def' for constants or " - "'var x: const T' for read-only variables."); + "'let x: const T' for read-only variables."); } else if (t.len == 6 && strncmp(t.start, "extern", 6) == 0) { @@ -673,23 +673,23 @@ static ASTNode *generate_derive_impls(ParserContext *ctx, ASTNode *strct, char * // Map types to appropriate get_* calls if (strcmp(ft, "int") == 0) { - sprintf(assign, "var _f_%s = (*j).get_int(\"%s\").unwrap_or(0);\n", fn, fn); + sprintf(assign, "let _f_%s = (*j).get_int(\"%s\").unwrap_or(0);\n", fn, fn); } else if (strcmp(ft, "double") == 0) { - sprintf(assign, "var _f_%s = (*j).get_float(\"%s\").unwrap_or(0.0);\n", fn, fn); + sprintf(assign, "let _f_%s = (*j).get_float(\"%s\").unwrap_or(0.0);\n", fn, fn); } else if (strcmp(ft, "bool") == 0) { - sprintf(assign, "var _f_%s = (*j).get_bool(\"%s\").unwrap_or(false);\n", fn, fn); + sprintf(assign, "let _f_%s = (*j).get_bool(\"%s\").unwrap_or(false);\n", fn, fn); } else if (strcmp(ft, "char*") == 0) { - sprintf(assign, "var _f_%s = (*j).get_string(\"%s\").unwrap_or(\"\");\n", fn, fn); + sprintf(assign, "let _f_%s = (*j).get_string(\"%s\").unwrap_or(\"\");\n", fn, fn); } else if (strcmp(ft, "String") == 0) { - sprintf(assign, "var _f_%s = String::new((*j).get_string(\"%s\").unwrap_or(\"\"));\n", fn, fn); + sprintf(assign, "let _f_%s = String::new((*j).get_string(\"%s\").unwrap_or(\"\"));\n", fn, fn); } else if (ft && strstr(ft, "Vec") && strstr(ft, "String")) { @@ -699,16 +699,16 @@ static ASTNode *generate_derive_impls(ParserContext *ctx, ASTNode *strct, char * vec_fields[vec_field_count++] = fn; } sprintf(assign, - "var _f_%s = Vec<String>::new();\n" - "var _arr_%s = (*j).get_array(\"%s\");\n" + "let _f_%s = Vec<String>::new();\n" + "let _arr_%s = (*j).get_array(\"%s\");\n" "if _arr_%s.is_some() {\n" - " var _a_%s = _arr_%s.unwrap();\n" - " for var _i_%s: usize = 0; _i_%s < _a_%s.len(); _i_%s = _i_%s + 1 {\n" - " var _item_%s = _a_%s.at(_i_%s);\n" + " let _a_%s = _arr_%s.unwrap();\n" + " for let _i_%s: usize = 0; _i_%s < _a_%s.len(); _i_%s = _i_%s + 1 {\n" + " let _item_%s = _a_%s.at(_i_%s);\n" " if _item_%s.is_some() {\n" - " var _str_%s = (*_item_%s.unwrap()).as_string();\n" + " let _str_%s = (*_item_%s.unwrap()).as_string();\n" " if _str_%s.is_some() {\n" - " var _s_%s = String::new(_str_%s.unwrap());\n" + " let _s_%s = String::new(_str_%s.unwrap());\n" " _f_%s.push(_s_%s); _s_%s.forget();\n" " }\n" " }\n" @@ -720,8 +720,8 @@ static ASTNode *generate_derive_impls(ParserContext *ctx, ASTNode *strct, char * { // Nested struct: call NestedType::from_json recursively sprintf(assign, - "var _opt_%s = (*j).get(\"%s\");\n" - "var _f_%s: %s;\n" + "let _opt_%s = (*j).get(\"%s\");\n" + "let _f_%s: %s;\n" "if _opt_%s.is_some() { _f_%s = %s::from_json(_opt_%s.unwrap()).unwrap(); }\n", fn, fn, fn, ft, fn, fn, ft, fn); } @@ -786,7 +786,7 @@ static ASTNode *generate_derive_impls(ParserContext *ctx, ASTNode *strct, char * } char body[8192]; - strcpy(body, "var _obj = JsonValue::object();\n"); + strcpy(body, "let _obj = JsonValue::object();\n"); ASTNode *f = strct->strct.fields; while (f) @@ -826,8 +826,8 @@ static ASTNode *generate_derive_impls(ParserContext *ctx, ASTNode *strct, char * else if (ft && strstr(ft, "Vec") && strstr(ft, "String")) { sprintf(set_call, - "var _arr_%s = JsonValue::array();\n" - "for var _i_%s: usize = 0; _i_%s < self.%s.length(); _i_%s = _i_%s + 1 {\n" + "let _arr_%s = JsonValue::array();\n" + "for let _i_%s: usize = 0; _i_%s < self.%s.length(); _i_%s = _i_%s + 1 {\n" " _arr_%s.push(JsonValue::string(self.%s.get(_i_%s).c_str()));\n" "}\n" "_obj.set(\"%s\", _arr_%s);\n", diff --git a/src/parser/parser_stmt.c b/src/parser/parser_stmt.c index 54e9b88..18146a5 100644 --- a/src/parser/parser_stmt.c +++ b/src/parser/parser_stmt.c @@ -1278,10 +1278,14 @@ ASTNode *parse_for(ParserContext *ctx, Lexer *l) ASTNode *init = NULL; if (lexer_peek(l).type != TOK_SEMICOLON) { - if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "var", 3) == 0) + if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "let", 3) == 0) { init = parse_var_decl(ctx, l); } + else if (lexer_peek(l).type == TOK_IDENT && strncmp(lexer_peek(l).start, "var", 3) == 0) + { + zpanic_at(lexer_peek(l), "'var' is deprecated. Use 'let' instead."); + } else { init = parse_expression(ctx, l); @@ -1936,9 +1940,9 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l) if (tk.type == TOK_AUTOFREE) { lexer_next(l); - if (lexer_peek(l).type != TOK_IDENT || strncmp(lexer_peek(l).start, "var", 3) != 0) + if (lexer_peek(l).type != TOK_IDENT || strncmp(lexer_peek(l).start, "let", 3) != 0) { - zpanic_at(lexer_peek(l), "Expected 'var' after autofree"); + zpanic_at(lexer_peek(l), "Expected 'let' after autofree"); } s = parse_var_decl(ctx, l); s->var_decl.is_autofree = 1; @@ -2077,28 +2081,33 @@ ASTNode *parse_statement(ParserContext *ctx, Lexer *l) return parse_plugin(ctx, l); } - if (strncmp(tk.start, "var", 3) == 0 && tk.len == 3) + if (strncmp(tk.start, "let", 3) == 0 && tk.len == 3) { return parse_var_decl(ctx, l); } - // Static local variable: static var x = 0; + if (strncmp(tk.start, "var", 3) == 0 && tk.len == 3) + { + zpanic_at(tk, "'var' is deprecated. Use 'let' instead."); + } + + // Static local variable: static let x = 0; if (strncmp(tk.start, "static", 6) == 0 && tk.len == 6) { lexer_next(l); // eat 'static' Token next = lexer_peek(l); - if (strncmp(next.start, "var", 3) == 0 && next.len == 3) + if (strncmp(next.start, "let", 3) == 0 && next.len == 3) { ASTNode *v = parse_var_decl(ctx, l); v->var_decl.is_static = 1; return v; } - zpanic_at(next, "Expected 'var' after 'static'"); + zpanic_at(next, "Expected 'let' after 'static'"); } if (strncmp(tk.start, "const", 5) == 0 && tk.len == 5) { - zpanic_at(tk, "'const' for declarations is deprecated. Use 'def' for constants or 'var " + zpanic_at(tk, "'const' for declarations is deprecated. Use 'def' for constants or 'let " "x: const T' for read-only variables."); } if (strncmp(tk.start, "return", 6) == 0 && tk.len == 6) 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 == '*') |
