From: Michael Wallner Date: Sat, 10 Oct 2015 22:29:25 +0000 (+0200) Subject: init X-Git-Url: https://git.m6w6.name/?a=commitdiff_plain;h=6ed7825ca4ddea88b00968e20cbaeeb1e8eb3de4;p=m6w6%2Fext-psi init --- 6ed7825ca4ddea88b00968e20cbaeeb1e8eb3de4 diff --git a/.editorconfig b/.editorconfig new file mode 100644 index 0000000..9b444ae --- /dev/null +++ b/.editorconfig @@ -0,0 +1,23 @@ +; see http://editorconfig.org +root = true + +[*] +end_of_line = lf +insert_final_newline = true +indent_style = tab +charset = utf-8 +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false + +[*.json] +indent_style = space +indent_size = 4 + +[package.xml] +indent_style = space +indent_size = 1 + +[config.w32] +end_of_line = crlf diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..3ce5b15 --- /dev/null +++ b/.gitignore @@ -0,0 +1,7 @@ +*.dSYM +/idl/lexer.c +/idl/parser +/idl/parser.h +/idl/parser.c +/idl/parser.out +/idl/makeheaders* diff --git a/TODO b/TODO new file mode 100644 index 0000000..286357b --- /dev/null +++ b/TODO @@ -0,0 +1,2 @@ +* move numbers to the lexer +* avoid allocs inside structures by reallocating the whole structure diff --git a/idl/Makefile b/idl/Makefile new file mode 100644 index 0000000..f7d99f7 --- /dev/null +++ b/idl/Makefile @@ -0,0 +1,29 @@ +CFLAGS = -g +.PHONY: all +all: parser makeheaders + +makeheaders.c: + curl -sSO http://www.hwaci.com/sw/mkhdr/makeheaders.c + +GENERATED_FILES += makeheaders +makeheaders: makeheaders.c + +GENERATED_FILES += parser +parser: main.c parser.c lexer.c + +GENERATED_FILES += parser.h +parser.h: parser.c makeheaders + ./makeheaders $<:$@ + touch $@ + +GENERATED_FILES += parser.c +parser.c: parser.y types.h + lemon -c -m $< + +GENERATED_FILES += lexer.c +lexer.c: lexer.re parser.h + re2c -o $@ $< + +.PHONY: clean +clean: + -rm -f $(GENERATED_FILES) diff --git a/idl/lexer.h b/idl/lexer.h new file mode 100644 index 0000000..e3f7c5f --- /dev/null +++ b/idl/lexer.h @@ -0,0 +1,36 @@ +#define BSIZE 256 + +typedef int token_t; +typedef unsigned char text; + +typedef struct PSI_Token { + token_t type; + unsigned line; + text text[1]; +} PSI_Token; + +typedef struct impl impl; +typedef struct decl decl; + +typedef struct PSI_Lexer { + FILE *fp; + char *fn; + struct { + size_t count; + decl **list; + } decl; + struct { + size_t count; + impl **list; + } impl; + size_t line; + text *cur, *tok, *lim, *eof, *ctx, *mrk, buf[BSIZE]; +} PSI_Lexer; + +PSI_Lexer *PSI_LexerInit(PSI_Lexer *L, const char *filename); +size_t PSI_LexerFill(PSI_Lexer *L, size_t n); +token_t PSI_LexerScan(PSI_Lexer *L); +void PSI_LexerDtor(PSI_Lexer *L); +void PSI_LexerFree(PSI_Lexer **L); + +PSI_Token *PSI_TokenAlloc(PSI_Lexer *L, token_t t); diff --git a/idl/lexer.re b/idl/lexer.re new file mode 100644 index 0000000..3d1c660 --- /dev/null +++ b/idl/lexer.re @@ -0,0 +1,213 @@ +#include +#include +#include +#include +#include + +#include "lexer.h" +#include "parser.h" +#include "types.h" + +#ifndef BSIZE +/*!max:re2c*/ +#define BSIZE 256 +#endif +#if BSIZE < YYMAXFILL +# error BSIZE must be greater than YYMAXFILL +#endif + +PSI_Token *PSI_TokenAlloc(PSI_Lexer *L, token_t t) +{ + PSI_Token *T; + size_t token_len = L->cur - L->tok; + + T = malloc(sizeof(*T) + token_len); + T->type = t; + T->line = L->line; + T->text[token_len] = 0; + memcpy(T->text, L->tok, token_len); + + return T; +} + +size_t PSI_LexerFill(PSI_Lexer *L, size_t n) +{ + // printf("+ Fill: n=%zu\n", n); + if (!n) { + L->cur = L->tok = L->lim = L->mrk = L->buf; + L->eof = NULL; + } + + if (!L->eof) { + size_t consumed = L->tok - L->buf; + size_t reserved = L->lim - L->tok; + size_t available = BSIZE - reserved; + size_t didread; + + if (consumed) { + memmove(L->buf, L->tok, reserved); + L->tok -= consumed; + L->cur -= consumed; + L->lim -= consumed; + L->mrk -= consumed; + } + + didread = fread(L->lim, 1, available, L->fp); + L->lim += didread; + if (didread < available) { + L->eof = L->lim; + } + + // printf("+ Fill: consumed=%zu reserved=%zu available=%zu didread=%zu\n", + // consumed, reserved, available, didread); + } + // printf("+ Fill: avail=%zu\n", L->lim - L->cur); + return L->lim - L->cur; +} + +void PSI_LexerDtor(PSI_Lexer *L) +{ + if (L->fp) { + fclose(L->fp); + } + if (L->fn) { + free(L->fn); + } + if (L->decl.list) { + size_t i; + + for (i = 0; i < L->decl.count; ++i) { + free_decl(L->decl.list[i]); + } + free(L->decl.list); + } + if (L->impl.list) { + size_t i; + + for (i = 0; i < L->impl.count; ++i) { + free_impl(L->impl.list[i]); + } + free(L->impl.list); + } + memset(L, 0, sizeof(*L)); +} + +void PSI_LexerFree(PSI_Lexer **L) +{ + if (*L) { + PSI_LexerDtor(*L); + free(*L); + *L = NULL; + } +} + +PSI_Lexer *PSI_LexerInit(PSI_Lexer *L, const char *filename) +{ + FILE *fp = fopen(filename, "r"); + + if (!fp) { + perror(filename); + return NULL; + } + + if (!L) { + L = malloc(sizeof(*L)); + } + memset(L, 0, sizeof(*L)); + + L->fp = fp; + L->fn = strdup(filename); + L->line = 1; + + PSI_LexerFill(L, 0); + + return L; +} + + +token_t PSI_LexerScan(PSI_Lexer *L) +{ + for (;;) { + L->tok = L->cur; + /*!re2c + re2c:indent:top = 2; + re2c:define:YYCTYPE = "unsigned char"; + re2c:define:YYCURSOR = L->cur; + re2c:define:YYLIMIT = L->lim; + re2c:define:YYMARKER = L->mrk; + re2c:define:YYFILL = "{ if (!PSI_LexerFill(L,@@)) return -1; }"; + re2c:yyfill:parameter = 0; + + B = [^a-zA-Z0-9_]; + W = [a-zA-Z0-9_]; + NAME = W+; + NSNAME = NAME ("\\" NAME)+; + NULL = 'NULL'; + MIXED = 'mixed'; + VOID = 'void'; + BOOL = 'bool'; + INT = 'int'; + FLOAT = 'float'; + DOUBLE = 'double'; + SINT8 = 'sint8'; + UINT8 = 'uint8'; + STRING = 'string'; + ARRAY = 'array'; + FUNCTION = 'function'; + LET = 'let'; + SET = 'set'; + RET = 'ret'; + STRVAL = 'strval'; + INTVAL = 'intval'; + FLOATVAL = 'floatval'; + BOOLVAL = 'boolval'; + TO_STRING = 'to_string'; + TO_INT = 'to_int'; + TO_FLOAT = 'to_float'; + TO_BOOL = 'to_bool'; + + "#" .* "\n" { ++L->line; return PSI_T_COMMENT;} + "(" {return PSI_T_LPAREN;} + ")" {return PSI_T_RPAREN;} + ";" {return PSI_T_EOS;} + "," {return PSI_T_COMMA;} + ":" {return PSI_T_COLON;} + "{" {return PSI_T_LCURLY;} + "}" {return PSI_T_RCURLY;} + "." {return PSI_T_DOT;} + "=" {return PSI_T_EQUALS;} + "$" {return PSI_T_DOLLAR;} + "*" {return PSI_T_POINTER;} + "&" {return PSI_T_REFERENCE;} + [\r\n] { ++L->line; continue; } + [\t ]+ { continue; } + NULL {return PSI_T_NULL;} + MIXED {return PSI_T_MIXED;} + VOID {return PSI_T_VOID;} + BOOL {return PSI_T_BOOL;} + INT {return PSI_T_INT;} + FLOAT {return PSI_T_FLOAT;} + DOUBLE {return PSI_T_DOUBLE;} + SINT8 {return PSI_T_SINT8;} + UINT8 {return PSI_T_UINT8;} + STRING {return PSI_T_STRING;} + ARRAY {return PSI_T_ARRAY;} + FUNCTION {return PSI_T_FUNCTION;} + LET {return PSI_T_LET;} + SET {return PSI_T_SET;} + RET {return PSI_T_RET;} + STRVAL {return PSI_T_STRVAL;} + INTVAL {return PSI_T_INTVAL;} + FLOATVAL {return PSI_T_FLOATVAL;} + BOOLVAL {return PSI_T_BOOLVAL;} + TO_STRING {return PSI_T_TO_STRING;} + TO_INT {return PSI_T_TO_INT;} + TO_FLOAT {return PSI_T_TO_FLOAT;} + TO_BOOL {return PSI_T_TO_BOOL;} + [0-9] {return PSI_T_DIGIT;} + NSNAME {return PSI_T_NSNAME;} + NAME {return PSI_T_NAME;} + */ + } + return -1; +} diff --git a/idl/main.c b/idl/main.c new file mode 100644 index 0000000..6732b7d --- /dev/null +++ b/idl/main.c @@ -0,0 +1,48 @@ +#include +#include +#include +#include "lexer.h" +#include "parser.h" + +static volatile int TRACE; + +static void loop(PSI_Lexer *L, void *P) +{ + token_t t; + PSI_Token *T = NULL; + + if (TRACE) { + PSI_ParserTrace(stdout, "> "); + } + + while (-1 != (t = PSI_LexerScan(L))) { + T = PSI_TokenAlloc(L, t); + + if (TRACE) { + printf("# Token: <%s>(%d)\n", T->text, t); + } + + PSI_Parser(P, t, T, L); + } + PSI_Parser(P, 0, T, L); +} + +int main(int argc, char *argv[]) +{ + PSI_Lexer L; + void *P = PSI_ParserAlloc(malloc); + + TRACE = !!getenv("TRACE"); + + if (!PSI_LexerInit(&L, argv[1])) { + perror("Failed to init lexer"); + return 1; + } + + loop(&L, P); + + PSI_ParserFree(P, free); + PSI_LexerDtor(&L); + + return 0; +} diff --git a/idl/parser.y b/idl/parser.y new file mode 100644 index 0000000..74433f9 --- /dev/null +++ b/idl/parser.y @@ -0,0 +1,272 @@ +%include { +#include +#include +#include +#include "lexer.h" +#include "parser.h" +#include "types.h" +} + +%name PSI_Parser +%token_prefix PSI_T_ +%token_type {PSI_Token *} +%token_destructor {free($$);} +%extra_argument {PSI_Lexer *L} +%syntax_error { + printf("ERROR: Syntax error on line %zu in '%s': '%s...'\n", L->line, L->fn, L->tok); + exit(1); +} + +file ::= blocks. + +blocks ::= block. +blocks ::= blocks block. + +block ::= decl(decl_). { + L->decl.list = realloc(L->decl.list, ++L->decl.count * sizeof(*L->decl.list)); + L->decl.list[L->decl.count-1] = decl_; +} +block ::= impl(impl_). { + L->impl.list = realloc(L->impl.list, ++L->impl.count * sizeof(*L->impl.list)); + L->impl.list[L->impl.count-1] = impl_; +} +block ::= COMMENT. + +%type decl {decl*} +decl(decl) ::= decl_arg(func) LPAREN decl_args(args) RPAREN EOS. { + decl = init_decl(func, args); +} +%type decl_var {decl_var*} +decl_var(var) ::= NAME(T). { + var = init_decl_var(T->text, 0); + free(T); +} +decl_var(var) ::= pointers(p) NAME(T). { + var = init_decl_var(T->text, p); + free(T); +} + +%type decl_vars {decl_vars*} +decl_vars(vars) ::= decl_var(var). { + vars = init_decl_vars(var); +} +decl_vars(vars) ::= decl_vars(vars_) COMMA decl_var(var). { + vars = add_decl_var(vars_, var); +} + +%type decl_arg {decl_arg*} +decl_arg(arg) ::= decl_type(type) decl_var(var). { + arg = init_decl_arg(type, var); +} + +%type decl_args {decl_args*} +decl_args(args) ::= decl_arg(arg). { + args = init_decl_args(arg); +} +decl_args(args) ::= decl_args(args_) COMMA decl_arg(arg). { + args = add_decl_arg(args_, arg); +} + +%type decl_type {decl_type*} +decl_type(type_) ::= VOID(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= INT(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= FLOAT(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= DOUBLE(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= SINT8(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} +decl_type(type_) ::= UINT8(T). { + type_ = init_decl_type(T->type, T->text); + free(T); +} + +%type impl {impl*} +impl(impl) ::= impl_func(func) LCURLY impl_stmts(stmts) RCURLY. { + impl = init_impl(func, stmts); +} + +%type impl_func {impl_func*} +impl_func(func) ::= FUNCTION NSNAME(NAME) LPAREN impl_args(args) RPAREN COLON impl_type(type). { + func = init_impl_func(NAME->text, args, type); + free(NAME); +} + +%type impl_def_val {impl_def_val*} +impl_def_val(def) ::= NULL. { + /* FIXME */ + def = init_impl_def_val(); +} +impl_def_val(def) ::= number. { + /* FIXME */ + def = init_impl_def_val(); +} + +%type impl_var {impl_var*} +impl_var(var) ::= DOLLAR NAME(T). { + var = init_impl_var(T->text, 0); + free(T); +} +impl_var(var) ::= REFERENCE DOLLAR NAME(T). { + var = init_impl_var(T->text, 1); + free(T); +} + +%type impl_arg {impl_arg*} +impl_arg(arg) ::= impl_type(type) impl_var(var). { + arg = init_impl_arg(type, var, NULL); +} +impl_arg(arg) ::= impl_type(type) impl_var(var) EQUALS impl_def_val(def). { + arg = init_impl_arg(type, var, def); +} + +%type impl_args {impl_args*} +impl_args(args) ::= impl_arg(arg). { + args = init_impl_args(arg); +} +impl_args(args) ::= impl_args(args_) COMMA impl_arg(arg). { + args = add_impl_arg(args_, arg); +} + +%type impl_stmts {impl_stmts*} +impl_stmts(stmts) ::= impl_stmt(stmt). { + stmts = init_impl_stmts(stmt); +} +impl_stmts(stmts) ::= impl_stmts(stmts_) impl_stmt(stmt). { + stmts = add_impl_stmt(stmts_, stmt); +} + +%type impl_stmt {impl_stmt*} +impl_stmt(stmt) ::= let_stmt(let). { + stmt = init_impl_stmt(PSI_T_LET, let); +} +impl_stmt(stmt) ::= set_stmt(set). { + stmt = init_impl_stmt(PSI_T_SET, set); +} +impl_stmt(stmt) ::= ret_stmt(ret). { + stmt = init_impl_stmt(PSI_T_RET, ret); +} + +%type let_stmt {let_stmt*} +let_stmt(let) ::= LET decl_var(var) EQUALS let_value(val) EOS. { + let = init_let_stmt(var, val); +} + +%type let_value {let_value*} +let_value(val) ::= let_func(func) LPAREN impl_var(var) RPAREN. { + val = init_let_value(func, var); +} +let_value(val) ::= let_reference_null_pointer. { + val = init_let_value(NULL, NULL); +} + +let_reference_null_pointer ::= REFERENCE NULL. + +%type let_func {let_func*} +let_func(func) ::= STRVAL(T). { + func = init_let_func(T->type, T->text); + free(T); +} +let_func(func) ::= INTVAL(T). { + func = init_let_func(T->type, T->text); + free(T); +} +let_func(func) ::= FLOATVAL(T). { + func = init_let_func(T->type, T->text); + free(T); +} +let_func(func) ::= BOOLVAL(T). { + func = init_let_func(T->type, T->text); + free(T); +} + +%type set_stmt {set_stmt*} +set_stmt(set) ::= SET impl_var(var) EQUALS set_value(val) EOS. { + set = init_set_stmt(var, val); +} + +%type set_value {set_value*} +set_value(val) ::= set_func(func) LPAREN decl_vars(vars) RPAREN. { + val = init_set_value(func, vars); +} + +%type set_func {set_func*} +set_func(func) ::= TO_STRING(T). { + func = init_set_func(T->type, T->text); + free(T); +} +set_func(func) ::= TO_INT(T). { + func = init_set_func(T->type, T->text); + free(T); +} +set_func(func) ::= TO_FLOAT(T). { + func = init_set_func(T->type, T->text); + free(T); +} +set_func(func) ::= TO_BOOL(T). { + func = init_set_func(T->type, T->text); + free(T); +} + +%type ret_stmt {ret_stmt*} +ret_stmt(ret) ::= RET set_func(func) LPAREN decl_var(var) RPAREN EOS. { + ret = init_ret_stmt(func, var); +} + +%type impl_type {impl_type*} +impl_type(type_) ::= VOID(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= MIXED(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= BOOL(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= INT(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= FLOAT(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= STRING(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} +impl_type(type_) ::= ARRAY(T). { + type_ = init_impl_type(T->type, T->text); + free(T); +} + +digits ::= DIGIT. +digits ::= digits DIGIT. +decimals ::= digits DOT digits. +decimals ::= DOT digits. +decimals ::= digits DOT. +number ::= digits. +number ::= PLUS digits. +number ::= MINUS digits. +number ::= decimals. +number ::= MINUS decimals. +number ::= PLUS decimals. + +%type pointers {unsigned} +pointers(p) ::= POINTER. {++p;} +pointers(p) ::= pointers(P) POINTER. {p = ++P;} diff --git a/idl/types.h b/idl/types.h new file mode 100644 index 0000000..b57f1db --- /dev/null +++ b/idl/types.h @@ -0,0 +1,471 @@ + +typedef struct decl_type { + text *name; + token_t type; +} decl_type; + +static inline decl_type *init_decl_type(token_t type, text *name) { + decl_type *t = malloc(sizeof(*t)); + t->type = type; + t->name = (text *) strdup((const char *) name); + return t; +} + +static inline void free_decl_type(decl_type *type) { + free(type->name); + free(type); +} + +typedef struct decl_var { + text *name; + unsigned pointer_level; +} decl_var; + +static inline decl_var *init_decl_var(text *name, unsigned pl) { + decl_var *v = malloc(sizeof(*v)); + v->name = (text *) strdup((const char *) name); + v->pointer_level = pl; + return v; +} + +static inline void free_decl_var(decl_var *var) { + free(var->name); + free(var); +} + +typedef struct decl_arg { + decl_type *type; + decl_var *var; +} decl_arg; + +static inline decl_arg *init_decl_arg(decl_type *type, decl_var *var) { + decl_arg *arg = malloc(sizeof(*arg)); + arg->type = type; + arg->var = var; + return arg; +} + +static inline void free_decl_arg(decl_arg *arg) { + free_decl_type(arg->type); + free_decl_var(arg->var); + free(arg); +} + +typedef struct decl_vars { + decl_var **vars; + size_t count; +} decl_vars; + +static inline decl_vars *init_decl_vars(decl_var *var) { + decl_vars *vars = malloc(sizeof(*vars)); + vars->count = 1; + vars->vars = malloc(sizeof(*vars->vars)); + vars->vars[0] = var; + return vars; +} + +static inline decl_vars *add_decl_var(decl_vars *vars, decl_var *var) { + vars->vars = realloc(vars->vars, ++vars->count * sizeof(*vars->vars)); + vars->vars[vars->count-1] = var; + return vars; +} + +static inline void free_decl_vars(decl_vars *vars) { + size_t i; + + for (i = 0; i < vars->count; ++i) { + free_decl_var(vars->vars[i]); + } + free(vars->vars); + free(vars); +} + +typedef struct decl_args { + decl_arg **args; + size_t count; +} decl_args; + +static inline decl_args *init_decl_args(decl_arg *arg) { + decl_args *args = malloc(sizeof(*args)); + args->count = 1; + args->args = malloc(sizeof(*args->args)); + args->args[0] = arg; + return args; +} + +static inline decl_args *add_decl_arg(decl_args *args, decl_arg *arg) { + args->args = realloc(args->args, ++args->count * sizeof(*args->args)); + args->args[args->count-1] = arg; + return args; +} + +static inline void free_decl_args(decl_args *args) { + size_t i; + + for (i = 0; i < args->count; ++i) { + free_decl_arg(args->args[i]); + } + free(args->args); + free(args); +} + +typedef struct decl { + decl_arg *func; + decl_args *args; +} decl; + +static inline decl* init_decl(decl_arg *func, decl_args *args) { + decl *d = malloc(sizeof(*d)); + d->func = func; + d->args = args; + return d; +} + +static inline void free_decl(decl *d) { + free_decl_arg(d->func); + free_decl_args(d->args); + free(d); +} + +typedef struct impl_type { + text *name; + token_t type; +} impl_type; + +static inline impl_type *init_impl_type(token_t type, text *name) { + impl_type *t = malloc(sizeof(*t)); + + t->type = type; + t->name = (text *) strdup((const char *) name); + return t; +} + +static inline void free_impl_type(impl_type *type) { + free(type->name); + free(type); +} + +typedef struct impl_var { + text *name; + unsigned reference:1; +} impl_var; + +static inline impl_var *init_impl_var(text *name, int is_reference) { + impl_var *var = malloc(sizeof(*var)); + var->name = (text *) strdup((const char *) name); + var->reference = is_reference; + return var; +} + +static inline void free_impl_var(impl_var *var) { + free(var->name); + free(var); +} + +typedef struct impl_def_val { + token_t type; + union { + int64_t digits; + double decimals; + } v; + unsigned is_null:1; +} impl_def_val; + +static inline impl_def_val *init_impl_def_val() { + impl_def_val *def = malloc(sizeof(*def)); + def->type = 0; + def->is_null = 1; + return def; +} + +static inline void free_impl_def_val(impl_def_val *def) { + free(def); +} + +typedef struct impl_arg { + impl_type *type; + impl_var *var; + impl_def_val *def; +} impl_arg; + +static inline impl_arg *init_impl_arg(impl_type *type, impl_var *var, impl_def_val *def) { + impl_arg *arg = malloc(sizeof(*arg)); + arg->type = type; + arg->var = var; + arg->def = def; + return arg; +} + +static inline void free_impl_arg(impl_arg *arg) { + free_impl_type(arg->type); + free_impl_var(arg->var); + if (arg->def) { + free_impl_def_val(arg->def); + } + free(arg); +} + +typedef struct impl_args { + impl_arg **args; + size_t count; +} impl_args; + +static inline impl_args *init_impl_args(impl_arg *arg) { + impl_args *args = malloc(sizeof(*args)); + args->count = 1; + args->args = malloc(sizeof(*args->args)); + args->args[0] = arg; + return args; +} + +static inline impl_args *add_impl_arg(impl_args *args, impl_arg *arg) { + args->args = realloc(args->args, ++args->count * sizeof(*args->args)); + args->args[args->count-1] = arg; + return args; +} + +static inline void free_impl_args(impl_args *args) { + size_t i; + + for (i = 0; i < args->count; ++i) { + free_impl_arg(args->args[i]); + } + free(args->args); + free(args); +} + +typedef struct impl_func { + text *name; + impl_args *args; + impl_type *return_type; +} impl_func; + +static inline impl_func *init_impl_func(text *name, impl_args *args, impl_type *type) { + impl_func *func = malloc(sizeof(*func)); + func->name = (text *) strdup((const char *) name); + func->args = args; + func->return_type = type; + return func; +} + +static inline void free_impl_func(impl_func *f) { + free_impl_type(f->return_type); + free_impl_args(f->args); + free(f->name); + free(f); +} + +typedef struct let_func { + token_t type; + text *name; +} let_func; + +static inline let_func *init_let_func(token_t type, text *name) { + let_func *func = malloc(sizeof(*func)); + func->type = type; + func->name = (text *) strdup((const char *) name); + return func; +} + +static inline void free_let_func(let_func *func) { + free(func->name); + free(func); +} + +typedef struct let_value { + let_func *func; + impl_var *var; + unsigned null_pointer_ref:1; +} let_value; + +static inline let_value *init_let_value(let_func *func, impl_var *var) { + let_value *val = malloc(sizeof(*val)); + + if (!func || !var) { + val->null_pointer_ref = 1; + } else { + val->null_pointer_ref = 0; + } + val->func = func; + val->var = var; + + return val; +} + +static inline void free_let_value(let_value *val) { + if (val->func) { + free_let_func(val->func); + } + if (val->var) { + free_impl_var(val->var); + } + free(val); +} + +typedef struct let_stmt { + decl_var *var; + let_value *val; +} let_stmt; + +static inline let_stmt *init_let_stmt(decl_var *var, let_value *val) { + let_stmt *let = malloc(sizeof(*let)); + let->var = var; + let->val = val; + return let; +} + +static inline void free_let_stmt(let_stmt *stmt) { + free_decl_var(stmt->var); + free_let_value(stmt->val); + free(stmt); +} + +typedef struct set_func { + token_t type; + text *name; +} set_func; + +static inline set_func *init_set_func(token_t type, text *name) { + set_func *func = malloc(sizeof(*func)); + func->type = type; + func->name = (text *) strdup((const char *) name); + return func; +} + +static inline void free_set_func(set_func *func) { + free(func->name); + free(func); +} + +typedef struct set_value { + set_func *func; + decl_vars *vars; +} set_value; + +static inline set_value *init_set_value(set_func *func, decl_vars *vars) { + set_value *val = malloc(sizeof(*val)); + val->func = func; + val->vars = vars; + return val; +} + +static inline void free_set_value(set_value *val) { + free_set_func(val->func); + free_decl_vars(val->vars); + free(val); +} + +typedef struct set_stmt { + impl_var *var; + set_value *val; +} set_stmt; + +static inline set_stmt *init_set_stmt(impl_var *var, set_value *val) { + set_stmt *set = malloc(sizeof(*set)); + set->var = var; + set->val = val; + return set; +} + +static inline void free_set_stmt(set_stmt *set) { + free_impl_var(set->var); + free_set_value(set->val); + free(set); +} + +typedef struct ret_stmt { + set_func *func; + decl_var *decl; +} ret_stmt; + +static inline ret_stmt *init_ret_stmt(set_func *func, decl_var *decl) { + ret_stmt *ret = malloc(sizeof(*ret)); + ret->func = func; + ret->decl = decl; + return ret; +} + +static inline void free_ret_stmt(ret_stmt *ret) { + free_set_func(ret->func); + free_decl_var(ret->decl); + free(ret); +} + +typedef struct impl_stmt { + token_t type; + union { + let_stmt *let; + set_stmt *set; + ret_stmt *ret; + void *ptr; + } s; +} impl_stmt; + +static inline impl_stmt *init_impl_stmt(token_t type, void *ptr) { + impl_stmt *stmt = malloc(sizeof(*stmt)); + stmt->type = type; + stmt->s.ptr = ptr; + return stmt; +} + +static inline void free_impl_stmt(impl_stmt *stmt) { + switch (stmt->type) { + case PSI_T_LET: + free_let_stmt(stmt->s.let); + break; + case PSI_T_SET: + free_set_stmt(stmt->s.set); + break; + case PSI_T_RET: + free_ret_stmt(stmt->s.ret); + break; + } + free(stmt); +} + +typedef struct impl_stmts { + impl_stmt **stmts; + size_t count; +} impl_stmts; + +static inline impl_stmts *init_impl_stmts(impl_stmt *stmt) { + impl_stmts *stmts = malloc(sizeof(*stmts)); + stmts->count = 1; + stmts->stmts = malloc(sizeof(*stmts->stmts)); + stmts->stmts[0] = stmt; + return stmts; +} + +static inline impl_stmts *add_impl_stmt(impl_stmts *stmts, impl_stmt *stmt) { + stmts->stmts = realloc(stmts->stmts, ++stmts->count * sizeof(*stmts->stmts)); + stmts->stmts[stmts->count-1] = stmt; + return stmts; +} + +static inline void free_impl_stmts(impl_stmts *stmts) { + size_t i; + + for (i = 0; i < stmts->count; ++i) { + free_impl_stmt(stmts->stmts[i]); + } + free(stmts->stmts); + free(stmts); +} + +typedef struct impl { + impl_func *func; + impl_stmts *stmts; +} impl; + +static inline impl *init_impl(impl_func *func, impl_stmts *stmts) { + impl *i = malloc(sizeof(*i)); + i->func = func; + i->stmts = stmts; + return i; +} + +static inline void free_impl(impl *impl) { + free_impl_func(impl->func); + free_impl_stmts(impl->stmts); + free(impl); +}