/* * Functions for constructing/accessing the Abstract Syntax Tree. * * Copyright © 2025 Samuel Lidén Borell * * SPDX-License-Identifier: EUPL-1.2+ OR LGPL-2.1-or-later */ #include #include #include "compiler.h" #include "token.h" struct Module *module, *modules; struct Type *current_type; struct Func *current_func; static struct Type **type_nextptr, **inner_type_nextptr; static struct Func **func_nextptr; static struct Func **type_func_nextptr, **innertype_func_nextptr; static struct Func **type_ctor_nextptr, **innertype_ctor_nextptr; /* TODO should constants in "utility files" be allowed? */ /*static struct Var **var_nextptr;*/ static struct Var **type_var_nextptr, **innertype_var_nextptr; struct ExprString *string_constants = NULL; static struct ExprString *empty_string = NULL; static unsigned next_string_const_id = 1; void module_start(void) { struct Module *mod = malloc(sizeof(struct Module)); NO_NULL(mod); mod->types = NULL; mod->funcs = NULL; /*mod->consts = NULL;*/ mod->types_list = NULL; mod->funcs_list = NULL; /*mod->consts_list = NULL;*/ mod->next = modules; modules = mod; module = mod; current_type = NULL; current_func = NULL; type_nextptr = &module->types_list; func_nextptr = &module->funcs_list; /*var_nextptr = &module->consts_list;*/ } struct Type *map_named_type(const char *name, size_t len) { struct TreeNode **root; struct Type *t; if (current_type && len == current_type->ident.node.length && !memcmp(name, current_type->ident.node.name, len)) { assert(current_type->ident.node.is_defined); return current_type; } /* If inside an type definition, then the sought type might be an inner/nested type defined later within the type being defined. So in that case we ONLY search among the inner types at this point, and only at the end we can search among the top-level types. */ root = (current_type ? ¤t_type->inner_types : &module->types); t = (struct Type *)tree_insert_str(root, name, len, NULL, sizeof(struct Type)); if (!t->ident.node.is_new) { return t; } t->outer = current_type; t->funcs = NULL; t->funcs_list = NULL; t->ctors = NULL; t->ctors_list = NULL; t->ctor_default = NULL; t->inner_types = NULL; t->inner_types_list = NULL; t->vars = NULL; t->vars_list = NULL; t->next = NULL; if (current_type) { *inner_type_nextptr = t; inner_type_nextptr = &t->next; } else { *type_nextptr = t; type_nextptr = &t->next; } return t; } void srcloc_init(struct SourceLocation *srcloc) { assert(current_filename != NULL); srcloc->filename = current_filename; srcloc->line = current_line; } void type_start(const char *name, size_t len) { struct Type *t; t = map_named_type(name, len); if (t->ident.node.is_defined) { error("Duplicate type name"); } srcloc_init(&t->ident.srcloc); t->ident.node.is_defined = true; if (current_type) { innertype_func_nextptr = &t->funcs_list; innertype_ctor_nextptr = &t->ctors_list; innertype_var_nextptr = &t->vars_list; } else { type_func_nextptr = &t->funcs_list; type_ctor_nextptr = &t->ctors_list; type_var_nextptr = &t->vars_list; inner_type_nextptr = &t->inner_types_list; } current_type = t; } static void add_default_constructor(void) { func_start("new", 3, FK_CONSTRUCTOR); func_end(); } void type_end(void) { if (!current_type->ctors) { add_default_constructor(); } current_type = current_type->outer; innertype_func_nextptr = NULL; innertype_ctor_nextptr = NULL; innertype_var_nextptr = NULL; if (!current_type) { type_func_nextptr = NULL; type_ctor_nextptr = NULL; type_var_nextptr = NULL; } } static void set_func_defaults(struct Func *f) { f->class_ = current_type; f->params = NULL; f->returns = NULL; f->vardecls = NULL; f->code = NULL; f->section_first = NULL; f->section_by_name = NULL; f->is_noreturn = false; f->is_modifying = false; f->is_constructor = false; f->num_params = 0; f->num_returns = 0; f->next = NULL; } static void register_func(struct Func *f) { assert(!f->is_constructor); if (current_type && current_type->outer) { *innertype_func_nextptr = f; innertype_func_nextptr = &f->next; } else if (current_type) { *type_func_nextptr = f; type_func_nextptr = &f->next; } else { *func_nextptr = f; func_nextptr = &f->next; } } static void register_ctor(struct Func *f) { assert(f->is_constructor); if (current_type->outer) { *innertype_ctor_nextptr = f; innertype_ctor_nextptr = &f->next; } else { *type_ctor_nextptr = f; type_ctor_nextptr = &f->next; } } struct Func *map_named_func(const char *name, size_t len, enum FuncKind kind) { struct Func *f; struct TreeNode **root; if (kind == FK_CONSTRUCTOR) { assert(current_type != NULL); root = ¤t_type->ctors; } else { root = (current_type ? ¤t_type->funcs : &module->funcs); } f = (struct Func *)tree_insert_str(root, name, len, NULL, sizeof(struct Func)); if (!f->ident.node.is_new) { return f; } set_func_defaults(f); if (kind == FK_CONSTRUCTOR) { f->is_constructor = true; f->is_modifying = true; } if (kind == FK_FUNC) { register_func(f); } else { register_ctor(f); } return f; } void func_start(const char *name, size_t len, enum FuncKind kind) { struct Func *f; f = map_named_func(name, len, kind); if (f->ident.node.is_defined) { error(kind == FK_FUNC ? "Duplicate function name" : "Duplicate constructor name"); } srcloc_init(&f->ident.srcloc); f->ident.node.is_defined = true; current_func = f; } void func_end(void) { current_func = NULL; } void toplevel_var_add(struct Var *var) { struct Var ***nextptr; if (current_type && current_type->outer) { nextptr = &innertype_var_nextptr; } else if (current_type) { nextptr = &type_var_nextptr; } else { /* TODO should constants in "utility files" be allowed? */ /*nextptr = &var_nextptr;*/ assert(0); } var->next = NULL; **nextptr = var; *nextptr = &var->next; } bool funcdefs_seen(void) { /* TODO should constants in "utility files" be allowed? */ /*if (!current_type) { return module->funcs != NULL; } else { return current_type->funcs != NULL; }*/ assert(current_type != NULL); return current_type->funcs != NULL; } struct Var *lookup_instance_var(const char *name, size_t len) { HashCode h; assert(current_type != NULL); assert(name != NULL); assert(len != 0); h = hash_str(name, len); return (struct Var *)tree_search(current_type->vars, h, len, name); } struct ExprString *register_string_literal(const char *string, size_t len) { if (len == 0 && empty_string) { return empty_string; } else { struct ExprString *es = malloc(sizeof(struct ExprString)); NO_NULL(es); es->next = string_constants; es->len = len; /* TODO unescape string */ es->s = (len != 0 ? dupmemz(string, len) : NULL); es->id = next_string_const_id++; string_constants = es; if (len == 0) { assert(empty_string == NULL); empty_string = es; } return es; } }