summaryrefslogtreecommitdiff
path: root/src/ast
diff options
context:
space:
mode:
authorZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-11 15:11:00 +0000
committerZuhaitz Méndez Fernández de Aránguiz <zuhaitz@debian>2026-01-11 15:11:00 +0000
commit55247a3f12a9eee7ba3fd7ca6d8fcea7a82c20f3 (patch)
treea2a71e2eb8ca0b2c483518c1902d89d18709c9ab /src/ast
parent2e7abed7cfe84a2c0df371cde35f8f68cfdca16c (diff)
Added src/ folder. Now I will add the rest.
Diffstat (limited to 'src/ast')
-rw-r--r--src/ast/ast.c283
-rw-r--r--src/ast/ast.h543
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