aboutsummaryrefslogtreecommitdiff
path: root/bootstrap/semchk.h
blob: 34d873e6e998193e0fabbbd3a2f8a609157765ab (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105

/*
 * Declarations for semantic checking functions.
 *
 * Copyright © 2025 Samuel Lidén Borell <samuel@kodafritt.se>
 *
 * 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