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/ast | |
| parent | 2e7abed7cfe84a2c0df371cde35f8f68cfdca16c (diff) | |
Added src/ folder. Now I will add the rest.
Diffstat (limited to 'src/ast')
| -rw-r--r-- | src/ast/ast.c | 283 | ||||
| -rw-r--r-- | src/ast/ast.h | 543 |
2 files changed, 826 insertions, 0 deletions
diff --git a/src/ast/ast.c b/src/ast/ast.c new file mode 100644 index 0000000..4688bf7 --- /dev/null +++ b/src/ast/ast.c @@ -0,0 +1,283 @@ + +#include <stdlib.h> +#include <string.h> +#include "ast.h" +#include "zprep.h" +#include "../parser/parser.h" + +typedef struct TraitReg +{ + char *name; + struct TraitReg *next; +} TraitReg; + +static TraitReg *registered_traits = NULL; + +void register_trait(const char *name) +{ + TraitReg *r = xmalloc(sizeof(TraitReg)); + r->name = xstrdup(name); + r->next = registered_traits; + registered_traits = r; +} + +int is_trait(const char *name) +{ + TraitReg *r = registered_traits; + while (r) + { + if (0 == strcmp(r->name, name)) + { + return 1; + } + r = r->next; + } + return 0; +} + +ASTNode *ast_create(NodeType type) +{ + ASTNode *node = xmalloc(sizeof(ASTNode)); + memset(node, 0, sizeof(ASTNode)); + node->type = type; + return node; +} + +void ast_free(ASTNode *node) +{ + (void)node; + return; +} + +Type *type_new(TypeKind kind) +{ + Type *t = xmalloc(sizeof(Type)); + t->kind = kind; + t->name = NULL; + t->inner = NULL; + t->args = NULL; + t->arg_count = 0; + t->is_const = 0; + t->array_size = 0; + return t; +} + +Type *type_new_ptr(Type *inner) +{ + Type *t = type_new(TYPE_POINTER); + t->inner = inner; + return t; +} + +int is_char_ptr(Type *t) +{ + // Handle both primitive char* and legacy struct char*. + if (TYPE_POINTER == t->kind && TYPE_CHAR == t->inner->kind) + { + return 1; + } + if (TYPE_POINTER == t->kind && TYPE_STRUCT == t->inner->kind && + 0 == strcmp(t->inner->name, "char")) + { + return 1; + } + return 0; +} + +int is_integer_type(Type *t) +{ + if (!t) + { + return 0; + } + + return (t->kind == TYPE_INT || t->kind == TYPE_CHAR || t->kind == TYPE_BOOL || + t->kind == TYPE_I8 || t->kind == TYPE_U8 || t->kind == TYPE_I16 || + t->kind == TYPE_U16 || t->kind == TYPE_I32 || t->kind == TYPE_U32 || + t->kind == TYPE_I64 || t->kind == TYPE_U64 || t->kind == TYPE_USIZE || + t->kind == TYPE_ISIZE || t->kind == TYPE_BYTE || t->kind == TYPE_RUNE || + t->kind == TYPE_UINT || t->kind == TYPE_I128 || t->kind == TYPE_U128); +} + +int is_float_type(Type *t) +{ + if (!t) + { + return 0; + } + + return (t->kind == TYPE_FLOAT || t->kind == TYPE_F32 || t->kind == TYPE_F64); +} + +int type_eq(Type *a, Type *b) +{ + if (!a || !b) + { + return 0; + } + + if (a == b) + { + return 1; + } + + // Lax integer matching (bool == int, char == i8, etc.). + if (is_integer_type(a) && is_integer_type(b)) + { + return 1; + } + + // Lax float matching. + if (is_float_type(a) && is_float_type(b)) + { + return 1; + } + + // String Literal vs char* + if (a->kind == TYPE_STRING && is_char_ptr(b)) + { + return 1; + } + + if (b->kind == TYPE_STRING && is_char_ptr(a)) + { + return 1; + } + + if (a->kind != b->kind) + { + return 0; + } + + if (a->kind == TYPE_STRUCT || a->kind == TYPE_GENERIC) + { + return 0 == strcmp(a->name, b->name); + } + if (a->kind == TYPE_POINTER || a->kind == TYPE_ARRAY) + { + return type_eq(a->inner, b->inner); + } + + return 1; +} + +char *type_to_string(Type *t) +{ + if (!t) + { + return xstrdup("void"); + } + + switch (t->kind) + { + case TYPE_VOID: + return xstrdup("void"); + case TYPE_BOOL: + return xstrdup("bool"); + case TYPE_STRING: + return xstrdup("string"); + case TYPE_CHAR: + return xstrdup("char"); + case TYPE_I8: + return xstrdup("int8_t"); + case TYPE_U8: + return xstrdup("uint8_t"); + case TYPE_I16: + return xstrdup("int16_t"); + case TYPE_U16: + return xstrdup("uint16_t"); + case TYPE_I32: + return xstrdup("int32_t"); + case TYPE_U32: + return xstrdup("uint32_t"); + case TYPE_I64: + return xstrdup("int64_t"); + case TYPE_U64: + return xstrdup("uint64_t"); + case TYPE_F32: + return xstrdup("float"); + case TYPE_F64: + return xstrdup("double"); + case TYPE_USIZE: + return xstrdup("size_t"); + case TYPE_ISIZE: + return xstrdup("ptrdiff_t"); + case TYPE_BYTE: + return xstrdup("uint8_t"); + case TYPE_I128: + return xstrdup("__int128"); + case TYPE_U128: + return xstrdup("unsigned __int128"); + case TYPE_RUNE: + return xstrdup("int32_t"); + case TYPE_UINT: + return xstrdup("unsigned int"); + case TYPE_INT: + return xstrdup("int"); + case TYPE_FLOAT: + return xstrdup("float"); + + case TYPE_POINTER: + { + char *inner = type_to_string(t->inner); + if (t->is_restrict) + { + char *res = xmalloc(strlen(inner) + 16); + sprintf(res, "%s* __restrict", inner); + return res; + } + else + { + char *res = xmalloc(strlen(inner) + 2); + sprintf(res, "%s*", inner); + return res; + } + } + + case TYPE_ARRAY: + { + char *inner = type_to_string(t->inner); + + if (t->array_size > 0) + { + char *res = xmalloc(strlen(inner) + 20); + sprintf(res, "%s[%d]", inner, t->array_size); + return res; + } + + char *res = xmalloc(strlen(inner) + 7); + sprintf(res, "Slice_%s", inner); + return res; + } + + case TYPE_FUNCTION: + if (t->inner) + { + free(type_to_string(t->inner)); + } + + return xstrdup("z_closure_T"); + + case TYPE_STRUCT: + case TYPE_GENERIC: + { + if (t->arg_count > 0) + { + char *base = t->name; + char *arg = type_to_string(t->args[0]); + char *clean_arg = sanitize_mangled_name(arg); + + char *res = xmalloc(strlen(base) + strlen(clean_arg) + 2); + sprintf(res, "%s_%s", base, clean_arg); + + free(arg); + free(clean_arg); + return res; + } + return xstrdup(t->name); + } + + default: + return xstrdup("unknown"); + } +} diff --git a/src/ast/ast.h b/src/ast/ast.h new file mode 100644 index 0000000..67dc2f3 --- /dev/null +++ b/src/ast/ast.h @@ -0,0 +1,543 @@ + +#ifndef AST_H +#define AST_H + +#include <stdlib.h> +#include "zprep.h" + +// Forward declarations. +struct ASTNode; +typedef struct ASTNode ASTNode; + +// ** Formal Type System ** +// Used for Generics, Type Inference, and robust pointer handling. +typedef enum +{ + TYPE_VOID, + TYPE_BOOL, + TYPE_CHAR, + TYPE_STRING, + TYPE_U0, + TYPE_I8, + TYPE_U8, + TYPE_I16, + TYPE_U16, + TYPE_I32, + TYPE_U32, + TYPE_I64, + TYPE_U64, + TYPE_I128, + TYPE_U128, + TYPE_F32, + TYPE_F64, + TYPE_INT, + TYPE_FLOAT, + TYPE_USIZE, + TYPE_ISIZE, + TYPE_BYTE, + TYPE_RUNE, + TYPE_UINT, + TYPE_STRUCT, + TYPE_ENUM, + TYPE_POINTER, + TYPE_ARRAY, + TYPE_FUNCTION, + TYPE_GENERIC, + TYPE_UNKNOWN +} TypeKind; + +typedef struct Type +{ + TypeKind kind; + char *name; // For STRUCT, GENERIC, ENUM. + struct Type *inner; // For POINTER, ARRAY. + struct Type **args; // For GENERIC args. + int arg_count; + int is_const; + int array_size; // For fixed-size arrays [T; N]. + int is_varargs; // For function types (...). + int is_restrict; // For restrict pointers. + int has_drop; // For RAII: does this type implement Drop? +} Type; + +// ** AST Node Types ** +typedef enum +{ + NODE_ROOT, + NODE_FUNCTION, + NODE_BLOCK, + NODE_RETURN, + NODE_VAR_DECL, + NODE_CONST, + NODE_TYPE_ALIAS, + NODE_IF, + NODE_WHILE, + NODE_FOR, + NODE_FOR_RANGE, + NODE_LOOP, + NODE_REPEAT, + NODE_UNLESS, + NODE_GUARD, + NODE_BREAK, + NODE_CONTINUE, + NODE_MATCH, + NODE_MATCH_CASE, + NODE_EXPR_BINARY, + NODE_EXPR_UNARY, + NODE_EXPR_LITERAL, + NODE_EXPR_VAR, + NODE_EXPR_CALL, + NODE_EXPR_MEMBER, + NODE_EXPR_INDEX, + NODE_EXPR_CAST, + NODE_EXPR_SIZEOF, + NODE_EXPR_STRUCT_INIT, + NODE_EXPR_ARRAY_LITERAL, + NODE_EXPR_SLICE, + NODE_STRUCT, + NODE_FIELD, + NODE_ENUM, + NODE_ENUM_VARIANT, + NODE_TRAIT, + NODE_IMPL, + NODE_IMPL_TRAIT, + NODE_INCLUDE, + NODE_RAW_STMT, + NODE_TEST, + NODE_ASSERT, + NODE_DEFER, + NODE_DESTRUCT_VAR, + NODE_TERNARY, + NODE_ASM, + NODE_LAMBDA, + NODE_PLUGIN, + NODE_GOTO, + NODE_LABEL, + NODE_DO_WHILE, + NODE_TYPEOF, + NODE_TRY, + NODE_REFLECTION, + NODE_AWAIT, + NODE_REPL_PRINT +} NodeType; + +// ** AST Node Structure ** +struct ASTNode +{ + NodeType type; + ASTNode *next; + 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). + 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. + + union + { + struct + { + ASTNode *children; + } root; + + struct + { + char *name; + char *args; // Legacy string args. + char *ret_type; // Legacy string return type. + ASTNode *body; + Type **arg_types; + char **defaults; + char **param_names; // Explicit parameter names. + int arg_count; + Type *ret_type_info; + int is_varargs; + int is_inline; + int must_use; // @must_use: warn if return value is discarded. + // GCC attributes + int noinline; // @noinline + int constructor; // @constructor + int destructor; // @destructor + int unused; // @unused + int weak; // @weak + int is_export; // @export (visibility default). + int cold; // @cold + int hot; // @hot + int noreturn; // @noreturn + int pure; // @pure + char *section; // @section("name") + int is_async; // async function + int is_comptime; // @comptime function + } func; + + struct + { + ASTNode *statements; + } block; + + struct + { + ASTNode *value; + } ret; + + struct + { + char *name; + char *type_str; + ASTNode *init_expr; + Type *type_info; + int is_autofree; + int is_mutable; + int is_static; + } var_decl; + + struct + { + char *name; + Type *payload; + int tag_id; + } variant; + + struct + { + char *name; + ASTNode *variants; + int is_template; + char *generic_param; + } enm; + + struct + { + char *alias; + char *original_type; + } type_alias; + + struct + { + ASTNode *condition; + ASTNode *then_body; + ASTNode *else_body; + } if_stmt; + + struct + { + ASTNode *condition; + ASTNode *body; + char *loop_label; + } while_stmt; + + struct + { + ASTNode *init; + ASTNode *condition; + ASTNode *step; + ASTNode *body; + char *loop_label; + } for_stmt; + + struct + { + char *var_name; + char *start; + char *end; + char *step; + ASTNode *body; + } for_range; + + struct + { + ASTNode *body; + char *loop_label; + } loop_stmt; + + struct + { + char *count; + ASTNode *body; + } repeat_stmt; + + struct + { + ASTNode *condition; + ASTNode *body; + } unless_stmt; + + struct + { + ASTNode *condition; + ASTNode *body; + } guard_stmt; + + struct + { + ASTNode *condition; + ASTNode *body; + char *loop_label; + } do_while_stmt; + + struct + { + ASTNode *expr; + ASTNode *cases; + } match_stmt; + + struct + { + char *pattern; + char *binding_name; + int is_destructuring; + ASTNode *guard; + ASTNode *body; + int is_default; + } match_case; + + struct + { + char *op; + ASTNode *left; + ASTNode *right; + } binary; + + struct + { + char *op; + ASTNode *operand; + } unary; + + struct + { + int type_kind; + int int_val; + double float_val; + char *string_val; + } literal; + + struct + { + char *name; + char *suggestion; + } var_ref; + + struct + { + ASTNode *callee; + ASTNode *args; + char **arg_names; + int arg_count; + } call; + + struct + { + ASTNode *target; + char *field; + int is_pointer_access; + } member; + + struct + { + ASTNode *array; + ASTNode *index; + } index; + + struct + { + ASTNode *array; + ASTNode *start; + ASTNode *end; + } slice; + + struct + { + char *target_type; + ASTNode *expr; + } cast; + + struct + { + char *struct_name; + ASTNode *fields; + } struct_init; + + struct + { + ASTNode *elements; + int count; + } array_literal; + + struct + { + char *name; + ASTNode *fields; + int is_template; + char *generic_param; + char *parent; + int is_union; + int is_packed; // @packed attribute. + int align; // @align(N) attribute, 0 = default. + } strct; + + struct + { + char *name; + char *type; + int bit_width; + } field; + + struct + { + char *name; + ASTNode *methods; + } trait; + + struct + { + char *struct_name; + ASTNode *methods; + } impl; + + struct + { + char *trait_name; + char *target_type; + ASTNode *methods; + } impl_trait; + + struct + { + char *path; + int is_system; + } include; + + struct + { + char *content; + } raw_stmt; + + struct + { + char *name; + ASTNode *body; + } test_stmt; + + struct + { + ASTNode *condition; + char *message; + } assert_stmt; + + struct + { + ASTNode *stmt; + } defer_stmt; + + struct + { + char *plugin_name; + char *body; + } plugin_stmt; + + struct + { + char **names; + int count; + ASTNode *init_expr; + int is_struct_destruct; + char *struct_name; // "Point" (or NULL if unchecked/inferred). + char **field_names; // NULL if same as 'names', otherwise mapped. + int is_guard; + char *guard_variant; // "Some", "Ok". + ASTNode *else_block; + } destruct; + + struct + { + ASTNode *cond; + ASTNode *true_expr; + ASTNode *false_expr; + } ternary; + + struct + { + char *code; + int is_volatile; + char **outputs; + char **output_modes; + char **inputs; + char **clobbers; + int num_outputs; + int num_inputs; + int num_clobbers; + } asm_stmt; + + struct + { + char **param_names; + char **param_types; + char *return_type; + ASTNode *body; + int num_params; + int lambda_id; + int is_expression; + char **captured_vars; + char **captured_types; + int num_captures; + } lambda; + + struct + { + char *target_type; + ASTNode *expr; + } size_of; + + struct + { + char *label_name; + ASTNode *goto_expr; + } goto_stmt; + + struct + { + char *label_name; + } label_stmt; + + struct + { + char *target_label; + } break_stmt; + + struct + { + char *target_label; + } continue_stmt; + + struct + { + ASTNode *expr; + } try_stmt; + + struct + { + int kind; // 0=type_name, 1=fields. + Type *target_type; + } reflection; + + struct + { + ASTNode *expr; + } repl_print; + }; +}; + +// ** Functions ** +ASTNode *ast_create(NodeType type); +void ast_free(ASTNode *node); + +Type *type_new(TypeKind kind); +Type *type_new_ptr(Type *inner); +int type_eq(Type *a, Type *b); +char *type_to_string(Type *t); + +#endif |
