/* * Declarations for semantic checking functions. * * Copyright © 2025 Samuel Lidén Borell * * SPDX-License-Identifier: EUPL-1.2+ OR LGPL-2.1-or-later */ #ifndef SLUL_SEMCHK_H #define SLUL_SEMCHK_H #include "compiler.h" /** * Binds types of the subexpressions in an expression, and also performs * type checks. If the typeref parameter is NULL, then the expr can have * any result type (but it must have known and non-ambiguous type), and * if not NULL, then it must be assignment-compatible to the given * typref. */ void typecheck_expr(const struct TypeRef *typeref, struct Expr *expr); /** * Determines the type of the expression. * * The return value must be free'd by the caller, with typeref_free(). */ struct TypeRef *determine_expr_typeref(struct Expr *expr); /** * Type checks a function call expression. Called by typecheck_expr(). * * The typescope parameter is used to look up type-scoped identifiers, * i.e. constructors in this case. */ struct TypeRef funccall_check(struct Expr *e, struct Type *typescope); enum TypeCompatMode { TC_ASSIGN, /**< Assignment a=b */ TC_COMPARE /**< Comparison */ }; /** * Checks whether two types are compatible. */ void check_type_compat( const struct TypeRef *tr_a, const struct TypeRef *tr_b, enum TypeCompatMode mode); /** Returns true if a range can only contain one specific value, i.e. that min==max. */ bool is_const(const struct Range *range); /** Returns true if an expression is constant */ bool is_expr_const(const struct Expr *expr); /** Determines the range of an arithmetic operation given the ranges of the inputs */ struct Range arithmetic_op_range( enum ExprKind operation, const struct Range *a, const struct Range *b); /** The kind of scope that is being exited */ enum ScopeLeaveKind { /** Leaving a control statement where exactly one block is executed: - `if`/`elif` with `else`, - `switch` with `default` */ SLK_NORMAL, /** Leaving a control statement that might not be executed - `if` without `else` - `switch` without default and where not all values are covered. */ SLK_NON_EXHAUSTIVE, /** Leaving a loop, that might be executed 0, 1 or multiple times. */ SLK_LOOP }; /** Semantic checking at the start of a function */ void varstate_function_start(void); /** Semantic checking when a variable scope is entered */ void varstate_enter_scope(void); /** Semantic checking when a variable scope is exited */ void varstate_leave_scope(enum ScopeLeaveKind); /** Semantic checking at `else`/`case` */ void varstate_else(void); /** Semantic checking at `return` */ void varstate_return(void); /** Semantic checking at `break` */ void varstate_break(void); /** Semantic checking at `continue` */ void varstate_continue(void); /** Semantic checking when a variable is declared */ void varstate_mark_declared(struct Var *var); /** Semantic checking when a variable is assigned */ void varstate_mark_assigned(struct Var *var); /** Checks that the given variable is assigned at this point in semantic checking. */ void varstate_require_assigned(const struct Var *var); /** Checks that the given variable may be assigned at this point in semantic checking. */ void varstate_require_modifiable(struct Var *var); /** Reports a warning if the current statement is unreachable. */ void varstate_warn_if_unreachable(void); #endif