aboutsummaryrefslogtreecommitdiff
path: root/include
diff options
context:
space:
mode:
authorKimplul <kimi.h.kuparinen@gmail.com>2025-05-07 21:22:38 +0300
committerKimplul <kimi.h.kuparinen@gmail.com>2025-05-07 21:22:38 +0300
commit0e0c41af58a0f4ec5a39ce77822de71e5523fcba (patch)
tree4a02b2f93e61411cbfc6084b0855dba51b326cd9 /include
parent1fadcec6d7b26d34edf3b5b3a293deea0edb4139 (diff)
downloadfwd-0e0c41af58a0f4ec5a39ce77822de71e5523fcba.tar.gz
fwd-0e0c41af58a0f4ec5a39ce77822de71e5523fcba.zip
implement enough type analysis for vector examplegnc
+ 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?)
Diffstat (limited to 'include')
-rw-r--r--include/fwd/ast.h163
-rw-r--r--include/fwd/debug.h5
-rw-r--r--include/fwd/mod.h4
-rw-r--r--include/fwd/rewrite.h9
-rw-r--r--include/fwd/scope.h7
5 files changed, 159 insertions, 29 deletions
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 <fwd/ast.h>
+
+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 */