aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--.gitignore1
-rw-r--r--include/cu/actualize.h33
-rw-r--r--include/cu/ast.h579
-rw-r--r--include/cu/compiler.h11
-rw-r--r--include/cu/debug.h56
-rw-r--r--include/cu/imports.h12
-rw-r--r--include/cu/parser.h44
-rw-r--r--include/cu/path.h10
-rw-r--r--include/cu/res.h57
-rw-r--r--include/cu/scope.h169
-rw-r--r--include/cu/string.h28
11 files changed, 1000 insertions, 0 deletions
diff --git a/.gitignore b/.gitignore
index 69334a2..daafc0e 100644
--- a/.gitignore
+++ b/.gitignore
@@ -2,3 +2,4 @@ deps.mk
docs/output
build
cu
+!include/cu
diff --git a/include/cu/actualize.h b/include/cu/actualize.h
new file mode 100644
index 0000000..ea736ac
--- /dev/null
+++ b/include/cu/actualize.h
@@ -0,0 +1,33 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+
+#ifndef ANALYZE_H
+#define ANALYZE_H
+
+#include <assert.h>
+
+#include "ast.h"
+#include "scope.h"
+
+int types_match(struct ast_node *a, struct ast_node *b);
+
+/* these three might be better off in some ast_utils.c or something */
+void replace_type(struct ast_node *type,
+ struct ast_node *from, struct ast_node *to);
+
+void replace_param_types(struct ast_node *param,
+ struct ast_node *param_type,
+ struct ast_node *arg_type);
+
+void init_template_type(struct ast_node *type, struct ast_node *param_type,
+ struct ast_node *arg_type);
+void init_template_types(struct ast_node *param, struct ast_node *param_type,
+ struct ast_node *arg_type);
+
+struct ast_node *extract_template(struct ast_node *type);
+struct ast_node *extract_typeof(struct ast_node *type);
+
+int analyze_root(struct scope *scope, struct ast_node *tree);
+int actualize_main(struct scope *scope);
+int actualize_temp_type(struct scope *scope, struct ast_node *type);
+
+#endif /* ANALYZE_H */
diff --git a/include/cu/ast.h b/include/cu/ast.h
new file mode 100644
index 0000000..f9e8492
--- /dev/null
+++ b/include/cu/ast.h
@@ -0,0 +1,579 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+
+#ifndef AST_H
+#define AST_H
+
+enum ast_binops {
+ AST_ADD,
+ AST_SUB,
+ AST_MUL,
+ AST_DIV,
+ AST_REM,
+ AST_XOR,
+ AST_POW,
+ AST_AND,
+ AST_LAND,
+ AST_OR,
+ AST_LOR,
+ AST_LSHIFT,
+ AST_RSHIFT,
+ AST_ASSIGN_ADD,
+ AST_ASSIGN_SUB,
+ AST_ASSIGN_MUL,
+ AST_ASSIGN_DIV,
+ AST_ASSIGN_REM,
+ AST_ASSIGN_AND,
+ AST_ASSIGN_OR,
+ AST_ASSIGN_XOR,
+ AST_ASSIGN_LSHIFT,
+ AST_ASSIGN_RSHIFT,
+ AST_LT,
+ AST_GT,
+ AST_LE,
+ AST_GE,
+ AST_NE,
+ AST_EQ,
+};
+
+enum ast_unops {
+ AST_NEG,
+ AST_LNOT,
+ AST_REF,
+ AST_DEREF,
+ AST_NOT
+};
+
+/* should this also have file name? Probably? */
+struct src_loc {
+ int first_line;
+ int last_line;
+ int first_col;
+ int last_col;
+};
+
+enum ast_node_type {
+ AST_BINOP = 1,
+ AST_UNOP,
+ AST_FETCH,
+ AST_INIT,
+ AST_ASSIGN,
+ AST_CALL,
+ AST_SIZEOF,
+ AST_CAST,
+ AST_DEFER,
+ AST_MACRO,
+ AST_LAST,
+ AST_PROC,
+ AST_GOTO,
+ AST_LABEL,
+ AST_VAR,
+ AST_LAMBDA,
+ AST_FOR,
+ AST_EMBED,
+ AST_DOT,
+ AST_WHILE,
+ AST_CTRL,
+ AST_RETURN,
+ AST_ALIAS,
+ AST_TEMPLATE,
+ AST_STRUCT,
+ AST_IF,
+ AST_TYPE,
+ AST_BLOCK,
+ AST_IMPORT,
+ AST_ENUM,
+ AST_UNION,
+ AST_VAL,
+ AST_SWITCH,
+ AST_CASE,
+ AST_CONST,
+ AST_ID,
+ AST_AS,
+ AST_EMPTY,
+};
+
+enum ast_ctrl_kind {
+ AST_CTRL_BREAK,
+ AST_CTRL_CONTINUE
+};
+
+enum ast_const_kind {
+ AST_CONST_INTEGER,
+ AST_CONST_STRING,
+ AST_CONST_FLOAT,
+};
+
+enum ast_type_kind {
+ AST_TYPE_ID,
+ AST_TYPE_ARR,
+ AST_TYPE_TYPEOF,
+ AST_TYPE_TEMPLATE,
+ AST_TYPE_ALIAS,
+ AST_TYPE_MEMBER,
+ AST_TYPE_POINTER,
+ AST_TYPE_UNION,
+ AST_TYPE_LAMBDA,
+ AST_TYPE_PROC,
+ AST_TYPE_STRUCT,
+ AST_TYPE_ENUM,
+ AST_TYPE_SIGN,
+};
+
+enum ast_typedef_kind {
+ AST_TYPEDEF_ALIAS,
+ AST_TYPEDEF_TEMPLATE,
+};
+
+enum ast_flag {
+ AST_FLAG_MUTABLE = (1 << 0),
+ AST_FLAG_CONST = (1 << 1),
+ AST_FLAG_EXTERN = (1 << 2),
+ AST_FLAG_VARIADIC = (1 << 3),
+ AST_FLAG_DELAYED = (1 << 4),
+ AST_FLAG_PUBLIC = (1 << 5),
+ /* Is untyped necessary? It's fairly easy to just look at the type of an
+ * expression... */
+ AST_FLAG_UNTYPED = (1 << 6),
+ AST_FLAG_FALLTHROUGH = (1 << 7),
+ AST_FLAG_UNHYGIENIC = (1 << 8),
+ AST_FLAG_ACTUAL = (1 << 9),
+ AST_FLAG_INIT = (1 << 10),
+ AST_FLAG_MEMBER = (1 << 11),
+ AST_FLAG_SHARED = (1 << 12),
+};
+
+struct ast_node;
+
+struct ast_if {
+ struct ast_node *cond;
+ struct ast_node *body;
+ struct ast_node *els;
+};
+
+struct ast_fetch {
+ struct ast_node *id;
+ struct ast_node *type;
+};
+
+struct ast_label {
+ struct ast_node *id;
+ struct ast_node *defers;
+};
+
+struct ast_goto {
+ struct ast_node *label;
+ struct ast_node *defers;
+};
+
+struct ast_alias {
+ struct ast_node *id;
+ struct ast_node *type;
+};
+
+struct template_implemented {
+ struct ast_node *type;
+ struct template_implemented *next;
+};
+
+/* should templates take decls or should it just be for structures? */
+struct ast_template {
+ struct ast_node *id;
+ struct ast_node *body;
+
+ struct template_implemented *impl_by;
+};
+
+struct ast_cast {
+ struct ast_node *expr;
+ struct ast_node *type;
+};
+
+struct ast_binop {
+ enum ast_binops op;
+ struct ast_node *left;
+ struct ast_node *right;
+};
+
+struct ast_unop {
+ enum ast_unops op;
+ struct ast_node *expr;
+};
+
+struct ast_call {
+ struct ast_node *id;
+ struct ast_node *args;
+};
+
+struct ast_defer {
+ struct ast_node *expr;
+};
+
+struct ast_macro {
+ struct ast_node *id;
+ struct ast_node *params;
+ struct ast_node *body;
+};
+
+struct ast_proc {
+ struct ast_node *id;
+ struct ast_node *sign;
+ struct ast_node *body;
+};
+
+struct ast_dot {
+ struct ast_node *expr;
+ struct ast_node *id;
+};
+
+struct ast_as {
+ struct ast_node *type;
+};
+
+struct ast_sizeof {
+ struct ast_node *expr;
+};
+
+struct ast_var {
+ struct ast_node *id;
+ struct ast_node *type;
+ struct ast_node *init;
+};
+
+struct ast_lambda {
+ struct ast_node *captures;
+ struct ast_node *sign;
+ struct ast_node *body;
+};
+
+struct ast_for {
+ struct ast_node *pre;
+ struct ast_node *cond;
+ struct ast_node *post;
+ struct ast_node *body;
+};
+
+struct ast_while {
+ struct ast_node *cond;
+ struct ast_node *body;
+};
+
+struct ast_ctrl {
+ enum ast_ctrl_kind kind;
+ struct ast_node *defers;
+};
+
+struct ast_return {
+ struct ast_node *expr;
+ struct ast_node *defers;
+};
+
+struct ast_type {
+ enum ast_type_kind kind;
+ struct ast_node *next;
+ union {
+ struct ast_node *id;
+
+ struct {
+ struct ast_node *size;
+ } arr;
+
+ struct {
+ struct ast_node *expr;
+ struct ast_node *actual;
+ } typeo;
+
+ struct {
+ struct ast_node *id;
+ struct ast_node *params;
+ struct ast_node *ret;
+ } proc;
+
+ struct {
+ struct ast_node *alias;
+ struct ast_node *actual;
+ } alias;
+
+ struct {
+ struct ast_node *id;
+ struct ast_node *expr;
+ } member;
+
+ struct {
+ struct ast_node *template;
+ struct ast_node *actual;
+ } template;
+
+ struct {
+ struct ast_node *params;
+ struct ast_node *ret;
+ } lambda;
+
+ struct {
+ struct ast_node *id;
+ struct ast_node *impls;
+ } struc;
+
+ struct {
+ struct ast_node *id;
+ struct ast_node *type;
+ } enu;
+
+ struct {
+ struct ast_node *id;
+ struct ast_node *impls;
+ } unio;
+
+ /* a signature can be either a procedure or a lambda, to be
+ * determined later. */
+ struct {
+ struct ast_node *params;
+ struct ast_node *ret;
+ } sign;
+
+ struct {
+ struct ast_node *id;
+ struct ast_node *types;
+ } impl;
+ };
+};
+
+struct ast_block {
+ struct ast_node *body;
+ struct ast_node *defers;
+};
+
+struct ast_import {
+ const char *file;
+};
+
+struct ast_embed {
+ const char *file;
+};
+
+struct ast_paste {
+ struct ast_node *id1;
+ struct ast_node *id2;
+};
+
+struct ast_enum {
+ struct ast_node *id;
+ struct ast_node *type;
+ struct ast_node *body;
+};
+
+struct ast_struct {
+ struct ast_node *id;
+ struct ast_node *generics;
+ struct ast_node *body;
+};
+
+struct ast_union {
+ struct ast_node *id;
+ struct ast_node *generics;
+ struct ast_node *body;
+};
+
+struct ast_val {
+ struct ast_node *id;
+ struct ast_node *val;
+};
+
+struct ast_switch {
+ struct ast_node *cond;
+ struct ast_node *cases;
+};
+
+struct ast_case {
+ struct ast_node *cond;
+ struct ast_node *body;
+};
+
+struct ast_const {
+ enum ast_const_kind kind;
+ union {
+ long long integer;
+ const char *str;
+ double dbl;
+ };
+};
+
+struct ast_init {
+ struct ast_node *body;
+};
+
+struct ast_assign {
+ struct ast_node *to;
+ struct ast_node *from;
+};
+
+struct ast_id {
+ const char *id;
+};
+
+struct ast_empty {
+};
+
+struct ast_node {
+ enum ast_node_type node_type;
+ enum ast_flag flags;
+ struct ast_node *next;
+
+ struct src_loc loc;
+
+ /* scope ast node belongs to */
+ struct scope *scope;
+ /* type of ast node */
+ struct ast_node *type;
+
+ union {
+ struct ast_binop _binop;
+ struct ast_unop _unop;
+ struct ast_call _call;
+ struct ast_cast _cast;
+ struct ast_macro _macro;
+ struct ast_proc _proc;
+ struct ast_goto _goto;
+ struct ast_label _label;
+ struct ast_var _var;
+ struct ast_lambda _lambda;
+ struct ast_if _if;
+ struct ast_for _for;
+ struct ast_while _while;
+ struct ast_ctrl _ctrl;
+ struct ast_defer _defer;
+ struct ast_type _type;
+ struct ast_dot _dot;
+ struct ast_block _block;
+ struct ast_import _import;
+ struct ast_embed _embed;
+ struct ast_return _return;
+ struct ast_switch _switch;
+ struct ast_paste _paste;
+ struct ast_alias _alias;
+ struct ast_template _template;
+ struct ast_enum _enum;
+ struct ast_struct _struct;
+ struct ast_union _union;
+ struct ast_val _val;
+ struct ast_case _case;
+ struct ast_const _const;
+ struct ast_init _init;
+ struct ast_assign _assign;
+ struct ast_id _id;
+ struct ast_as _as;
+ struct ast_sizeof _sizeof;
+ struct ast_fetch _fetch;
+ struct ast_empty _empty;
+ };
+};
+
+struct ast_node *gen_binop(enum ast_binops op,
+ struct ast_node *left, struct ast_node *right);
+
+struct ast_node *gen_unop(enum ast_unops op, struct ast_node *expr);
+
+struct ast_node *gen_call(struct ast_node *id, struct ast_node *args);
+
+struct ast_node *gen_id(const char *id);
+
+struct ast_node *gen_int(long long integer);
+struct ast_node *gen_string(const char *str);
+struct ast_node *gen_float(double dbl);
+
+struct ast_node *gen_assign(struct ast_node *to, struct ast_node *from);
+struct ast_node *gen_init(struct ast_node *body);
+
+struct ast_node *gen_while(struct ast_node *cond, struct ast_node *body);
+
+struct ast_node *gen_for(struct ast_node *pre, struct ast_node *cond,
+ struct ast_node *post, struct ast_node *body);
+
+struct ast_node *gen_return(struct ast_node *expr);
+
+struct ast_node *gen_ctrl(enum ast_ctrl_kind kind, struct src_loc loc);
+
+struct ast_node *gen_macro(struct ast_node *id, struct ast_node *params,
+ struct ast_node *body);
+
+struct ast_node *gen_if(struct ast_node *cond, struct ast_node *body,
+ struct ast_node *els);
+
+struct ast_node *gen_switch(struct ast_node *cond, struct ast_node *cases);
+
+struct ast_node *gen_case(struct ast_node *expr, struct ast_node *body);
+
+struct ast_node *gen_type(enum ast_type_kind kind, struct ast_node *id,
+ struct ast_node *decl, struct ast_node *rets);
+
+struct ast_node *gen_block(struct ast_node *body);
+
+struct ast_node *gen_var(struct ast_node *id, struct ast_node *type,
+ struct ast_node *init);
+
+struct ast_node *gen_lambda(struct ast_node *captures,
+ struct ast_node *type, struct ast_node * body);
+
+struct ast_node *gen_proc(struct ast_node *id, struct ast_node *type,
+ struct ast_node *body);
+
+struct ast_node *gen_dot(struct ast_node *expr, struct ast_node *id);
+
+struct ast_node *gen_enum(struct ast_node *id, struct ast_node *type,
+ struct ast_node *body);
+
+struct ast_node *gen_val(struct ast_node *id, struct ast_node *val);
+
+struct ast_node *gen_alias(struct ast_node *id, struct ast_node *type);
+
+struct ast_node *gen_template(struct ast_node *id, struct ast_node *body);
+
+struct ast_node *gen_import(const char *file);
+
+struct ast_node *gen_cast(struct ast_node *expr, struct ast_node *type);
+
+struct ast_node *gen_embed(const char *file);
+
+struct ast_node *gen_goto(struct ast_node *label);
+
+struct ast_node *gen_label(struct ast_node *id);
+
+struct ast_node *gen_defer(struct ast_node *expr);
+
+struct ast_node *gen_as(struct ast_node *type);
+
+struct ast_node *gen_sizeof(struct ast_node *expr);
+
+struct ast_node *gen_struct(struct ast_node *id, struct ast_node *generics,
+ struct ast_node *body);
+
+struct ast_node *gen_union(struct ast_node *id, struct ast_node *generics,
+ struct ast_node *body);
+
+struct ast_node *gen_fetch(struct ast_node *id, struct ast_node *type);
+
+/* might have to come up with a better name for this */
+struct ast_node *gen_last();
+
+struct ast_node *gen_empty();
+
+struct ast_node *clone_ast_node(struct ast_node *node);
+int identical_ast_nodes(int exact, struct ast_node *left,
+ struct ast_node *right);
+
+void destroy_ast_node(struct ast_node *node);
+void destroy_ast_tree(struct ast_node *root);
+
+void dump_ast(int depth, struct ast_node *root);
+void ast_append(struct ast_node *list, struct ast_node *elem);
+void ast_set_flags(struct ast_node *node, enum ast_flag flags);
+void ast_clear_flags(struct ast_node *node, enum ast_flag flags);
+int ast_flags(struct ast_node *node, enum ast_flag flags);
+
+int ast_call_on(int (*call)(struct ast_node *node, void *data),
+ struct ast_node *node, void *data);
+
+size_t ast_list_len(struct ast_node *list);
+struct ast_node *ast_last_node(struct ast_node *node);
+struct ast_node *ast_block_last(struct ast_node *node);
+
+#endif /* AST_H */
diff --git a/include/cu/compiler.h b/include/cu/compiler.h
new file mode 100644
index 0000000..325c746
--- /dev/null
+++ b/include/cu/compiler.h
@@ -0,0 +1,11 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+
+#ifndef CT_COMPILER_H
+#define CT_COMPILER_H
+
+#include <cu/scope.h>
+
+int compile(const char *file);
+int process_file(struct scope **parent, int public, const char *file);
+
+#endif /* CT_COMPILER_H */
diff --git a/include/cu/debug.h b/include/cu/debug.h
new file mode 100644
index 0000000..3099b3c
--- /dev/null
+++ b/include/cu/debug.h
@@ -0,0 +1,56 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+
+#ifndef CT_DEBUG_H
+#define CT_DEBUG_H
+
+#include <stdio.h>
+
+#include <cu/ast.h>
+
+#if DEBUG
+#define debug(x, ...) \
+ do {fprintf(stderr, "debug: " x "\n",##__VA_ARGS__);} while(0)
+#else
+#define debug(x, ...)
+#endif
+
+#define error(x, ...) \
+ do {fprintf(stderr, "error: " x "\n",##__VA_ARGS__);} while(0)
+
+#define warn(x, ...) \
+ do {fprintf(stderr, "warn: " x "\n",##__VA_ARGS__);} while(0)
+
+#define info(x, ...) \
+ do {fprintf(stderr, "info: " x "\n",##__VA_ARGS__);} while(0)
+
+
+struct file_ctx {
+ const char *fname;
+ const char *fbuf;
+};
+
+char *type_str(struct ast_node *type);
+char *call_str(struct ast_node *call);
+void semantic_info(struct file_ctx ctx, struct ast_node *node, const char *fmt,
+ ...);
+void semantic_warn(struct file_ctx ctx, struct ast_node *node, const char *fmt,
+ ...);
+void semantic_error(struct file_ctx ctx, struct ast_node *node, const char *fmt,
+ ...);
+void internal_error(const char *fmt, ...);
+
+enum issue_level {
+ SRC_INFO,
+ SRC_WARN,
+ SRC_ERROR
+};
+
+struct src_issue {
+ enum issue_level level;
+ struct src_loc loc;
+ struct file_ctx fctx;
+ size_t offset;
+};
+
+void src_issue(struct src_issue issue, const char *err_msg, ...);
+#endif /* CT_DEBUG_H */
diff --git a/include/cu/imports.h b/include/cu/imports.h
new file mode 100644
index 0000000..1043cef
--- /dev/null
+++ b/include/cu/imports.h
@@ -0,0 +1,12 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+
+#ifndef CT_IMPORTS_H
+#define CT_IMPORTS_H
+
+#include <stdbool.h>
+
+void add_import_path(const char *dir);
+const char *find_import(const char *file);
+bool already_imported(const char *file);
+
+#endif /* CT_IMPORTS_H */
diff --git a/include/cu/parser.h b/include/cu/parser.h
new file mode 100644
index 0000000..dfc2b6a
--- /dev/null
+++ b/include/cu/parser.h
@@ -0,0 +1,44 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+
+#ifndef PARSER_H
+#define PARSER_H
+
+#include <stddef.h>
+#include <stdbool.h>
+#include <cu/ast.h>
+
+struct parser {
+ bool failed;
+ void *lexer;
+ size_t buf_offset;
+ const char *buf;
+ const char *fname;
+ size_t comment_nesting;
+ struct ast_node *tree;
+};
+
+#define YY_DECL int yylex(YYSTYPE *yylval, YYLTYPE *yylloc, \
+ yyscan_t yyscanner, struct parser *parser)
+
+#include <../gen/gen_parser.h>
+#ifndef FROM_LEXER
+#include <../gen/gen_lexer.h>
+#endif
+
+YY_DECL;
+
+struct parser *create_parser();
+void destroy_parser(struct parser *p);
+void parse(struct parser *p, const char *fname, const char *buf);
+int next_interesting_feature(YYSTYPE *yylval, YYLTYPE *yylloc,
+ void *scanner, struct parser *parser);
+
+struct src_loc to_src_loc(YYLTYPE *yylloc);
+
+void yyerror(YYLTYPE *yylloc, void *lexer, struct parser *parser,
+ const char *msg);
+
+long long match_escape(char c);
+const char *clone_string(const char *s);
+
+#endif /* PARSER_H */
diff --git a/include/cu/path.h b/include/cu/path.h
new file mode 100644
index 0000000..700f77f
--- /dev/null
+++ b/include/cu/path.h
@@ -0,0 +1,10 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+
+#ifndef CT_PATH
+#define CT_PATH
+
+char *cu_basename(const char *file);
+char *cu_dirname(const char *file);
+char *cu_cwdname();
+
+#endif /* CT_PATH */
diff --git a/include/cu/res.h b/include/cu/res.h
new file mode 100644
index 0000000..e1a1fc3
--- /dev/null
+++ b/include/cu/res.h
@@ -0,0 +1,57 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+
+/**
+ * @file res.h
+ * Simple resource manager header.
+ */
+
+#ifndef CT_RES_H
+#define CT_RES_H
+
+#include <stddef.h>
+
+/**
+ * Very simple resource manager.
+ * Keeps track of all allocations and frees them all at once.
+ */
+struct res {
+ /** Number of allocations. */
+ size_t n;
+ /** Maximum number of allocations. */
+ size_t max;
+ /** Pointer to array of pointers to allocations. */
+ void **p;
+};
+
+/**
+ * Create new resource manager.
+ *
+ * @return Pointer to resource manager.
+ */
+struct res *res_create();
+
+/**
+ * Resource manager wrapper around malloc().
+ *
+ * @param r Resource manager.
+ * @param size Size of allocation.
+ * @return Pointer to newly allocated area.
+ */
+void *res_alloc(struct res *r, size_t size);
+
+/**
+ * Add already alloced pointer to manager.
+ *
+ * @param r Resource manager.
+ * @param p Pointer to manage.
+ */
+void res_add(struct res *r, void *p);
+
+/**
+ * Destroy resource manager and free all associated allocations.
+ *
+ * @param r Resource manager to destroy.
+ */
+void res_destroy(struct res *r);
+
+#endif /* CT_RES_H */
diff --git a/include/cu/scope.h b/include/cu/scope.h
new file mode 100644
index 0000000..5a75427
--- /dev/null
+++ b/include/cu/scope.h
@@ -0,0 +1,169 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+
+#ifndef SCOPE_H
+#define SCOPE_H
+
+#include "ast.h"
+#include "debug.h"
+
+enum scope_flags {
+ SCOPE_PUBLIC = (1 << 0),
+ SCOPE_FILE = (1 << 1),
+};
+
+/* basic linked list for now, can probably be optimized into some kind of hash
+ * table later */
+struct visible {
+ struct ast_node *node;
+ struct scope *owner;
+ struct visible *next;
+};
+
+struct scratch {
+ struct ast_node *node;
+ struct scratch *next;
+};
+
+struct actual {
+ struct ast_node *node;
+ struct actual *next;
+};
+
+struct callable {
+ struct proc_node *root;
+ struct ast_node *id;
+ struct callable *next;
+};
+
+struct param_node {
+ struct ast_node *type;
+ struct proc_node *proc;
+ struct param_node *next;
+};
+
+struct proc_node {
+ struct param_node *primitives;
+
+ struct param_node *referential;
+ struct param_node *fallback;
+
+ struct ast_node *proc;
+};
+
+
+struct scope {
+ struct scope *parent;
+ enum scope_flags flags;
+ size_t number;
+
+ struct file_ctx fctx;
+
+ /* used by the parent to keep track of all its children */
+ struct scope *next;
+ struct scope *children;
+
+ /* list of actualized functions, shared between all scopes in the
+ * compilation unit */
+ struct actual *actuals;
+
+ /* for temp stuff */
+ struct scratch *scratch;
+
+ /* types */
+ /* TODO: add actualized types maybe? */
+ struct visible *enums;
+ struct visible *structs;
+ struct visible *aliases;
+ struct visible *builtins;
+ struct visible *templates;
+
+ /* basic variables */
+ struct visible *vars;
+ struct visible *macros;
+
+ /* collect procedures */
+ struct visible *procs;
+
+ /* callables */
+ struct callable *callable;
+};
+
+enum match_flags {
+ MATCH_GLOBAL = (1 << 0),
+ MATCH_CALL = (1 << 1),
+};
+
+struct scope *create_scope();
+struct actual *create_actuals();
+void destroy_actuals(struct actual *actuals);
+void destroy_visible(struct scope *scope, struct visible *visible);
+void destroy_scope(struct scope *scope);
+
+struct scope *create_temp_scope(struct scope *parent);
+
+int scope_add_defaults(struct scope *root);
+/* not sure if this should be public */
+void scope_destroy_defaults(struct scope *root);
+
+int scope_add_scratch(struct scope *scope, struct ast_node *scratch);
+
+void scope_set_flags(struct scope *scope, enum scope_flags flags);
+int scope_flags(struct scope *scope, enum scope_flags flags);
+
+void scope_add_scope(struct scope *parent, struct scope *child);
+
+int scope_add_actual(struct scope *scope, struct ast_node *node);
+/* sets a node's owner as scope, and as needed propagates references to public
+ * things up the file scope chain. */
+int scope_add_var(struct scope *scope, struct ast_node *var);
+int scope_add_type(struct scope *scope, struct ast_node *type);
+int scope_add_proc(struct scope *scope, struct ast_node *proc);
+int scope_add_macro(struct scope *scope, struct ast_node *macro);
+int scope_add_alias(struct scope *scope, struct ast_node *alias);
+int scope_add_template(struct scope *scope, struct ast_node *type_template);
+
+int scope_add_existing_var(struct scope *scope, struct visible *var);
+int scope_add_existing_proc(struct scope *scope, struct visible *proc);
+
+/* actuals are global, so technically no need for a file_* */
+struct ast_node *scope_find_actual(struct scope *scope, struct ast_node *id);
+
+struct ast_node *scope_find(struct scope *scope, struct ast_node *id);
+struct ast_node *scope_find_var(struct scope *scope, struct ast_node *id);
+struct ast_node *scope_find_type(struct scope *scope, struct ast_node *id);
+struct ast_node *scope_find_proc(struct scope *scope, struct ast_node *id);
+struct ast_node *scope_find_macro(struct scope *scope, struct ast_node *id);
+struct ast_node *scope_find_alias(struct scope *scope, struct ast_node *id);
+struct ast_node *scope_find_template(struct scope *scope, struct ast_node *id);
+
+struct ast_node *file_scope_find(struct scope *scope, struct ast_node *id);
+struct ast_node *file_scope_find_var(struct scope *scope, struct ast_node *id);
+struct ast_node *file_scope_find_type(struct scope *scope, struct ast_node *id);
+struct ast_node *file_scope_find_proc(struct scope *scope, struct ast_node *id);
+struct ast_node *file_scope_find_macro(struct scope *scope,
+ struct ast_node *id);
+struct ast_node *file_scope_find_alias(struct scope *scope,
+ struct ast_node *id);
+struct ast_node *file_scope_find_override(struct scope *scope,
+ struct ast_node *id);
+struct ast_node *file_scope_find_template(struct scope *scope,
+ struct ast_node *id);
+
+struct ast_node *scope_resolve_arr(struct scope *scope, struct ast_node *call);
+struct ast_node *scope_resolve_macro(struct scope *scope,
+ struct ast_node *call);
+struct ast_node *scope_resolve_actual(struct scope *scope,
+ struct ast_node *call);
+struct ast_node *scope_resolve_proc(struct scope *scope, struct ast_node *call);
+struct ast_node *scope_resolve_call(struct scope *scope, struct ast_node *call);
+
+struct ast_node *scope_resolve_type(struct scope *scope, struct ast_node *type);
+struct ast_node *file_scope_resolve_type(struct scope *scope,
+ struct ast_node *type);
+
+struct ast_node *file_scope_resolve_call(struct scope *scope,
+ struct ast_node *call);
+int implements(enum match_flags flags, struct scope *scope,
+ struct ast_node *arg_type,
+ struct ast_node *param_type);
+#endif /* SCOPE_H */
diff --git a/include/cu/string.h b/include/cu/string.h
new file mode 100644
index 0000000..75d7c62
--- /dev/null
+++ b/include/cu/string.h
@@ -0,0 +1,28 @@
+/* SPDX-License-Identifier: GPL-3.0-or-later */
+
+#ifndef CT_STRING_H
+#define CT_STRING_H
+
+#include <stddef.h>
+#include <string.h>
+#include <stdbool.h>
+
+struct string {
+ size_t len;
+ char *buf;
+};
+
+struct string *new_string(const char *s);
+void destroy_string(struct string *s);
+
+int str_append(struct string *s, char c);
+int str_concat(struct string *s, const char *c);
+int str_add(struct string *s, struct string *c);
+
+char str_index(struct string *s, size_t i);
+char str_rindex(struct string *s, size_t i);
+
+bool str_compare(struct string *s, const char *c);
+void str_clear(struct string *s);
+
+#endif /* CT_STRING_H */