diff options
| author | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-11 15:11:00 +0000 |
|---|---|---|
| committer | Zuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian> | 2026-01-11 15:11:00 +0000 |
| commit | 55247a3f12a9eee7ba3fd7ca6d8fcea7a82c20f3 (patch) | |
| tree | a2a71e2eb8ca0b2c483518c1902d89d18709c9ab /src/parser/parser_type.c | |
| parent | 2e7abed7cfe84a2c0df371cde35f8f68cfdca16c (diff) | |
Added src/ folder. Now I will add the rest.
Diffstat (limited to 'src/parser/parser_type.c')
| -rw-r--r-- | src/parser/parser_type.c | 706 |
1 files changed, 706 insertions, 0 deletions
diff --git a/src/parser/parser_type.c b/src/parser/parser_type.c new file mode 100644 index 0000000..a5f8d86 --- /dev/null +++ b/src/parser/parser_type.c @@ -0,0 +1,706 @@ + +#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) +{ + Token t = lexer_peek(l); + + if (t.type == TOK_IDENT) + { + // Handle "struct Name" or "enum Name" + if ((t.len == 6 && strncmp(t.start, "struct", 6) == 0) || + (t.len == 4 && strncmp(t.start, "enum", 4) == 0)) + { + lexer_next(l); // consume keyword + t = lexer_peek(l); + if (t.type != TOK_IDENT) + { + zpanic_at(t, "Expected identifier after struct/enum"); + } + } + + lexer_next(l); + char *name = token_strdup(t); + + // Self type alias: Replace "Self" with current impl struct type + if (strcmp(name, "Self") == 0 && ctx->current_impl_struct) + { + name = xstrdup(ctx->current_impl_struct); + } + + // Handle Namespace :: (A::B -> A_B) + while (lexer_peek(l).type == TOK_DCOLON) + { + lexer_next(l); // eat :: + Token next = lexer_next(l); + if (next.type != TOK_IDENT) + { + zpanic_at(t, "Expected identifier after ::"); + } + + char *suffix = token_strdup(next); + char *resolved_suffix = suffix; + + // Map Zen Primitive suffixes to C types to match Generic Instantiation + if (strcmp(suffix, "I32") == 0) + { + resolved_suffix = "int32_t"; + } + else if (strcmp(suffix, "U32") == 0) + { + resolved_suffix = "uint32_t"; + } + else if (strcmp(suffix, "I8") == 0) + { + resolved_suffix = "int8_t"; + } + else if (strcmp(suffix, "U8") == 0) + { + resolved_suffix = "uint8_t"; + } + else if (strcmp(suffix, "I16") == 0) + { + resolved_suffix = "int16_t"; + } + else if (strcmp(suffix, "U16") == 0) + { + resolved_suffix = "uint16_t"; + } + else if (strcmp(suffix, "I64") == 0) + { + resolved_suffix = "int64_t"; + } + else if (strcmp(suffix, "U64") == 0) + { + resolved_suffix = "uint64_t"; + } + else if (strcmp(suffix, "usize") == 0) + { + resolved_suffix = "size_t"; + } + else if (strcmp(suffix, "string") == 0) + { + resolved_suffix = "char*"; + } + + // Check if 'name' is a module alias (e.g., m::Vector) + Module *mod = find_module(ctx, name); + char *merged; + if (mod) + { + // Module-qualified type: Use module base name + merged = xmalloc(strlen(mod->base_name) + strlen(resolved_suffix) + 2); + sprintf(merged, "%s_%s", mod->base_name, resolved_suffix); + } + else + { + // Regular namespace or enum variant + merged = xmalloc(strlen(name) + strlen(resolved_suffix) + 2); + sprintf(merged, "%s_%s", name, resolved_suffix); + } + + free(name); + if (suffix != resolved_suffix) + { + free(suffix); // Only free if we didn't remap + } + else + { + free(suffix); + } + + name = merged; + } + + // Check for Primitives (Base types) + if (strcmp(name, "U0") == 0) + { + free(name); + return type_new(TYPE_VOID); + } + if (strcmp(name, "I8") == 0) + { + free(name); + return type_new(TYPE_I8); + } + if (strcmp(name, "U8") == 0) + { + free(name); + return type_new(TYPE_U8); + } + if (strcmp(name, "I16") == 0) + { + free(name); + return type_new(TYPE_I16); + } + if (strcmp(name, "U16") == 0) + { + free(name); + return type_new(TYPE_U16); + } + if (strcmp(name, "I32") == 0) + { + free(name); + return type_new(TYPE_I32); + } + if (strcmp(name, "U32") == 0) + { + free(name); + return type_new(TYPE_U32); + } + if (strcmp(name, "I64") == 0) + { + free(name); + return type_new(TYPE_I64); + } + if (strcmp(name, "U64") == 0) + { + free(name); + return type_new(TYPE_U64); + } + if (strcmp(name, "F32") == 0) + { + free(name); + return type_new(TYPE_F32); + } + if (strcmp(name, "F64") == 0) + { + free(name); + return type_new(TYPE_F64); + } + if (strcmp(name, "usize") == 0) + { + free(name); + return type_new(TYPE_USIZE); + } + if (strcmp(name, "isize") == 0) + { + free(name); + return type_new(TYPE_ISIZE); + } + if (strcmp(name, "byte") == 0) + { + free(name); + return type_new(TYPE_BYTE); + } + if (strcmp(name, "I128") == 0) + { + free(name); + return type_new(TYPE_I128); + } + if (strcmp(name, "U128") == 0) + { + free(name); + return type_new(TYPE_U128); + } + if (strcmp(name, "rune") == 0) + { + free(name); + return type_new(TYPE_RUNE); + } + if (strcmp(name, "uint") == 0) + { + free(name); + return type_new(TYPE_UINT); + } + + if (strcmp(name, "int") == 0) + { + free(name); + return type_new(TYPE_INT); + } + if (strcmp(name, "float") == 0) + { + free(name); + return type_new(TYPE_F32); + } + if (strcmp(name, "double") == 0) + { + free(name); + return type_new(TYPE_F64); + } + if (strcmp(name, "void") == 0) + { + free(name); + return type_new(TYPE_VOID); + } + if (strcmp(name, "string") == 0) + { + free(name); + return type_new(TYPE_STRING); + } + if (strcmp(name, "bool") == 0) + { + free(name); + return type_new(TYPE_BOOL); + } + if (strcmp(name, "char") == 0) + { + free(name); + return type_new(TYPE_CHAR); + } + + // Selective imports ONLY apply when we're NOT in a module context + if (!ctx->current_module_prefix) + { + SelectiveImport *si = find_selective_import(ctx, name); + if (si) + { + // This is a selectively imported symbol + // 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); + } + } + + // 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) + char *prefixed_name = xmalloc(strlen(ctx->current_module_prefix) + strlen(name) + 2); + sprintf(prefixed_name, "%s_%s", ctx->current_module_prefix, name); + free(name); + name = prefixed_name; + } + + Type *ty = type_new(TYPE_STRUCT); + ty->name = name; + + // Handle Generics <T> + if (lexer_peek(l).type == TOK_LANGLE) + { + lexer_next(l); // eat < + Type *arg = parse_type_formal(ctx, l); + + // 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) + { + lexer_next(l); // Consume > + } + else if (next_tok.type == TOK_OP && next_tok.len == 2 && + strncmp(next_tok.start, ">>", 2) == 0) + { + // Split >> into two > tokens + // Consume the first > by advancing lexer manually + l->pos += 1; + l->col += 1; + } + else + { + zpanic_at(t, "Expected > after generic"); + } + + // --- INSTANTIATION TRIGGER --- + char *arg_str = type_to_string(arg); + instantiate_generic(ctx, name, arg_str); + + char *clean_arg = sanitize_mangled_name(arg_str); + char mangled[256]; + sprintf(mangled, "%s_%s", name, clean_arg); + free(clean_arg); + + free(ty->name); + ty->name = xstrdup(mangled); + free(arg_str); + + ty->kind = TYPE_STRUCT; + ty->args = NULL; + ty->arg_count = 0; + } + return ty; + } + + if (t.type == TOK_LBRACKET) + { + lexer_next(l); // eat [ + Type *inner = parse_type_formal(ctx, l); + + // Check for fixed-size array [T; N] + if (lexer_peek(l).type == TOK_SEMICOLON) + { + lexer_next(l); // eat ; + Token size_tok = lexer_next(l); + int size = 0; + if (size_tok.type == TOK_INT) + { + size = atoi(size_tok.start); + } + else if (size_tok.type == TOK_IDENT) + { + // Look up in symbol table for constant propagation + char *name = token_strdup(size_tok); + Symbol *sym = find_symbol_entry(ctx, name); + if (sym && sym->is_const_value) + { + size = sym->const_int_val; + sym->is_used = 1; // MARK AS USED + } + else + { + zpanic_at(size_tok, + "Array size must be a compile-time constant or integer literal"); + } + free(name); + } + else + { + zpanic_at(size_tok, "Expected integer for array size"); + } + if (lexer_next(l).type != TOK_RBRACKET) + { + zpanic("Expected ] after array size"); + } + + Type *arr = type_new(TYPE_ARRAY); + arr->inner = inner; + arr->array_size = size; + return arr; + } + + // Otherwise it's a slice [T] + if (lexer_next(l).type != TOK_RBRACKET) + { + zpanic("Expected ] in type"); + } + + // Register Slice + char *inner_str = type_to_string(inner); + register_slice(ctx, inner_str); + + Type *arr = type_new(TYPE_ARRAY); + arr->inner = inner; + arr->array_size = 0; // 0 means slice, not fixed-size + return arr; + } + + if (t.type == TOK_LPAREN) + { + lexer_next(l); // eat ( + char sig[256]; + sig[0] = 0; + + while (1) + { + Type *sub = parse_type_formal(ctx, l); + char *s = type_to_string(sub); + strcat(sig, s); + free(s); + + if (lexer_peek(l).type == TOK_COMMA) + { + lexer_next(l); + strcat(sig, "_"); + } + else + { + break; + } + } + if (lexer_next(l).type != TOK_RPAREN) + { + zpanic("Expected ) in tuple"); + } + + register_tuple(ctx, sig); + + char *tuple_name = xmalloc(strlen(sig) + 7); + sprintf(tuple_name, "Tuple_%s", sig); + + Type *ty = type_new(TYPE_STRUCT); + ty->name = tuple_name; + return ty; + } + + return type_new(TYPE_UNKNOWN); +} + +Type *parse_type_formal(ParserContext *ctx, Lexer *l) +{ + int is_restrict = 0; + if (lexer_peek(l).type == TOK_IDENT && lexer_peek(l).len == 8 && + strncmp(lexer_peek(l).start, "restrict", 8) == 0) + { + lexer_next(l); // eat restrict + is_restrict = 1; + } + + // 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' + Type *fn_type = type_new(TYPE_FUNCTION); + fn_type->is_varargs = 0; + + expect(l, TOK_LPAREN, "Expected '(' for function type"); + + // Parse Arguments + fn_type->arg_count = 0; + fn_type->args = NULL; + + while (lexer_peek(l).type != TOK_RPAREN) + { + Type *arg = parse_type_formal(ctx, l); + fn_type->arg_count++; + fn_type->args = xrealloc(fn_type->args, sizeof(Type *) * fn_type->arg_count); + fn_type->args[fn_type->arg_count - 1] = arg; + + if (lexer_peek(l).type == TOK_COMMA) + { + lexer_next(l); + } + else + { + break; + } + } + expect(l, TOK_RPAREN, "Expected ')' after function args"); + + // Parse Return Type (-> Type) + if (lexer_peek(l).type == TOK_ARROW) + { + lexer_next(l); // eat -> + fn_type->inner = parse_type_formal(ctx, l); // Return type stored in inner + } + else + { + fn_type->inner = type_new(TYPE_VOID); + } + + return fn_type; + } + + // 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 == '*') + { + lexer_next(l); // consume '*' + t = type_new_ptr(t); + } + + // 4. Handle Array Suffixes (e.g. int[10]) + while (lexer_peek(l).type == TOK_LBRACKET) + { + lexer_next(l); // consume '[' + + int size = 0; + if (lexer_peek(l).type == TOK_INT) + { + Token t = lexer_peek(l); + char buffer[64]; + int len = t.len < 63 ? t.len : 63; + strncpy(buffer, t.start, len); + buffer[len] = 0; + size = atoi(buffer); + lexer_next(l); + } + + expect(l, TOK_RBRACKET, "Expected ']' in array type"); + + Type *arr = type_new(TYPE_ARRAY); + arr->inner = t; + arr->array_size = size; + t = arr; + } + + if (is_restrict) + { + t->is_restrict = 1; + } + return t; +} + +char *parse_type(ParserContext *ctx, Lexer *l) +{ + Type *t = parse_type_formal(ctx, l); + + return type_to_string(t); +} + +char *parse_array_literal(ParserContext *ctx, Lexer *l, const char *st) +{ + (void)ctx; // suppress unused parameter warning + lexer_next(l); + size_t cap = 128; + char *c = xmalloc(cap); + c[0] = 0; + int n = 0; + + while (1) + { + Token t = lexer_peek(l); + if (t.type == TOK_RBRACKET) + { + lexer_next(l); + break; + } + if (t.type == TOK_COMMA) + { + lexer_next(l); + continue; + } + + const char *s = l->src + l->pos; + int d = 0; + while (1) + { + Token it = lexer_peek(l); + if (it.type == TOK_EOF) + { + break; + } + if (d == 0 && (it.type == TOK_COMMA || it.type == TOK_RBRACKET)) + { + break; + } + if (it.type == TOK_LBRACKET || it.type == TOK_LPAREN) + { + d++; + } + if (it.type == TOK_RBRACKET || it.type == TOK_RPAREN) + { + d--; + } + lexer_next(l); + } + + int len = (l->src + l->pos) - s; + if (strlen(c) + len + 5 > cap) + { + cap *= 2; + c = xrealloc(c, cap); + } + if (n > 0) + { + strcat(c, ", "); + } + strncat(c, s, len); + n++; + } + + char rt[64]; + if (strncmp(st, "Slice_", 6) == 0) + { + strcpy(rt, st + 6); + } + else + { + strcpy(rt, "int"); + } + + char *o = xmalloc(strlen(c) + 128); + sprintf(o, "(%s){.data=(%s[]){%s},.len=%d,.cap=%d}", st, rt, c, n, n); + free(c); + return o; +} +char *parse_tuple_literal(ParserContext *ctx, Lexer *l, const char *tn) +{ + (void)ctx; // suppress unused parameter warning + lexer_next(l); + size_t cap = 128; + char *c = xmalloc(cap); + c[0] = 0; + + while (1) + { + Token t = lexer_peek(l); + if (t.type == TOK_RPAREN) + { + lexer_next(l); + break; + } + if (t.type == TOK_COMMA) + { + lexer_next(l); + continue; + } + + const char *s = l->src + l->pos; + int d = 0; + while (1) + { + Token it = lexer_peek(l); + if (it.type == TOK_EOF) + { + break; + } + if (d == 0 && (it.type == TOK_COMMA || it.type == TOK_RPAREN)) + { + break; + } + if (it.type == TOK_LPAREN) + { + d++; + } + if (it.type == TOK_RPAREN) + { + d--; + } + lexer_next(l); + } + + int len = (l->src + l->pos) - s; + if (strlen(c) + len + 5 > cap) + { + cap *= 2; + c = xrealloc(c, cap); + } + if (strlen(c) > 0) + { + strcat(c, ", "); + } + strncat(c, s, len); + } + + char *o = xmalloc(strlen(c) + 128); + sprintf(o, "(%s){%s}", tn, c); + free(c); + return o; +} +char *parse_embed(ParserContext *ctx, Lexer *l) +{ + lexer_next(l); + Token t = lexer_next(l); + if (t.type != TOK_STRING) + { + zpanic("String required"); + } + char fn[256]; + strncpy(fn, t.start + 1, t.len - 2); + fn[t.len - 2] = 0; + + FILE *f = fopen(fn, "rb"); + if (!f) + { + zpanic("404: %s", fn); + } + fseek(f, 0, SEEK_END); + long len = ftell(f); + rewind(f); + unsigned char *b = xmalloc(len); + fread(b, 1, len, f); + fclose(f); + + register_slice(ctx, "char"); + size_t oc = len * 6 + 128; + char *o = xmalloc(oc); + sprintf(o, "(Slice_char){.data=(char[]){"); + char *p = o + strlen(o); + for (int i = 0; i < len; i++) + { + p += sprintf(p, "0x%02X,", b[i]); + } + sprintf(p, "},.len=%ld,.cap=%ld}", len, len); + free(b); + return o; +} |
