33 static const size_t kImportTags[] = {eCtuTagImports, eCtuTagTypes};
34 static const size_t kDeclTags[] = {eCtuTagValues, eCtuTagFunctions};
36 static const search_t kSearchImports = {
38 .count =
sizeof(kImportTags) /
sizeof(
size_t),
41 static const search_t kSearchDecl = {
43 .count =
sizeof(kDeclTags) /
sizeof(
size_t),
46 static bool is_public(
const tree_t *decl)
55 bool is_imported =
false;
79 if (
tree_is(ns, eTreeDeclModule))
88 if (is_imported && !is_public(decl))
91 "cannot access non-public declaration `%s`", name);
94 if (
tree_is(decl, eTreeDeclFunction) ||
tree_is(decl, eTreeDeclParam))
111 const char *expr_kind,
tree_t *expr)
122 if (
tree_is(result, eTreeError))
132 if (!
tree_is(type, eTreeTypeBool))
134 return tree_raise(expr->
node, sema->
reports, &kEvent_InvalidLiteralType,
"invalid type `%s` for boolean literal",
140 return verify_expr_type(sema, eTreeTypeBool, type,
"boolean literal", it);
147 const tree_t *type = implicit_type
151 if (!
tree_is(type, eTreeTypeDigit))
153 return tree_raise(expr->
node, sema->
reports, &kEvent_InvalidLiteralType,
"invalid type `%s` for integer literal",
159 return verify_expr_type(sema, eTreeTypeDigit, type,
"integer literal", it);
180 if (implicit_type != NULL)
191 if (!
tree_is(type, eTreeTypeDigit))
193 return tree_raise(expr->
node, sema->
reports, &kEvent_InvalidLiteralType,
"invalid type `%s` for char literal",
199 return tree_raise(expr->
node, sema->
reports, &kEvent_InvalidLiteralType,
"char literal must contain at least 1 code point");
203 mpz_init_set_ui(value, expr->
text[0]);
206 return verify_expr_type(sema, eTreeTypeDigit, type,
"char literal", it);
211 bool needs_load =
false;
212 return sema_decl_name(sema, expr->
node, expr->
path, &needs_load);
217 bool needs_load =
true;
219 tree_t *name = sema_decl_name(sema, expr->
node, expr->
path, &needs_load);
221 if (!
tree_is(name, eTreeDeclFunction))
234 if (implicit_type != NULL)
265 return tree_error(expr->
node, &kEvent_InvalidBinaryOperation,
"invalid binary");
281 if (
tree_is(inner, eTreeError))
283 return tree_error(expr->
node, &kEvent_InvalidUnaryOperation,
"invalid unary");
294 "cannot apply unary `%s` to non-digit type `%s`",
303 "cannot apply unary `%s` to non-bool type `%s`",
314 static const tree_t *get_param_checked(
const vector_t *params,
size_t i)
328 if (
tree_is(callee, eTreeError))
334 if (
tree_is(type, eTreeTypeReference))
344 for (
size_t i = 0; i < len; i++)
346 const tree_t *ty = get_param_checked(params, i);
358 if (
tree_is(ty, eTreeTypeReference))
369 if (
tree_is(inner, eTreeError))
375 mpz_init_set_ui(zero, 0);
379 const tree_t *ty = get_ptr_type(type);
380 if (!
tree_is(ty, eTreeTypePointer))
383 "cannot dereference non-pointer type `%s` inside lvalue",
tree_to_string(ty));
393 if (
tree_is(inner, eTreeError))
404 if (
tree_is(inner, eTreeError))
409 if (
tree_is(inner, eTreeDeclLocal))
418 if (
tree_is(type, eTreeTypeReference))
427 static bool can_index_type(
const tree_t *ty)
431 case eTreeTypePointer:
432 case eTreeTypeArray:
return true;
434 default:
return false;
450 if (!can_index_type(ty))
508 if (!
tree_is(ty, eTreeTypeStruct))
511 "cannot access field of non-struct type `%s`",
tree_to_string(ty));
515 if (field_tmp == NULL)
521 *
object = object_tmp;
531 tree_t *type = sema_field_common(sema, expr, &
object, &field);
544 tree_t *type = sema_field_common(sema, expr, &
object, &field);
561 "cannot indirectly access field of non-pointer-to-struct type `%s`",
584 "cannot indirectly access field of non-pointer-to-struct type `%s`",
604 if (implicit_type == NULL)
606 return tree_raise(expr->
node, reports, &kEvent_InvalidInitializer,
"cannot infer type of initializer");
609 if (!
tree_is(implicit_type, eTreeTypeStruct))
611 return tree_raise(expr->
node, reports, &kEvent_InvalidInitializer,
"cannot initialize non-struct type `%s`",
620 .quals = eQualMutable
629 for (
size_t i = 0; i < len; i++)
638 "field `%s` not found in struct `%s`", element->
field,
654 for (
size_t i = 0; i < field_count; i++)
691 "cannot get offset of non-aggregate type `%s`",
tree_to_string(ty)
719 default:
CT_NEVER(
"invalid lvalue-expr kind %d", expr->
kind);
727 const tree_t *inner = implicit_type == NULL
758 default:
CT_NEVER(
"invalid rvalue-expr kind %d", expr->
kind);
767 CTASSERT(value != NULL || type != NULL);
769 const tree_t *actual_type = type != NULL
777 .quals = stmt->
mut ? eQualMutable : eQualConst,
800 [eCtuTagFunctions] = 4,
806 for (
size_t i = 0; i < len; i++)
838 if (stmt->
name != NULL)
875 if (stmt->
label == NULL)
883 return tree_raise(stmt->
node, ctx->
reports, &kEvent_InvalidControlFlow,
"loop control statement not within a loop");
898 tree_t *loop = get_label_loop(sema, stmt);
904 tree_t *loop = get_label_loop(sema, stmt);
933 "expression statement may have no effect");
946 case eTreeTypePointer:
960 case eTreeTypePointer:
return type->
ptr;
961 case eTreeTypeReference:
CT_NEVER(
"cannot resolve storage type of reference");
963 default:
return type;
972 case eTreeTypePointer:
return type;
974 case eTreeTypeReference:
CT_NEVER(
"cannot resolve decl type of reference");
CT_TREE_API tree_t * tree_builtin_alignof(const node_t *node, const tree_t *type, const tree_t *align_type)
CT_TREE_API tree_t * tree_builtin_offsetof(const node_t *node, const tree_t *type, const tree_t *field, const tree_t *offset_type)
CT_BEGIN_API CT_TREE_API tree_t * tree_builtin_sizeof(const node_t *node, const tree_t *type, const tree_t *size_type)
CT_PUREFN CT_TREE_API const node_t * tree_get_node(const tree_t *tree)
CT_PUREFN CT_TREE_API tree_kind_t tree_get_kind(const tree_t *tree)
CT_PUREFN CT_TREE_API const char * tree_get_name(const tree_t *tree)
CT_PUREFN CT_TREE_API const tree_t * tree_get_type(const tree_t *tree)
CT_PUREFN CT_TREE_API bool tree_is(const tree_t *self, tree_kind_t kind)
CT_TREE_API const char * tree_to_string(const tree_t *self)
CT_PUREFN CT_TREE_API tree_t * tree_ty_get_case(const tree_t *self, const char *name)
CT_PUREFN CT_TREE_API const tree_t * tree_fn_get_return(const tree_t *self)
CT_TREE_API const tree_t * tree_get_storage_type(const tree_t *self)
CT_PUREFN CT_TREE_API tree_t * tree_ty_get_field(const tree_t *self, const char *name)
CT_TREE_API const tree_attribs_t * tree_get_attrib(const tree_t *self)
CT_PUREFN CT_TREE_API const vector_t * tree_fn_get_params(const tree_t *self)
CT_PUREFN CT_TREE_API const tree_t * tree_ty_load_type(const tree_t *self)
get the type of a type after it has been loaded
void ctu_add_decl(tree_t *sema, ctu_tag_t tag, const char *name, tree_t *decl)
tree_t * ctu_get_int_type(digit_t digit, sign_t sign)
ctu_sema_t ctu_sema_nested(ctu_sema_t *parent, tree_t *sema, tree_t *decl, vector_t *block)
tree_t * ctu_get_char_type(void)
tree_t * ctu_get_loop(tree_t *sema, const char *name)
void ctu_set_current_loop(ctu_sema_t *sema, tree_t *loop)
tree_t * ctu_get_bool_type(void)
tree_t * ctu_current_loop(ctu_sema_t *sema)
logger_t * ctu_sema_reports(ctu_sema_t *sema)
tree_t * ctu_sema_type(ctu_sema_t *sema, const ctu_t *type)
tree_t * ctu_sema_lvalue(ctu_sema_t *sema, const ctu_t *expr)
const tree_t * ctu_resolve_storage_type(const tree_t *type)
size_t ctu_resolve_storage_length(const tree_t *type)
tree_t * ctu_sema_rvalue(ctu_sema_t *sema, const ctu_t *expr, const tree_t *implicit_type)
tree_t * ctu_sema_stmt(ctu_sema_t *sema, const ctu_t *stmt)
const tree_t * ctu_resolve_decl_type(const tree_t *type)
const tree_t * ctu_get_default_value(const node_t *node, const tree_t *type)
CT_MEMORY_API arena_t * get_global_arena(void)
get the global memory arena
CT_NODISCARD CT_STD_API set_t * set_new(size_t size, hash_info_t info, arena_t *arena)
create a new set
CT_STD_API const void * set_add(set_t *set, const void *key)
add a key to a set
CT_NODISCARD CT_PUREFN CT_STD_API bool set_contains(const set_t *set, const void *key)
check if a set contains a key
#define CT_UNUSED(x)
mark a variable as unused
CT_NOTIFY_API event_builder_t msg_notify(INOUT_NOTNULL logger_t *logs, const diagnostic_t *diagnostic, const node_t *node, STA_FORMAT_STRING const char *fmt,...)
notify the logger of a new message
#define CT_NEVER(...)
assert that a code path is never reached
#define CTASSERT(expr)
assert a condition, prints the condition as a message
#define CTASSERTF(expr,...)
assert a condition with a message and optional format arguments
CT_UTIL_API bool util_type_is_aggregate(const tree_t *type)
CT_UTIL_API void * util_select_decl(tree_t *sema, search_t search, const char *name)
search for a declaration by name in a set of tags
CT_UTIL_API tree_t * util_search_namespace(tree_t *sema, search_t search, const node_t *node, const vector_t *path, bool *is_imported)
search for a namespace given a path, ignoring the last element in the path
CT_UTIL_API tree_t * util_type_cast(const tree_t *dst, tree_t *expr)
attempt to cast an expression to a type
CT_UTIL_API bool util_types_comparable(tree_cookie_t *cookie, const tree_t *lhs, const tree_t *rhs)
query two types for comparability in binary logic operations
CT_TREE_API tree_t * tree_expr_unit(const node_t *node, const tree_t *type)
CT_TREE_API tree_t * tree_stmt_jump(const node_t *node, tree_t *label, tree_jump_t jump)
CT_TREE_API tree_t * tree_type_reference(const node_t *node, const char *name, const tree_t *reference)
create a reference type
CT_TREE_API void tree_report(logger_t *reports, const tree_t *error)
CT_TREE_API tree_t * tree_expr_field(const node_t *node, const tree_t *type, tree_t *object, tree_t *field)
CT_TREE_API tree_t * tree_stmt_loop(const node_t *node, tree_t *cond, tree_t *body, tree_t *other)
CT_TREE_API tree_t * tree_expr_offset(const node_t *node, const tree_t *type, tree_t *object, tree_t *offset)
CT_TREE_API tree_t * tree_expr_digit(const node_t *node, const tree_t *type, const mpz_t value)
CT_TREE_API tree_t * tree_expr_cast(const node_t *node, const tree_t *type, const tree_t *expr, tree_cast_t cast)
create a cast expression
CT_TREE_API tree_t * tree_module(tree_t *parent, const node_t *node, const char *name, size_t decls, const size_t *sizes)
create a new module
CT_TREE_API tree_t * tree_expr_unary(const node_t *node, unary_t unary, tree_t *expr)
CT_TREE_API tree_t * tree_stmt_init(const node_t *node, tree_t *dst, tree_t *src)
CT_TREE_API tree_t * tree_stmt_return(const node_t *node, const tree_t *value)
create a return statement
CT_TREE_API tree_t * tree_error(const node_t *node, const diagnostic_t *diagnostic, const char *message,...)
CT_TREE_API tree_t * tree_expr_compare(const node_t *node, const tree_t *type, compare_t compare, const tree_t *lhs, const tree_t *rhs)
CT_TREE_API tree_t * tree_type_pointer(const node_t *node, const char *name, const tree_t *pointer, size_t length)
create a pointer type
CT_TREE_API tree_cookie_t * tree_get_cookie(tree_t *sema)
return a resolution cookie
CT_TREE_API tree_t * tree_raise(const node_t *node, logger_t *reports, const diagnostic_t *diagnostic, const char *message,...)
CT_TREE_API tree_t * tree_expr_call(const node_t *node, const tree_t *callee, const vector_t *args)
CT_TREE_API tree_t * tree_expr_string(const node_t *node, const tree_t *type, const char *value, size_t length)
create a string expression
CT_TREE_API tree_t * tree_expr_bool(const node_t *node, const tree_t *type, bool value)
CT_TREE_API tree_t * tree_expr_binary(const node_t *node, const tree_t *type, binary_t binary, const tree_t *lhs, const tree_t *rhs)
CT_TREE_API tree_t * tree_expr_load(const node_t *node, tree_t *expr)
load a value from a pointer or storage
CT_TREE_API tree_t * tree_resolve_type(tree_cookie_t *cookie, const tree_t *decl)
tree_kind_t
all tree node types
CT_TREE_API tree_t * tree_expr_address(const node_t *node, tree_t *expr)
create a reference to an object
CT_TREE_API const tree_t * tree_follow_type(const tree_t *type)
CT_TREE_API tree_t * tree_stmt_assign(const node_t *node, tree_t *dst, const tree_t *src)
CT_TREE_API tree_t * tree_stmt_block(const node_t *node, const vector_t *stmts)
create a block statement
CT_TREE_API void tree_add_local(tree_t *self, tree_t *decl)
CT_TREE_API const char * unary_name(unary_t op)
get the pretty name of a unary operator
CT_TREE_API tree_t * tree_resolve(tree_cookie_t *cookie, const tree_t *decl)
CT_TREE_API tree_t * tree_stmt_branch(const node_t *node, tree_t *cond, tree_t *then, tree_t *other)
CT_TREE_API tree_t * tree_decl_local(const node_t *node, const char *name, tree_storage_t storage, const tree_t *type)
CT_TREE_API tree_t * tree_type_array(const node_t *node, const char *name, const tree_t *array, size_t length)
create a new array type
CT_STD_API const hash_info_t kTypeInfoPtr
type information for a generic pointer this operates on the pointer itself and not the data it points...
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_get(const vector_t *vector, size_t index)
get a value from a vector
CT_NODISCARD CT_STD_API vector_t * vector_new(size_t size, arena_t *arena)
create a new vector with an initial capacity
CT_NODISCARD CT_STD_API vector_t * vector_of(size_t len, arena_t *arena)
create a new vector with a specified length
CT_STD_API const vector_t kEmptyVector
a global empty vector used to avoid allocating alot of empty vectors
CT_STD_API void vector_push(vector_t **vector, void *value)
push a value onto the end of a vector
CT_NODISCARD CT_PUREFN CT_STD_API void * vector_tail(const vector_t *vector)
get the last element of a vector
CT_STD_API void vector_set(vector_t *vector, size_t index, void *value)
set a value in a vector
CT_NODISCARD CT_PUREFN CT_STD_API size_t vector_len(const vector_t *vector)
get the length of a vector
tree_t * ctu_cast_type(tree_t *sema, tree_t *expr, const tree_t *type)
vector_t * block
current statement block
tree_t * decl
current decl
tree_t * sema
current scope
a position in a source file
tree_visibility_t visibility
the visibility of the declaration
const tree_t * storage
the underlying storage type
const char * name
the name of the declaration
a generic vector of pointers