diff options
Diffstat (limited to 'include')
-rw-r--r-- | include/fwd/analyze.h | 12 | ||||
-rw-r--r-- | include/fwd/ast.h | 393 | ||||
-rw-r--r-- | include/fwd/compiler.h | 25 | ||||
-rw-r--r-- | include/fwd/debug.h | 138 | ||||
-rw-r--r-- | include/fwd/lower.h | 12 | ||||
-rw-r--r-- | include/fwd/parser.h | 59 | ||||
-rw-r--r-- | include/fwd/scope.h | 194 | ||||
-rw-r--r-- | include/fwd/vec.h | 47 |
8 files changed, 880 insertions, 0 deletions
diff --git a/include/fwd/analyze.h b/include/fwd/analyze.h new file mode 100644 index 0000000..bdbcdb2 --- /dev/null +++ b/include/fwd/analyze.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef FWD_ANALYZE +#define FWD_ANALYZE + +#include <fwd/ast.h> +#include <fwd/scope.h> + +int analyze_root(struct scope *scope, struct ast *root); + +#endif /* FWD_ANALYZE */ diff --git a/include/fwd/ast.h b/include/fwd/ast.h new file mode 100644 index 0000000..909137d --- /dev/null +++ b/include/fwd/ast.h @@ -0,0 +1,393 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef AST_H +#define AST_H + +#include <stddef.h> +#include <stdbool.h> + +/** + * @file ast.h + * + * Abstract syntax tree handling. + */ + +#define NULL_LOC() ((struct src_loc){0, 0, 0, 0}) + +/** Represents a source location, spanning over some bit of code. */ +struct src_loc { + /** First line of interesting text. */ + int first_line; + /** Last line of interesting text. */ + int last_line; + /** First column in first line of interesting text. */ + int first_col; + /** Last column in last line of interesting text. */ + int last_col; +}; + +struct ast; + +enum type_kind { + TYPE_ID = 1, TYPE_CONSTRUCT +}; + +struct type { + enum type_kind k; + + /* type arg */ + struct type *t0; + + /* id */ + char *id; + + /* next */ + struct type *n; + + struct src_loc loc; +}; + +/** Possible AST node types. We reserve node 0 as an illegal value. */ +enum ast_kind { + /** Creating new variable. */ + AST_LET = 1, + /** Call procedure. */ + AST_CALL, + /** Procedure definition. */ + AST_PROC_DEF, + /** Variable declaration/definition. */ + AST_VAR_DEF, + /** Dot. \c a.b; */ + AST_DOT, + /* Closure */ + AST_CLOSURE, + /** Construct new type, something!{} */ + AST_INIT, + /** Block. E.g. \c {} */ + AST_BLOCK, + /** Any ID, variable or whatever. */ + AST_ID, + /** Empty. Essentially noop. */ + AST_EMPTY, + /** Add, \c + */ + AST_ADD, + /** Subtract, \c - */ + AST_SUB, + /** Multiply, \ * */ + AST_MUL, + /** Divide, \c \ */ + AST_DIV, + /** Remainder, \c % */ + AST_REM, + /** Logical and, \c && */ + AST_LAND, + /** Logical or, \c ||*/ + AST_LOR, + /** Left shift (logical), \c << @todo add arithmetic shifts? */ + AST_LSHIFT, + /** Right shift (logical), \c >> */ + AST_RSHIFT, + /** Less than, \c < */ + AST_LT, + /** Greater than, \c > */ + AST_GT, + /** Less than or equal, \c <= */ + AST_LE, + /** Greater than or equal, \c >= */ + AST_GE, + /** Not equal, \c != */ + AST_NE, + /** Equal, \c == */ + AST_EQ, + /** Negation, \c - */ + AST_NEG, + /** Logical negation, \c ! */ + AST_LNOT, + /** Bitwise negation, \c ~ */ + AST_NOT, + AST_CONST_INT, + AST_CONST_FLOAT, + AST_CONST_CHAR, + AST_CONST_BOOL, + AST_CONST_STR, +}; + +struct ast { + enum ast_kind k; + double d; + long long v; + char *s; + struct ast *a0; + struct ast *a1; + struct ast *a2; + struct ast *a3; + struct type *t2; + + struct ast *n; + struct src_loc loc; + struct scope *scope; +}; + +struct ast *gen_ast(enum ast_kind kind, + struct ast *a0, + struct ast *a1, + struct ast *a2, + struct ast *a3, + struct type *t1, + char *s, + long long v, + double d, + struct src_loc loc); + +struct type *tgen_type(enum type_kind kind, + struct type *t0, + char *id, + struct src_loc loc); + +static inline bool is_binop(struct ast *x) +{ + switch (x->k) { + case AST_ADD: + case AST_SUB: + case AST_MUL: + case AST_DIV: + case AST_REM: + case AST_LSHIFT: + case AST_RSHIFT: + return true; + default: + break; + }; + + return false; +} + +static inline bool is_unop(struct ast *x) +{ + switch (x->k) { + case AST_NOT: + case AST_NEG: + return true; + default: + break; + } + + return false; +} + +static inline bool is_comparison(struct ast *x) +{ + switch (x->k) { + case AST_LT: + case AST_GT: + case AST_LE: + case AST_GE: + case AST_NE: + case AST_EQ: + return true; + default: + break; + } + + return false; +} + +static inline bool is_const(struct ast *x) +{ + /* note that const strings are sort of their own entity */ + switch (x->k) { + case AST_CONST_INT: + case AST_CONST_CHAR: + case AST_CONST_BOOL: + case AST_CONST_FLOAT: + return true; + default: + break; + } + + return false; +} + +#define gen_str_type1(k, s, t, a, loc) gen_ast(k, a, NULL, NULL, NULL, \ + t, s, -1, 0., loc) +#define gen_str_type(k, s, t, loc) gen_str_type1(k, s, t, NULL, loc) +#define gen_str3(k, s, a, b, c, loc) gen_ast(k, a, b, c, NULL, NULL, s, -1, 0., \ + loc) +#define gen_str2(k, s, a, b, loc) gen_str3(k, s, a, b, NULL, loc) +#define gen_str1(k, s, a, loc) gen_str2(k, s, a, NULL, loc) +#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) + + +/* kind of hacky but I guess it works, and allows us to check that the type is + * correct every time */ +#define return_s(x, kind) *({assert((x)->k == kind); &(x)->s;}) +#define return_a0(x, kind) *({assert((x)->k == kind); &(x)->a0;}) +#define return_a1(x, kind) *({assert((x)->k == kind); &(x)->a1;}) +#define return_a2(x, kind) *({assert((x)->k == kind); &(x)->a2;}) +#define return_a3(x, kind) *({assert((x)->k == kind); &(x)->a3;}) +#define return_t2(x, kind) *({assert((x)->k == kind); &(x)->t2;}) + +#define return_id(x, kind) *({assert((x)->k == kind); &(x)->id;}) +#define return_t0(x, kind) *({assert((x)->k == kind); &(x)->t0;}) + +#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 closure_bindings(x) return_a0(x, AST_CLOSURE) +#define closure_body(x) return_a1(x, AST_CLOSURE) +#define gen_closure(bindings, body, loc) \ + gen2(AST_CLOSURE, bindings, body, loc) + +#define binop_left(x) ({assert(is_binop(x)); x->a0;}) +#define binop_right(x) ({assert(is_binop(x)); x->a1;}) +#define gen_binop(op, left, right, loc) \ + gen2(op, left, right, loc) + +#define comparison_left(x) ({assert(is_comparison(x)); x->a0;}) +#define comparison_right(x) ({assert(is_comparison(x)); x->a1;}) +#define gen_comparison(op, left, right, loc) \ + gen2(op, left, right, loc) + +#define unop_expr(x) ({assert(is_unop(x)); x->a0;}) +#define gen_unop(op, expr, loc) \ + gen1(op, expr, loc) + +#define call_expr(x) return_a0(x, AST_CALL) +#define call_args(x) return_a1(x, AST_CALL) +#define gen_call(expr, args, loc) \ + gen2(AST_CALL, expr, args, loc) + +#define proc_id(x) return_s(x, AST_PROC_DEF) +#define proc_params(x) return_a0(x, AST_PROC_DEF) +#define proc_rtype(x) return_t2(x, AST_PROC_DEF) +#define proc_body(x) return_a1(x, AST_PROC_DEF) +#define gen_proc(id, params, rtype, body, loc) \ + gen_ast(AST_PROC_DEF, params, body, NULL, NULL, rtype, id, 0, 0., loc) + +#define dot_id(x) return_s(x, AST_DOT) +#define dot_expr(x) return_a0(x, AST_DOT) +#define gen_dot(id, expr, loc) \ + gen_str1(AST_DOT, id, expr, loc) + +#define var_id(x) return_s(x, AST_VAR_DEF) +#define var_type(x) return_t2(x, AST_VAR_DEF) +#define var_init(x) return_a0(x, AST_VAR_DEF) +#define gen_var(id, loc) \ + gen_ast(AST_VAR_DEF, NULL, NULL, NULL, NULL, NULL, id, 0, 0., loc) + +#define block_body(x) return_a0(x, AST_BLOCK) +#define gen_block(body, loc) \ + gen1(AST_BLOCK, body, loc) + +#define str_val(x) return_s(x, AST_CONST_STR) +#define gen_const_str(s, loc) \ + gen_ast(AST_CONST_STR, NULL, NULL, NULL, NULL, NULL, s, 0, 0., loc) + +#define int_val(x) *({assert(x->k == AST_CONST_INT); &x->v;}) +#define gen_const_int(i, loc) \ + gen_ast(AST_CONST_INT, NULL, NULL, NULL, NULL, NULL, NULL, i, 0., loc) + +#define float_val(x) *({assert(x->k == AST_CONST_FLOAT); &x->d;}) +#define gen_const_float(d, loc) \ + gen_ast(AST_CONST_FLOAT, NULL, NULL, NULL, NULL, NULL, NULL, 0, d, loc) + +#define char_val(x) *({assert(x->k == AST_CONST_CHAR); &x->v;}) +#define gen_const_char(i, loc) \ + gen_ast(AST_CONST_CHAR, NULL, NULL, NULL, NULL, NULL, NULL, i, 0., loc) + +#define bool_val(x) *({assert(x->k == AST_CONST_CHAR); &x->v;}) +#define gen_const_bool(i, loc) \ + gen_ast(AST_CONST_BOOL, NULL, NULL, NULL, NULL, NULL, NULL, i, 0., loc) + +#define let_id(x) return_s(x, AST_LET) +#define let_expr(x) return_a0(x, AST_LET) +#define gen_let(id, from, loc) \ + gen_str1(AST_LET, id, from, loc) + +#define init_args(x) return_t2(x, AST_INIT) +#define init_body(x) return_a0(x, AST_INIT) +#define init_id(x) return_s(x, AST_INIT) +#define gen_init(id, targs, body, loc) \ + gen_str_type1(AST_INIT, id, targs, body, loc) + +#define id_str(x) return_s(x, AST_ID) +#define gen_id(id, loc) \ + gen_str(AST_ID, id, loc) + +#define gen_empty(loc) \ + gen1(AST_EMPTY, NULL, loc) + +struct ast *clone_ast(struct ast *n); +struct ast *clone_ast_list(struct ast *l); + +void ast_dump_list(int depth, struct ast *root); +void ast_dump(int depth, struct ast *node); +void ast_append(struct ast **list, struct ast *elem); + +struct ast *ast_prepend(struct ast *list, struct ast *elem); + +typedef int (*ast_callback_t)(struct ast *, void *); +typedef int (*type_callback_t)(struct type *, void *); +int ast_visit(ast_callback_t before, ast_callback_t after, struct ast *node, + void *data); +int ast_visit_list(ast_callback_t before, ast_callback_t after, + struct ast *node, void *data); + +/** + * Number of elements in AST list. + * + * @param list List whose elements to count. + * @return Number of elements in \p list. + */ +size_t ast_list_len(struct ast *list); + +/** + * Get last nose in ASt list. + * + * @param list List whose last element to get. + * @return Last node in \p list. + */ +struct ast *ast_last(struct ast *list); + +/** + * Get last element in block. + * + * @param block Block whose last element to get. + * @return Last node in block. + */ +struct ast *ast_block_last(struct ast *block); + +void destroy_allocs(); +const char *primitive_str(struct type *kind); + +int same_id(char *id1, char *id2); +int equiv_nodes(struct ast *n1, struct ast *n2); +int equiv_node_lists(struct ast *c1, struct ast *c2); + +struct ast *reverse_ast_list(struct ast *root); +struct type *reverse_type_list(struct type *root); + +void fix_closures(struct ast *root); + +#define foreach_node(iter, nodes) \ + for (struct ast *iter = nodes; iter; iter = iter->n) + +#define foreach_type(iter, types) \ + for (struct type *iter = types; iter; iter = iter->n) + +#endif /* AST_H */ diff --git a/include/fwd/compiler.h b/include/fwd/compiler.h new file mode 100644 index 0000000..b7f1569 --- /dev/null +++ b/include/fwd/compiler.h @@ -0,0 +1,25 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef FWD_COMPILER_H +#define FWD_COMPILER_H + +/** + * @file compiler.h + * + * Top level compiler. + */ + +#include <fwd/scope.h> + +/** + * Compile a root file. + * A root file is a file given on the command line, and is assumed to + * create a file tree that eventually results in a binary. + * + * @param file Root file to compile. + * @return \c 0 if compilation was succesful, otherwise some non-zero value. + */ +int compile(const char *input); + +#endif /* FWD_COMPILER_H */ diff --git a/include/fwd/debug.h b/include/fwd/debug.h new file mode 100644 index 0000000..85ed9db --- /dev/null +++ b/include/fwd/debug.h @@ -0,0 +1,138 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef FWD_DEBUG_H +#define FWD_DEBUG_H + +/** + * @file debug.h + * + * Debugging and general information printing helpers. + */ + +#include <stdio.h> + +#include <fwd/ast.h> + +#if DEBUG +/** + * Print debugging message. Only active if \c DEBUG is defined, + * + * @param x Format string. Follows standard printf() formatting. + */ +#define debug(x, ...) \ + do {fprintf(stderr, "debug: " x "\n",##__VA_ARGS__);} while(0) +#else +#define debug(x, ...) +#endif + +/** + * Print error message. + * + * @param x Format string. Follows standard printf() formatting. + */ +#define error(x, ...) \ + do {fprintf(stderr, "error: " x "\n",##__VA_ARGS__);} while(0) + +/** + * Print warning message. + * + * @param x Format string. Follows standard printf() formatting. + */ +#define warn(x, ...) \ + do {fprintf(stderr, "warn: " x "\n",##__VA_ARGS__);} while(0) + +/** + * Print info message. + * + * @param x Format string. Follows standard printf() formatting. + */ +#define info(x, ...) \ + do {fprintf(stderr, "info: " x "\n",##__VA_ARGS__);} while(0) + + +/** Keeps track of file name and file buffer. */ +struct file_ctx { + /** File name. */ + const char *fname; + /** File buffer. */ + const char *fbuf; +}; + +/** + * Print info that relates to a specific AST node. + * Recommended for situations where it may be useful to clarify some + * previous error or warning. + * + * @param ctx File context \p node was generated from. + * @param node AST node to print message with. + * @param fmt Format string. Follows standard printf() formatting. + */ +void semantic_info(struct file_ctx ctx, struct ast *node, const char *fmt, ...); + +/** + * Print warning that relates to a specific AST node. + * Recommended for situations where the user wrote some shady code + * and it might be unclear what was meant. + * + * The language itself tries to avoid such situations, and as such warnings + * should probably be avoided in favor of errors. Still, I can imagine that + * there are situations where warnings can be useful, so it's provided. + * + * @param ctx File context \p node was generated from. + * @param node AST node to print message with. + * @param fmt Format string. Follows standard printf() formatting. + */ +void semantic_warn(struct file_ctx ctx, struct ast *node, const char *fmt, + ...); + +/** + * Print warning that relates to a specific AST node. + * Recommended for situations where the user messed up. + * + * @param ctx File context \p node was generated from. + * @param node AST node to print message with. + * @param fmt Format string. Follows standard printf() formatting. + */ +void semantic_error(struct file_ctx ctx, struct ast *node, const char *fmt, + ...); +void loc_error(struct file_ctx ctx, struct src_loc loc, const char *fmt, ...); + +/** + * Print internal error. + * Recommended for situations where the developer (probably me) messed up. + * + * @param fmt Format string. Follows standard printf() formatting. + */ +void internal_error(const char *fmt, ...); +void internal_warn(const char *fmt, ...); + +/** Issue categorization. */ +enum issue_level { + /** Information. */ + SRC_INFO, + /** Warning. */ + SRC_WARN, + /** Error. */ + SRC_ERROR +}; + +/** Context for issue in user code. */ +struct src_issue { + /** How bad the issue is. */ + enum issue_level level; + /** Where the issue happened relative to file buffer. */ + struct src_loc loc; + /** File context issue happened in. */ + struct file_ctx fctx; +}; + +/** + * Print a source issue. + * + * @param issue Context for issue. + * @param err_msg Format string. Follows standard printf() formatting. + */ +void src_issue(struct src_issue issue, const char *err_msg, ...); + +#endif /* FWD_DEBUG_H */ diff --git a/include/fwd/lower.h b/include/fwd/lower.h new file mode 100644 index 0000000..1aace53 --- /dev/null +++ b/include/fwd/lower.h @@ -0,0 +1,12 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef FWD_LOWER_H +#define FWD_LOWER_H + +#include <fwd/ast.h> +#include <stdio.h> + +int lower(struct scope *root); + +#endif /* FWD_LOWER_H */ diff --git a/include/fwd/parser.h b/include/fwd/parser.h new file mode 100644 index 0000000..93017d8 --- /dev/null +++ b/include/fwd/parser.h @@ -0,0 +1,59 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef PARSER_H +#define PARSER_H + +/** + * @file parser.h + * + * Glue file to get lexer and parser to play nice. + */ + +#include <stddef.h> +#include <stdbool.h> +#include <fwd/ast.h> + +/** Stuff the parser needs to do its job. */ +struct parser { + /** Whether parsing failed or succeeded. */ + bool failed; + /** Lexer. Parser owns the lexer and is responsible for initializing + * and destroyint the lexer. + */ + void *lexer; + + /** File content in memory. */ + const char *buf; + /** Filename. */ + const char *fname; + /** How deeply we've nested comments. */ + size_t comment_nesting; + /** Raw AST. */ + struct ast *tree; +}; + +/** + * Create new parser. + * + * @return Created parser. + */ +struct parser *create_parser(); + +/** + * Destroy parser. + * + * @param p Parser to destroy. + */ +void destroy_parser(struct parser *p); + +/** + * Run parser on buffer \p buf with name \p fname. + * + * @param p Parser to run. + * @param fname Name of file \p buf was read from. + * @param buf Contents of \p fname. + */ +void parse(struct parser *p, const char *fname, const char *buf); + +#endif /* PARSER_H */ diff --git a/include/fwd/scope.h b/include/fwd/scope.h new file mode 100644 index 0000000..6a78793 --- /dev/null +++ b/include/fwd/scope.h @@ -0,0 +1,194 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef SCOPE_H +#define SCOPE_H + +/** + * @file scope.h + * + * Scope handling stuff. + */ + +#include "ast.h" +#include "debug.h" + +/** + * An AST node visible to the scope we're in. + * The same AST node can be referenced by multiple visible nodes, + * but only the owning scope is allowed to destroy the node. + * Check that \p owner is identical to the scope the visible node + * belongs to. + * + * Basic linked list for now, can probably be optimized into some kind of hash + * table later. + */ +struct visible { + /** Name of the visible node. */ + char *id; + /** AST node that is visible. */ + struct ast *node; + /** Next visible object in the scope we're in. */ + struct visible *next; +}; + +/** + * Scope. + * Responsible for keeping track of visibilities and + * file context. + */ +struct scope { + /** Parent scope, NULL if top scope. */ + struct scope *parent; + + /** Unique scope ID. Mostly used for debugging. */ + size_t number; + + /** + * File context of scope. Accurate debugging output relies + * on keeping track of which file and buffer a context is in. + */ + struct file_ctx fctx; + + /** + * Next child node. + * Used by the parent scope to keep track of all its children. + */ + struct scope *next; + + /** List of child scopes. */ + struct scope *children; + + struct visible *symbols; +}; + +/** + * Create scope. + * + * @return New, empty scope. + */ +struct scope *create_scope(); + +/** + * Destroy scope. + * Destroys all lists the scope owns and frees the scope. + * + * @param scope Scope to destroy. + */ +void destroy_scope(struct scope *scope); + +/** + * Add default stuff to scope, mainly builtin types. + * + * @param root Scope to add default stuff to. + * @note Only has to be called on the file scope, all child scopes will + * look up stuff from the file scope anyway. + * @return \c 0 if succesful, non-zero otherwise. + */ +int scope_add_defaults(struct scope *root); + +/** + * Destroy defaults in scope that might otherwise not be freed. + * + * @param root Scope to destroy added defaults in. + * @todo not sure if this should be private. + */ +void scope_destroy_defaults(struct scope *root); + +/** + * Add a scratch AST node. + * + * @param scope Scope to add scratch AST node to. + * @param scratch Scratch node to add to \p scope. + * @return \c 0 when successful, non-zero otherwise. + */ +int scope_add_scratch(struct scope *scope, struct ast *scratch); + +/** + * Add child scope to \p parent. + * + * @param parent Scope to add scope to. + * @param child Scope to add to scope. + */ +void scope_add_scope(struct scope *parent, struct scope *child); + +/** + * Add variable to scope. + * Propagates public variables up the file scope chain as references. + * + * @param scope Scope to add variable to. + * @param var Variable to add to scope. + * @return \c 0 when succesful, non-zero otherwise. + */ +int scope_add_var(struct scope *scope, struct ast *var); + +/** + * Add type to scope. + * Propagates public types up the file scope chain as references. + * + * @param scope Scope to add type to. + * @param type Type to add to scope. + * @return \c 0 when succesful, non-zero otherwise. + */ +int scope_add_type(struct scope *scope, char *id, struct ast *type); + +/** + * Add procedure to scope. + * Propagates public procedures up the file scope chain as references. + * + * @param scope Scope to add procedure to. + * @param proc Procedure to add to scope. + * @return \c 0 when succesful, non-zero otherwise. + */ +int scope_add_proc(struct scope *scope, struct ast *proc); + +/** + * Find a variable with ID in \p scope. + * @note Only looks in the current scope, so doesn't see anything outside + * of it. See file_scope_find_var(). + * + * @param scope Scope to look in. + * @param id ID of variable to find. + * @return Pointer to the AST node corresponding to \p id if found, + * otherwise \c NULL. + */ +struct ast *scope_find_var(struct scope *scope, char *id); +struct ast *scope_find_symbol(struct scope *scope, char *id); + +/** + * Find a procedure with ID in \p scope. + * @note Only looks in the current scope, so doesn't see anything outside + * of it. See file_scope_find_proc(). + * + * @param scope Scope to look in. + * @param id ID of procedure to find. + * @return Pointer to the AST node corresponding to \p id if found, + * otherwise \c NULL. + */ +struct ast *scope_find_proc(struct scope *scope, char *id); + +/** + * Find a variable with ID visible to \p scope. + * + * @param scope Scope to look in. + * @param id ID of variable to find. + * @return Pointer to the AST node corresponding to \p id if found, + * otherwise \c NULL. + */ +struct ast *file_scope_find_var(struct scope *scope, char *id); +struct ast *file_scope_find_symbol(struct scope *scope, char *id); + +/** + * Find a procedure with ID visible to \p scope. + * + * @param scope Scope to look in. + * @param id ID of procedure to find. + * @return Pointer to the AST node corresponding to \p id if found, + * otherwise \c NULL. + */ +struct ast *file_scope_find_proc(struct scope *scope, char *id); + +#define foreach_visible(iter, init) \ + for (struct visible *iter = init; iter; iter = iter->next) + +#endif /* SCOPE_H */ diff --git a/include/fwd/vec.h b/include/fwd/vec.h new file mode 100644 index 0000000..1b78c59 --- /dev/null +++ b/include/fwd/vec.h @@ -0,0 +1,47 @@ +/* SPDX-License-Identifier: copyleft-next-0.3.1 */ +/* Copyright 2024 Kim Kuparinen < kimi.h.kuparinen@gmail.com > */ + +#ifndef VEC_H +#define VEC_H + +#include <stddef.h> + +struct vec { + size_t n; + size_t s; + size_t ns; + void *buf; +}; + +struct vec vec_create(size_t s); +void vec_destroy(struct vec *v); +void vec_reset(struct vec *v); + +size_t vec_len(struct vec *v); +void *vec_at(struct vec *v, size_t i); +void *vec_back(struct vec *v); +void *vec_pop(struct vec *v); +void vec_append(struct vec *v, void *n); + +typedef int (*vec_comp_t)(const void *, const void *); +void vec_sort(struct vec *v, vec_comp_t comp); + +#define foreach_vec(iter, v) \ + for (size_t iter = 0; iter < vec_len(&v); ++iter) + +#define vect_at(type, v, i) \ + *(type *)vec_at(&v, i) + +#define vect_append(type, v, e) \ + vec_append(&v, (type *)(e)) + +#define vect_back(type, v) \ + *(type *)vec_back(&v) + +#define vect_pop(type, v) \ + *(type *)vec_pop(&v) + +#define vec_uninit(v) \ + (v.buf == NULL) + +#endif /* VEC_H */ |