/* SPDX-License-Identifier: copyleft-next-0.3.1 */ /* Copyright 2023 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" /** Flags a scope can have. */ enum scope_flags { /** Scope is public, i.e. stuff defined in this scope should be made * visible to parent file scopes. */ SCOPE_PUBLIC = (1 << 0), /** Scope is file scope. */ SCOPE_FILE = (1 << 1), }; /** * 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; }; struct expanded { struct ast *node; struct type *types; struct ast *expd; struct expanded *next; }; struct type_defs { char *id; struct ast *type_def; struct type_defs *next; }; /** * Scope. * Responsible for keeping track of visibilities and * file context. */ struct scope { /** Parent scope, NULL if top scope. */ struct scope *parent; /** Scope flags. */ enum scope_flags flags; /** 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 expanded *expanded; struct visible *symbols; struct visible *macros; struct visible *types; struct visible *type_constructs; }; /** * 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); /** * Set scope flags. * * @param scope Scope to set flags for. * @param flags Flags to set in scope. */ void scope_set_flags(struct scope *scope, enum scope_flags flags); /** * Check if scope has flags active. * * @param scope Scope to check flags in. * @param flags Flags to check for. * @return \c 1 if flags are set, \c 0 if flags are unset. * @note All flags have to be set for the result to be \c 1. */ unsigned scope_flags(struct scope *scope, enum scope_flags flags); /** * 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); int scope_add_chain(struct scope *scope, char *id, struct ast *node); /** * 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); /** * Add macro to scope. * Propagates public macros up the file scope chain as references. * * @param scope Scope to add macro to. * @param macro Macro to add to scope. * @return \c 0 when succesful, non-zero otherwise. */ int scope_add_macro(struct scope *scope, struct ast *macro); /** * Add template to scope. * Propagates public templates up the file scope chain as references. * * @param scope Scope to add template to. * @param type_template Template to add to scope. * @return \c 0 when succesful, non-zero otherwise. */ int scope_add_trait(struct scope *scope, struct ast *trait); int scope_add_expd_struct(struct scope *scope, struct ast *def, struct type *types, struct ast *expanded); int scope_add_expd_chain(struct scope *scope, struct ast *def, struct type *types, struct ast *expanded); /** * 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 type with ID in \p scope. * @note Only looks in the current scope, so doesn't see anything outside * of it. See file_scope_find_type(). * * @param scope Scope to look in. * @param id ID of type to find. * @return Pointer to the AST node corresponding to \p id if found, * otherwise \c NULL. */ struct ast *scope_find_type(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 macro with ID in \p scope. * @note Only looks in the current scope, so doesn't see anything outside * of it. See file_scope_find_macro(). * * @param scope Scope to look in. * @param id ID of macro to find. * @return Pointer to the AST node corresponding to \p id if found, * otherwise \c NULL. */ struct ast *scope_find_macro(struct scope *scope, char *id); /** * Find an alias with ID in \p scope. * @note Only looks in the current scope, so doesn't see anything outside * of it. See file_scope_find_alias(). * * @param scope Scope to look in. * @param id ID of alias to find. * @return Pointer to the AST node corresponding to \p id if found, * otherwise \c NULL. */ struct ast *scope_find_alias(struct scope *scope, char *id); /** * Find a template with ID in \p scope. * @note Only looks in the current scope, so doesn't see anything outside * of it. See file_scope_find_template(). * * @param scope Scope to look in. * @param id ID of template to fetch. * @return Pointer to the AST node corresponding to \p id if found, * otherwise \c NULL. */ struct ast *scope_find_trait(struct scope *scope, char *id); struct ast *scope_find_expd_struct(struct scope *scope, struct ast *def, struct type *types); /** * 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 type 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_type(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); /** * Find a macro with ID visible to \p scope. * * @param scope Scope to look in. * @param id ID of macro to find. * @return Pointer to the AST node corresponding to \p id if found, * otherwise \c NULL. */ struct ast *file_scope_find_macro(struct scope *scope, char *id); /** * Find a alias with ID visible to \p scope. * * @param scope Scope to look in. * @param id ID of alias to find. * @return Pointer to the AST node corresponding to \p id if found, * otherwise \c NULL. */ struct ast *file_scope_find_alias(struct scope *scope, char *id); /** * Find a template with ID visible to \p scope. * * @param scope Scope to look in. * @param id ID of template to find. * @return Pointer to the AST node corresponding to \p id if found, * otherwise \c NULL. */ struct ast *file_scope_find_trait(struct scope *scope, char *id); struct ast *file_scope_find_expd_struct(struct scope *scope, struct ast *def, struct type *types); bool same_src(struct ast *a, struct ast *b); #define foreach_visible(iter, init) \ for (struct visible *iter = init; iter; iter = iter->next) #define foreach_expanded(iter, init) \ for (struct expanded *iter = init; iter; iter = iter->next) #endif /* SCOPE_H */