From 0e0c41af58a0f4ec5a39ce77822de71e5523fcba Mon Sep 17 00:00:00 2001 From: Kimplul Date: Wed, 7 May 2025 21:22:38 +0300 Subject: implement enough type analysis for vector example + Big commit, scary + Some details still a bit up in the air, mainly about move checking structure member access ('register' types are freely copied I guess, same as in rust? How about user types?) --- include/fwd/ast.h | 163 ++++++++++++++++++++++++++++++++++++++++++-------- include/fwd/debug.h | 5 +- include/fwd/mod.h | 4 ++ include/fwd/rewrite.h | 9 +++ include/fwd/scope.h | 7 ++- 5 files changed, 159 insertions(+), 29 deletions(-) create mode 100644 include/fwd/rewrite.h (limited to 'include') diff --git a/include/fwd/ast.h b/include/fwd/ast.h index 69f7bf1..044a27e 100644 --- a/include/fwd/ast.h +++ b/include/fwd/ast.h @@ -32,12 +32,46 @@ struct src_loc { struct ast; enum type_kind { - TYPE_ID = 1, TYPE_CONSTRUCT, TYPE_REF, TYPE_PTR, TYPE_CLOSURE, - TYPE_PURE_CLOSURE, TYPE_FUNC_PTR, TYPE_VOID, + TYPE_ID = 1, TYPE_REF, TYPE_PTR, TYPE_ARR, TYPE_CLOSURE, + TYPE_PURE_CLOSURE, TYPE_FUNC_PTR, TYPE_VOID, TYPE_NIL, TYPE_I8, TYPE_I16, TYPE_I32, TYPE_I64, TYPE_U8, TYPE_U16, TYPE_U32, TYPE_U64 }; +static inline bool is_int_type(enum type_kind k) +{ + switch (k) { + case TYPE_I8: + case TYPE_I16: + case TYPE_I32: + case TYPE_I64: + case TYPE_U8: + case TYPE_U16: + case TYPE_U32: + case TYPE_U64: + return true; + + default: + return false; + } + + return false; +} + +static inline bool is_ptr_type(enum type_kind k) +{ + switch (k) { + case TYPE_PTR: + case TYPE_FUNC_PTR: + return true; + + default: + return false; + } + + return false; +} + struct type { enum type_kind k; @@ -73,6 +107,8 @@ enum ast_kind { /** If statement */ AST_IF, /** Nil check */ + AST_NIL_CHECK, + /** Nil */ AST_NIL, /** Call procedure. */ AST_CALL, @@ -124,12 +160,29 @@ enum ast_kind { AST_EQ, /** Negation, \c - */ AST_NEG, + /** Bitwise negation, \c ~ */ + AST_BNEG, /** Logical negation, \c ! */ AST_LNOT, /** Bitwise negation, \c ~ */ AST_NOT, /** Reference (note, not addrof!) */ AST_REF, + /** Sizeof */ + AST_SIZEOF, + AST_AS, + AST_ARR, + AST_ASSIGN, + AST_CONSTRUCTION, + AST_CONSTRUCT, + AST_SELF, + AST_FORGET, + AST_PASTE, + AST_IMPLEMENTS, + AST_TEMPLATE, + AST_INSTANCE, + AST_SUPERTEMPLATE, + AST_INSTANCE_CONT, /** Dereferencing. * @todo should references and pointers both use this? */ @@ -270,11 +323,14 @@ static inline bool is_const(struct ast *x) static inline bool is_lvalue(struct ast *node) { switch (node->k) { + case AST_ARR: + case AST_DEREF: + case AST_DOT: case AST_ID: - /** @todo others */ return true; - default: return false; + default: + return false; } return false; @@ -295,13 +351,8 @@ static inline bool is_trivially_copyable(struct type *type) case TYPE_PTR: case TYPE_FUNC_PTR: case TYPE_PURE_CLOSURE: - /** @todo primitive types */ return true; - case TYPE_ID: - /* very special, bad bad bad */ - return strcmp(type->id, "int") == 0; - default: return false; } @@ -318,11 +369,11 @@ static inline bool is_trivially_copyable(struct type *type) #define gen_str(k, s, loc) gen_ast(k, NULL, NULL, NULL, NULL, NULL, s, -1, 0., \ loc) - #define gen4(k, a, b, c, d, loc) gen_ast(k, a, b, c, d, NULL, NULL, -1, 0., loc) #define gen3(k, a, b, c, loc) gen4(k, a, b, c, NULL, loc) #define gen2(k, a, b, loc) gen3(k, a, b, NULL, loc) #define gen1(k, a, loc) gen2(k, a, NULL, loc) +#define gen0(k, loc) gen1(k, NULL, loc) /* kind of hacky but I guess it works, and allows us to check that the type is @@ -340,17 +391,16 @@ static inline bool is_trivially_copyable(struct type *type) #define tgen_void(loc) \ tgen_type(TYPE_VOID, NULL, NULL, loc) -#define tgen_err(loc) \ - tgen_type(TYPE_ERR, NULL, NULL, loc) - #define tid_str(x) return_id(x, TYPE_ID) #define tgen_id(id, loc) \ tgen_type(TYPE_ID, NULL, id, loc) -#define tconstruct_id(x) return_id(x, TYPE_CONSTRUCT) -#define tconstruct_args(x) return_t0(x, TYPE_CONSTRUCT) -#define tgen_construct(id, args, loc) \ - tgen_type(TYPE_CONSTRUCT, args, id, loc) +#define tgen_nil(loc) \ + tgen_type(TYPE_NIL, NULL, NULL, loc) + +#define tarr_base(x) return_t0(x, TYPE_ARR) +#define tgen_arr(base, len, loc) \ + tgen_type(TYPE_ARR, base, len, loc) #define tptr_base(x) return_t0(x, TYPE_PTR) #define tgen_ptr(base, loc) \ @@ -387,6 +437,60 @@ static inline bool is_trivially_copyable(struct type *type) #define gen_comparison(op, left, right, loc) \ gen2(op, left, right, loc) +#define construction_id(x) return_s(x, AST_CONSTRUCTION) +#define construction_expr(x) return_a0(x, AST_CONSTRUCTION) +#define gen_construction(id, expr, loc) \ + gen_str1(AST_CONSTRUCTION, id, expr, loc) + +#define construct_id(x) return_s(x, AST_CONSTRUCT) +#define construct_members(x) return_a0(x, AST_CONSTRUCT) +#define gen_construct(id, members, loc) \ + gen_str1(AST_CONSTRUCT, id, members, loc) + +#define gen_paste(l, r, loc) \ + gen2(AST_PASTE, l, r, loc) + +#define forget_id(x) return_s(x, AST_FORGET) +#define gen_forget(id, loc) \ + gen_str(AST_FORGET, id, loc) + +#define gen_implements(id, loc) \ + gen_str(AST_IMPLEMENTS, id, loc) + +#define template_type_params(x) return_a0(x, AST_TEMPLATE) +#define template_body(x) return_a2(x, AST_TEMPLATE) +#define gen_template(id, types, params, body, loc) \ + gen_str3(AST_TEMPLATE, id, types, params, body, loc) + +#define gen_supertemplate(id, types, params, inst, body, loc) \ + gen_ast(AST_SUPERTEMPLATE, types, params, inst, body, NULL, id, 0, 0., loc) + +#define gen_self(loc) \ + gen0(AST_SELF, loc) + +#define instance_id(x) return_s(x, AST_INSTANCE) +#define instance_templ(x) return_a1(x, AST_INSTANCE) +#define instance_type_args(x) return_t2(x, AST_INSTANCE) +#define gen_instance(name, templ, types, exprs, loc) \ + gen_ast(AST_INSTANCE, exprs, templ, NULL, NULL, types, name, 0, 0., loc) + +#define gen_instance_cont(name, body, loc) \ + gen_str1(AST_INSTANCE_CONT, name, body, loc) + +#define sizeof_type(x) return_t2(x, AST_SIZEOF) +#define gen_sizeof(type, loc) \ + gen_ast(AST_SIZEOF, NULL, NULL, NULL, NULL, type, NULL, 0, 0., loc) + +#define assign_expr(x) return_a1(x, AST_ASSIGN) +#define assign_target(x) return_a0(x, AST_ASSIGN) +#define gen_assign(l, r, loc) \ + gen2(AST_ASSIGN, l, r, loc) + +#define arr_base(x) return_a0(x, AST_ARR) +#define arr_idx(x) return_a1(x, AST_ARR) +#define gen_arr(base, idx, loc) \ + gen2(AST_ARR, base, idx, loc) + #define unop_expr(x) ({assert(is_unop(x)); x->a0;}) #define gen_unop(op, expr, loc) \ gen1(op, expr, loc) @@ -427,10 +531,9 @@ static inline bool is_trivially_copyable(struct type *type) gen_str(AST_TRAIT_DEF, id, loc) #define struct_id(x) return_s(x, AST_STRUCT_DEF) -#define struct_params(x) return_a0(x, AST_STRUCT_DEF) -#define struct_body(x) return_a1(x, AST_STRUCT_DEF) -#define gen_struct(id, params, body, loc) \ - gen_str2(AST_STRUCT_DEF, id, params, body, loc) +#define struct_body(x) return_a0(x, AST_STRUCT_DEF) +#define gen_struct(id, body, loc) \ + gen_str1(AST_STRUCT_DEF, id, body, loc) #define import_file(x) return_s(x, AST_IMPORT) #define gen_import(file, loc) \ @@ -479,11 +582,19 @@ static inline bool is_trivially_copyable(struct type *type) #define gen_if(cond, body, els, loc) \ gen3(AST_IF, cond, body, els, loc) -#define nil_var(x) return_s(x, AST_NIL) -#define nil_body(x) return_a1(x, AST_NIL) -#define nil_ref(x) return_a2(x, AST_NIL) -#define gen_nil(var, body, ref, loc) \ - gen_ast(AST_NIL, NULL, body, ref, NULL, NULL, var, 0, 0., loc) +#define nil_check_expr(x) return_a0(x, AST_NIL_CHECK) +#define nil_check_body(x) return_a1(x, AST_NIL_CHECK) +#define nil_check_ref(x) return_a2(x, AST_NIL_CHECK) +#define gen_nil_check(expr, body, ref, loc) \ + gen3(AST_NIL_CHECK, expr, body, ref, loc) + +#define gen_nil(loc) \ + gen0(AST_NIL, loc) + +#define as_expr(x) return_a0(x, AST_AS) +#define as_type(x) return_t2(x, AST_AS) +#define gen_as(expr, type, loc) \ + gen_ast(AST_AS, expr, NULL, NULL, NULL, type, NULL, 0, 0., loc) #define own_id(x) return_s(x, AST_OWN) #define own_body(x) return_a1(x, AST_OWN) diff --git a/include/fwd/debug.h b/include/fwd/debug.h index c3dce63..ac4dfdf 100644 --- a/include/fwd/debug.h +++ b/include/fwd/debug.h @@ -96,6 +96,9 @@ void semantic_warn(struct scope *scope, struct ast *node, const char *fmt, ...); void semantic_error(struct scope *scope, struct ast *node, const char *fmt, ...); +void type_error(struct scope *scope, struct type *type, const char *fmt, + ...); + void loc_error(struct scope *scope, struct src_loc loc, const char *fmt, ...); /** @@ -141,6 +144,6 @@ void type_mismatch(struct scope *scope, struct ast *node, void move_error(struct ast *new_use, struct ast *prev_use); void reference_error(struct ast *new_use, struct ast *prev_use); -const char *type_str(struct type *t); +char *type_str(struct type *t); #endif /* FWD_DEBUG_H */ diff --git a/include/fwd/mod.h b/include/fwd/mod.h index 6031c92..51aa9c4 100644 --- a/include/fwd/mod.h +++ b/include/fwd/mod.h @@ -61,6 +61,10 @@ static inline void *fwd_arg(fwd_extern_args_t args, size_t idx, fwd_type_t id) #define FWD_ARG_T(args, idx, type) \ FWD_ARG(args, idx, type, FWD_T(type)) +/* unimplemented as of yet */ +#define FWD_RET(id, x) \ + abort() + static inline fwd_type_t fwd_t_signed(size_t s) { switch (s) { diff --git a/include/fwd/rewrite.h b/include/fwd/rewrite.h new file mode 100644 index 0000000..d9c4129 --- /dev/null +++ b/include/fwd/rewrite.h @@ -0,0 +1,9 @@ +#ifndef FWD_REWRITE_H +#define FWD_REWRITE_H + +#include + +int rewrite_types(struct ast *node, char *orig, char *new); +int rewrite_holes(struct ast *node, char *new); + +#endif /* FWD_REWRITE_H */ diff --git a/include/fwd/scope.h b/include/fwd/scope.h index ab268bc..c3bafa0 100644 --- a/include/fwd/scope.h +++ b/include/fwd/scope.h @@ -55,6 +55,7 @@ struct scope { /** List of child scopes. */ struct scope *children; + struct visible templates; struct visible symbols; struct visible traits; struct visible types; @@ -113,13 +114,11 @@ int scope_add_scratch(struct scope *scope, struct ast *scratch); */ void scope_add_scope(struct scope *parent, struct scope *child); - int scope_add_symbol(struct scope *scope, struct ast *symbol); struct ast *scope_find_symbol(struct scope *scope, char *id); struct ast *file_scope_find_symbol(struct scope *scope, char *id); int scope_add_type(struct scope *scope, struct ast *type); -int scope_add_chain(struct scope *scope, struct ast *type); struct ast *scope_find_type(struct scope *scope, char *id); struct ast *file_scope_find_type(struct scope *scope, char *id); @@ -127,4 +126,8 @@ int scope_add_trait(struct scope *scope, struct ast *trait); struct ast *scope_find_trait(struct scope *scope, char *id); struct ast *file_scope_find_trait(struct scope *scope, char *id); +int scope_add_template(struct scope *scope, struct ast *trait); +struct ast *scope_find_template(struct scope *scope, char *id); +struct ast *file_scope_find_template(struct scope *scope, char *id); + #endif /* SCOPE_H */ -- cgit v1.2.3