diff options
author | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-04-27 00:22:13 +0300 |
---|---|---|
committer | Kimplul <kimi.h.kuparinen@gmail.com> | 2024-04-27 00:22:13 +0300 |
commit | 449ca1e570aa421992bbe98c6928def1ba8896fd (patch) | |
tree | e64321b0c26da220c804403edc644079a81621dc | |
parent | 515ad657ec6ef685c9c91479540518a0091f1516 (diff) | |
download | posthaste-449ca1e570aa421992bbe98c6928def1ba8896fd.tar.gz posthaste-449ca1e570aa421992bbe98c6928def1ba8896fd.zip |
forgot to exclude include in gitignore
-rw-r--r-- | .gitignore | 1 | ||||
-rw-r--r-- | include/posthaste/ast.h | 343 | ||||
-rw-r--r-- | include/posthaste/check.h | 10 | ||||
-rw-r--r-- | include/posthaste/compile.h | 8 | ||||
-rw-r--r-- | include/posthaste/core.h | 7 | ||||
-rw-r--r-- | include/posthaste/date.h | 23 | ||||
-rw-r--r-- | include/posthaste/debug.h | 38 | ||||
-rw-r--r-- | include/posthaste/execute.h | 8 | ||||
-rw-r--r-- | include/posthaste/interpret.h | 8 | ||||
-rw-r--r-- | include/posthaste/lower.h | 107 | ||||
-rw-r--r-- | include/posthaste/parser.h | 57 | ||||
-rw-r--r-- | include/posthaste/scope.h | 31 | ||||
-rw-r--r-- | include/posthaste/utils.h | 14 | ||||
-rw-r--r-- | include/posthaste/vec.h | 45 |
14 files changed, 700 insertions, 0 deletions
@@ -2,3 +2,4 @@ build deps.mk docs/output posthaste +!include/posthaste diff --git a/include/posthaste/ast.h b/include/posthaste/ast.h new file mode 100644 index 0000000..c47e28c --- /dev/null +++ b/include/posthaste/ast.h @@ -0,0 +1,343 @@ +#ifndef AST_H +#define AST_H + +#include <stdint.h> +#include <stdbool.h> +#include <string.h> +#include <stdlib.h> +#include <assert.h> + +/* used to detect semantic loops. + * When entering a node during type checking, AST_FLAG_INIT is set for the node, + * and when exiting, AST_FLAG_CHECKED is set. + * If we enter a node and AST_FLAG_INIT is set without AST_FLAG_CHECKED, we're + * in a loop (for example, two auto functions that just contains calls to each other) + * and type checking has failed. + */ +enum ast_flags { + AST_FLAG_INIT = (1 << 0), + AST_FLAG_CHECKED = (1 << 1), +}; + +enum ast_kind { + /* reserve 0 for uninitialized nodes */ + AST_PROC_DEF = 1, + AST_FUNC_DEF, + AST_VAR_DEF, + AST_FORMAL_DEF, + AST_CONST_INT, + AST_CONST_DATE, + AST_RETURN, + AST_ASSIGN, + AST_ID, + AST_DOT, /* write attribute */ + AST_ATTR, /* read attribute */ + AST_PRINT, + AST_CONST_STRING, + AST_PROC_CALL, + AST_FUNC_CALL, + AST_UNTIL, + AST_UNLESS, + AST_UNLESS_EXPR, + AST_EQ, + AST_LT, + AST_ADD, + AST_SUB, + AST_MUL, + AST_DIV, + AST_POS, /* + INT */ + AST_NEG, /* - INT */ + /* hidden, internal nodes */ + AST_DATE_ADD, + AST_DATE_SUB, + AST_DATE_DIFF, + AST_PRINT_STRING, + AST_PRINT_DATE, + AST_PRINT_BOOL, + AST_PRINT_INT, + AST_BUILTIN_CALL, +}; + +enum type_kind { + TYPE_DATE = 1, TYPE_INT, + /* internal */ + TYPE_STRING, TYPE_BOOL, TYPE_VOID, + /* placeholder for auto functions before their return type is deduced */ + TYPE_AUTO, +}; + +/* used by lower.c, defined here to avoid circular dependencies */ +struct loc { + /* is this a local location? 1 local, 0 global */ + uint32_t l : 1; + /* offset within either local stack or global array */ + uint32_t o : 31; +}; + +/* where a node was generated from in the source file */ +struct src_loc { + int first_line; + int last_line; + int first_col; + int last_col; +}; + +struct ast { + enum ast_kind k; + enum type_kind t; + + /* holds name of variables/funcs/procs */ + char *id; + + /* hold name of return type in func/proc defs */ + char *type; + + /* holds constant value, both ints and dates */ + int64_t v; + + /* references to other ast nodes, exact usage depends on the kind of + * node this is. See macros below. */ + struct ast *a0; + struct ast *a1; + struct ast *a2; + + /* next ast node in list */ + struct ast *n; + + struct src_loc loc; + + /* scope that this node belongs to */ + struct scope *scope; + + enum ast_flags flags; + + /* used by lower.c as a kind of cache for mapping variable definitions + * to locations */ + struct loc l; +}; + +static inline unsigned ast_flags(struct ast *n, enum ast_flags flags) +{ + return n->flags & flags; +} + +static inline void ast_set_flags(struct ast *n, enum ast_flags flags) +{ + n->flags |= flags; +} + +struct ast *gen_ast(enum ast_kind kind, + struct ast *a0, + struct ast *a1, + struct ast *a2, + char *id, + char *type, + int64_t v, + struct src_loc loc); + +/* nifty way to check that all ASTs are of the kind we think they are. + * Generally all accesses to ast members a0 - a2 should go through these macros. + * id is also usually best to access via this macro, but a simple null check + * works as a 'polymorphic' check. Wrappers for each ast node kind follow. */ +#define get_a0(x, kind) *({assert((x)->k == kind); &(x)->a0;}) +#define get_a1(x, kind) *({assert((x)->k == kind); &(x)->a1;}) +#define get_a2(x, kind) *({assert((x)->k == kind); &(x)->a2;}) +#define get_id(x, kind) *({assert((x)->k == kind); &(x)->id;}) + +#define gen_id(id, loc) \ + gen_ast(AST_ID, NULL, NULL, NULL, id, NULL, 0, loc) + +#define var_id(x) get_id(x, AST_VAR_DEF) +#define var_expr(x) get_a0(x, AST_VAR_DEF) +#define gen_var_def(id, expr, loc) \ + gen_ast(AST_VAR_DEF, expr, NULL, NULL, id, NULL, 0, loc) + +#define formal_id(x) get_id(x, AST_FORMAL_DEF) +#define gen_formal_def(id, type, loc) \ + gen_ast(AST_FORMAL_DEF, NULL, NULL, NULL, id, type, 0, loc) + +#define proc_call_id(x) get_id(x, AST_PROC_CALL) +#define proc_call_args(x) get_a0(x, AST_PROC_CALL) +#define gen_proc_call(id, args, loc) \ + gen_ast(AST_PROC_CALL, args, NULL, NULL, id, NULL, 0, loc) + +#define func_call_id(x) get_id(x, AST_FUNC_CALL) +#define func_call_args(x) get_a0(x, AST_FUNC_CALL) +#define gen_func_call(id, args, loc) \ + gen_ast(AST_FUNC_CALL, args, NULL, NULL, id, NULL, 0, loc) + +#define assign_l(x) get_a0(x, AST_ASSIGN) +#define assign_r(x) get_a1(x, AST_ASSIGN) +#define gen_assign(l, r, loc) \ + gen_ast(AST_ASSIGN, l, r, NULL, NULL, NULL, 0, loc) + +#define dot_base(x) get_a0(x, AST_DOT) +#define gen_dot(base, prop, loc) \ + gen_ast(AST_DOT, base, NULL, NULL, prop, NULL, 0, loc) + +#define print_items(x) get_a0(x, AST_PRINT) +#define gen_print(items, loc) \ + gen_ast(AST_PRINT, items, NULL, NULL, NULL, NULL, 0, loc) + +#define gen_const_string(s, loc) \ + gen_ast(AST_CONST_STRING, NULL, NULL, NULL, s, NULL, 0, loc) + +#define return_expr(x) get_a0(x, AST_RETURN) +#define gen_return(expr, loc) \ + gen_ast(AST_RETURN, expr, NULL, NULL, NULL, NULL, 0, loc) + +#define until_body(x) get_a0(x, AST_UNTIL) +#define until_cond(x) get_a1(x, AST_UNTIL) +#define gen_until(body, cond, loc) \ + gen_ast(AST_UNTIL, body, cond, NULL, NULL, NULL, 0, loc) + +#define eq_l(x) get_a0(x, AST_EQ) +#define eq_r(x) get_a1(x, AST_EQ) +#define gen_eq(l, r, loc) \ + gen_ast(AST_EQ, l, r, NULL, NULL, NULL, 0, loc) + +#define lt_l(x) get_a0(x, AST_LT) +#define lt_r(x) get_a1(x, AST_LT) +#define gen_lt(l, r, loc) \ + gen_ast(AST_LT, l, r, NULL, NULL, NULL, 0, loc) + +#define add_l(x) get_a0(x, AST_ADD) +#define add_r(x) get_a1(x, AST_ADD) +#define gen_add(l, r, loc) \ + gen_ast(AST_ADD, l, r, NULL, NULL, NULL, 0, loc) + +#define sub_l(x) get_a0(x, AST_SUB) +#define sub_r(x) get_a1(x, AST_SUB) +#define gen_sub(l, r, loc) \ + gen_ast(AST_SUB, l, r, NULL, NULL, NULL, 0, loc) + +#define mul_l(x) get_a0(x, AST_MUL) +#define mul_r(x) get_a1(x, AST_MUL) +#define gen_mul(l, r, loc) \ + gen_ast(AST_MUL, l, r, NULL, NULL, NULL, 0, loc) + +#define div_l(x) get_a0(x, AST_DIV) +#define div_r(x) get_a1(x, AST_DIV) +#define gen_div(l, r, loc) \ + gen_ast(AST_DIV, l, r, NULL, NULL, NULL, 0, loc) + +#define pos_expr(x) get_a0(x, AST_POS) +#define gen_pos(expr, loc) \ + gen_ast(AST_POS, expr, NULL, NULL, NULL, NULL, 0, loc) + +#define neg_expr(x) get_a0(x, AST_NEG) +#define gen_neg(expr, loc) \ + gen_ast(AST_NEG, expr, NULL, NULL, NULL, NULL, 0, loc) + +#define attr_base(x) get_a0(x, AST_ATTR) +#define gen_attr(base, attr, loc) \ + gen_ast(AST_ATTR, base, NULL, NULL, attr, NULL, 0, loc) + +#define gen_const_int(v, loc) \ + gen_ast(AST_CONST_INT, NULL, NULL, NULL, NULL, NULL, v, loc) + +#define gen_const_date(d, loc) \ + gen_ast(AST_CONST_DATE, NULL, NULL, NULL, NULL, NULL, d, loc) + +#define unless_body(x) get_a0(x, AST_UNLESS) +#define unless_cond(x) get_a1(x, AST_UNLESS) +#define unless_otherwise(x) get_a2(x, AST_UNLESS) +#define gen_unless(body, cond, otherwise, loc) \ + gen_ast(AST_UNLESS, body, cond, otherwise, NULL, NULL, 0, loc) + +#define unless_expr_body(x) get_a0(x, AST_UNLESS_EXPR) +#define unless_expr_cond(x) get_a1(x, AST_UNLESS_EXPR) +#define unless_expr_otherwise(x) get_a2(x, AST_UNLESS_EXPR) +#define gen_unless_expr(body, cond, otherwise, loc) \ + gen_ast(AST_UNLESS_EXPR, body, cond, otherwise, NULL, NULL, 0, loc) + +#define proc_id(x) get_id(x, AST_PROC_DEF) +#define proc_formals(x) get_a0(x, AST_PROC_DEF) +#define proc_vars(x) get_a1(x, AST_PROC_DEF) +#define proc_body(x) get_a2(x, AST_PROC_DEF) +#define gen_proc_def(id, rtype, formals, vars, body, loc) \ + gen_ast(AST_PROC_DEF, formals, vars, body, id, rtype, 0, loc) + +#define func_id(x) get_id(x, AST_FUNC_DEF) +#define func_formals(x) get_a0(x, AST_FUNC_DEF) +#define func_vars(x) get_a1(x, AST_FUNC_DEF) +#define func_body(x) get_a2(x, AST_FUNC_DEF) +#define gen_func_def(id, rtype, formals, vars, body, loc) \ + gen_ast(AST_FUNC_DEF, formals, vars, body, id, rtype, 0, loc) + +#define date_diff_l(x) get_a0(x, AST_DATE_DIFF) +#define date_diff_r(x) get_a1(x, AST_DATE_DIFF) + +#define date_add_l(x) get_a0(x, AST_DATE_ADD) +#define date_add_r(x) get_a1(x, AST_DATE_ADD) + +#define date_sub_l(x) get_a0(x, AST_DATE_SUB) +#define date_sub_r(x) get_a1(x, AST_DATE_SUB) + +/* used by fixup_print_item() below */ +static inline enum ast_kind print_item(enum type_kind k) +{ + switch (k) { + case TYPE_STRING: return AST_PRINT_STRING; + case TYPE_INT: return AST_PRINT_INT; + case TYPE_DATE: return AST_PRINT_DATE; + case TYPE_BOOL: return AST_PRINT_BOOL; + default: + } + + abort(); +} + +/* convert a print item to an explicit AST node for printing that specific type, + * makes lowering ast to bytecode a little bit easier */ +#define fixup_print_item(expr) \ + gen_ast(print_item(expr->t), expr, NULL, NULL, NULL, NULL, 0, expr->loc) + +#define print_date_expr(x) get_a0(x, AST_PRINT_DATE) +#define print_int_expr(x) get_a0(x, AST_PRINT_INT) +#define print_string_expr(x) get_a0(x, AST_PRINT_STRING) +#define print_bool_expr(x) get_a0(x, AST_PRINT_BOOL) + +#define builtin_call_id(x) get_id(x, AST_BUILTIN_CALL) + +/* get last ast node in a list */ +struct ast *ast_last(struct ast *n); + +#ifdef DEBUG +void ast_dump(int depth, struct ast *root); +void ast_dump_list(int depth, struct ast *root); +#endif /* DEBUG */ + +/* free memory owned by ast nodes */ +void destroy_ast_nodes(); + +typedef int (*ast_callback_t)(struct ast *, 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); + +size_t ast_list_len(struct ast *l); + +#define foreach_node(iter, nodes) \ + for (struct ast *iter = nodes; iter; iter = iter->n) + +/* convert type name to a string representation */ +static inline const char *type_str(enum type_kind k) +{ + switch (k) { + case TYPE_INT: return "INT"; + case TYPE_DATE: return "DATE"; + case TYPE_STRING: return "STRING"; + case TYPE_BOOL: return "BOOL"; + case TYPE_VOID: return "VOID"; + /* purposefully skip TYPE_AUTO as it just means we + * haven't assigned a type to it yet */ + default: break; + } + + return "NO TYPE"; +} + +#endif /* AST_H */ diff --git a/include/posthaste/check.h b/include/posthaste/check.h new file mode 100644 index 0000000..a796fc7 --- /dev/null +++ b/include/posthaste/check.h @@ -0,0 +1,10 @@ +#ifndef POSTHASTE_CHECK_H +#define POSTHASTE_CHECK_H + +#include <posthaste/scope.h> + +/* stuff related to semantic checking */ + +int check(struct scope *scope, struct ast *tree); + +#endif /* POSTHASTE_CHECK_H */ diff --git a/include/posthaste/compile.h b/include/posthaste/compile.h new file mode 100644 index 0000000..e149ac6 --- /dev/null +++ b/include/posthaste/compile.h @@ -0,0 +1,8 @@ +#ifndef POSTHASTE_COMPILE_H +#define POSTHASTE_COMPILE_H + +/* stuff related to compiling bytecode to machine code */ + +void compile(); + +#endif /* POSTHASTE_COMPILE_H */ diff --git a/include/posthaste/core.h b/include/posthaste/core.h new file mode 100644 index 0000000..ba52525 --- /dev/null +++ b/include/posthaste/core.h @@ -0,0 +1,7 @@ +#ifndef CORE_H +#define CORE_H + +/* handles parsing, type checking and execution of fname */ +int run(const char *fname); + +#endif /* CORE_H */ diff --git a/include/posthaste/date.h b/include/posthaste/date.h new file mode 100644 index 0000000..d091d79 --- /dev/null +++ b/include/posthaste/date.h @@ -0,0 +1,23 @@ +#ifndef DATE_H +#define DATE_H + +/* stuff related to posthaste date handling */ + +#include <stdint.h> +#include <time.h> +#include <stdbool.h> + +/* store dates as regular integers, with lowest five bits being the day, the + * next four the month, and the rest the year */ +typedef uint64_t ph_date_t; + +ph_date_t date_from_string(const char str[static 11]); +ph_date_t date_from_numbers(unsigned year, unsigned month, unsigned day); +void date_to_string(char str[static 11], ph_date_t date); +void date_split(ph_date_t date, unsigned *year, unsigned *month, unsigned *day); +bool date_valid(ph_date_t date); +struct tm tm_from_date(ph_date_t date); +ph_date_t date_from_tm(struct tm time); +ph_date_t current_date(); + +#endif /* DATE_H */ diff --git a/include/posthaste/debug.h b/include/posthaste/debug.h new file mode 100644 index 0000000..fa3d2b9 --- /dev/null +++ b/include/posthaste/debug.h @@ -0,0 +1,38 @@ +#ifndef POSTHASTE_DEBUG_H +#define POSTHASTE_DEBUG_H + +/* stuff related to printing out issues in code to the user */ + +#include <stdio.h> +#include <stdarg.h> + +#include <posthaste/scope.h> +#include <posthaste/ast.h> + +struct src_issue { + const char *fname; + const char *buf; + struct src_loc loc; +}; + +void src_issue(struct src_issue issue, const char *msg, ...); +void vsrc_issue(struct src_issue issue, const char *msg, va_list args); + +/* warn on incompatible types in format string */ +__attribute__((format (printf, 3, 4))) +static inline void semantic_error(struct scope *scope, struct ast *n, + const char *msg, ...) +{ + va_list args; + va_start(args, msg); + struct src_issue issue; + issue.loc = n->loc; + /* technically we could also just iterate upwards through parent scopes + * until we reach a file scope, but this works as well */ + issue.fname = scope->fname; + issue.buf = scope->buf; + vsrc_issue(issue, msg, args); + va_end(args); +} + +#endif /* POSTHASTE_DEBUG_H */ diff --git a/include/posthaste/execute.h b/include/posthaste/execute.h new file mode 100644 index 0000000..ef51549 --- /dev/null +++ b/include/posthaste/execute.h @@ -0,0 +1,8 @@ +#ifndef POSTHASTE_EXECUTE_H +#define POSTHASTE_EXECUTE_H + +/* stuff related to executing compiled machine code */ + +void execute(); + +#endif /* POSTHASTE_EXECUTE_H */ diff --git a/include/posthaste/interpret.h b/include/posthaste/interpret.h new file mode 100644 index 0000000..50bdbf3 --- /dev/null +++ b/include/posthaste/interpret.h @@ -0,0 +1,8 @@ +#ifndef POSTHASTE_INTERPRET_H +#define POSTHASTE_INTERPRET_H + +/* stuff related to interpreting our bytecode */ + +void interpret(); + +#endif /* POSTHASTE_INTERPRET_H */ diff --git a/include/posthaste/lower.h b/include/posthaste/lower.h new file mode 100644 index 0000000..d5b1d7d --- /dev/null +++ b/include/posthaste/lower.h @@ -0,0 +1,107 @@ +#ifndef POSTHASTE_LOWER_H +#define POSTHASTE_LOWER_H + +/* stuff related to lowering AST to bytecode */ + +#include <posthaste/ast.h> +#include <posthaste/vec.h> + +enum insn_kind { + LABEL, /* no-op during interpretation, + used by JIT engine to keep track of jump branch destinations. + Each branch/jump must have a corresponding label!*/ + CALL, + MOVE, + ADD, + SUB, + MUL, + DIV, + ARG, /* push location to arg stack */ + RETVAL, /* move return value to location */ + PRINT_DATE, + PRINT_STRING, + PRINT_INT, + PRINT_BOOL, + PRINT_NEWLINE, + PRINT_SPACE, + DATE_ADD, + DATE_SUB, + DATE_DIFF, + STORE_DAY, /* x.day etc */ + STORE_MONTH, + STORE_YEAR, + LOAD_DAY, /* x'day etc */ + LOAD_MONTH, + LOAD_YEAR, + LOAD_WEEKDAY, + LOAD_WEEKNUM, + TODAY, /* the builtin Today() is lowered to a single instruction */ + RET, /* return with value */ + STOP, /* return without value */ + CONST, /* push a constant value to loc */ + EQ, + LT, + NEG, /* negation, -x */ + B, /* branch if non-zero */ + BZ, /* branch if zero */ + J, /* jump */ +}; + +struct insn { + enum insn_kind k; + /* output location */ + struct loc o; + + /* input locations */ + struct loc i0; + struct loc i1; + + /* potential constant value */ + union { + int64_t v; + char *s; + }; +}; + +/* after lowering, there's no real difference between posthaste 'functions' and + * 'procedures', so I just use fn to refer to either or */ +struct fn { + char *name; + + size_t idx; + + /* virtual stack pointer used during lowering to choose where to place + * values */ + size_t sp; + + /* maximum stack pointer value to know how much stack space to allocate */ + size_t max_sp; + + /* instruction buffer */ + struct vec insns; + + /* used by jit */ + /* how many formal parameters */ + size_t params; + + /* machine code buffer, for whatever reason seems to commonly be called 'arena' + * in JIT compilers, just following the convention here*/ + void *arena; + + /* size of arena */ + size_t size; +}; + +int lower_ast(struct ast *tree); + +struct fn *find_fn(size_t idx); +size_t num_globals(); + +void destroy_lowering(); + +static inline bool is_null_loc(struct loc l) +{ + return l.l == 0 && l.o == 1; +} + +#endif /* POSTHASTE_LOWER_H */ diff --git a/include/posthaste/parser.h b/include/posthaste/parser.h new file mode 100644 index 0000000..d3a3e6b --- /dev/null +++ b/include/posthaste/parser.h @@ -0,0 +1,57 @@ +#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 <posthaste/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 Contexts of \p fname. + */ +void parse(struct parser *p, const char *fname, const char *buf); + +#endif /* PARSER_H */ diff --git a/include/posthaste/scope.h b/include/posthaste/scope.h new file mode 100644 index 0000000..8c9dbf9 --- /dev/null +++ b/include/posthaste/scope.h @@ -0,0 +1,31 @@ +#ifndef POSTHASTE_SCOPE_H +#define POSTHASTE_SCOPE_H + +#include <posthaste/ast.h> +#include <posthaste/vec.h> + +struct scope { + size_t id; + struct scope *parent; + + const char *fname; + const char *buf; + + struct vec visible; +}; + +struct scope *create_scope(); +void destroy_scopes(); + +void scope_add_scope(struct scope *parent, struct scope *scope); +void scope_set_file(struct scope *scope, const char *fname, const char *buf); + +struct ast *scope_find(struct scope *scope, char *id); +struct ast *file_scope_find(struct scope *scope, char *id); + +int scope_add_var(struct scope *scope, struct ast *var); +int scope_add_formal(struct scope *scope, struct ast *var); +int scope_add_proc(struct scope *scope, struct ast *proc); +int scope_add_func(struct scope *scope, struct ast *func); + +#endif /* POSTHASTE_SCOPE_H */ diff --git a/include/posthaste/utils.h b/include/posthaste/utils.h new file mode 100644 index 0000000..603455a --- /dev/null +++ b/include/posthaste/utils.h @@ -0,0 +1,14 @@ +#ifndef POSTHASTE_UTILS_H +#define POSTHASTE_UTILS_H + +/* random things not strictly related to anything else */ + +static inline bool same_id(const char *a, const char *b) +{ + /* I always forget to compare to zero */ + return strcmp(a, b) == 0; +} + +#define UNUSED(x) (void)x + +#endif /* POSTHASTE_UTILS_H */ diff --git a/include/posthaste/vec.h b/include/posthaste/vec.h new file mode 100644 index 0000000..2ffa80c --- /dev/null +++ b/include/posthaste/vec.h @@ -0,0 +1,45 @@ +#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); +void vec_reserve(struct vec *v, size_t ns); + +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 */ |