Fix foreach body copy. Moved deref / addr into special functions. Cleaned up access. Remove .sizeof .alignof .qnameof .nameof, create $qnameof $nameof

This commit is contained in:
Christoffer Lerno
2021-07-25 23:01:54 +02:00
committed by Christoffer Lerno
parent 2815a6d02e
commit 9f42ddb68d
18 changed files with 296 additions and 122 deletions

View File

@@ -40,7 +40,7 @@ private func void LinkedList.linkFirst(LinkedList *list, Type value)
private func void LinkedList.linkLast(LinkedList *list, Type value)
{
Node *last = list.last;
Node *new_node = mem::alloc(Node.sizeof);
Node *new_node = mem::alloc($sizeof(Node));
*new_node = { .prev = last, .value = value };
list.last = new_node;
if (!last)

View File

@@ -13,7 +13,7 @@ private func void List.ensureCapacity(List *list) @inline
if (list.capacity == list.size)
{
list.capacity = list.capacity ? 2 * list.capacity : 16;
list.entries = mem::realloc(list.entries, Type.sizeof * list.capacity);
list.entries = mem::realloc(list.entries, $sizeof(Type) * list.capacity);
}
}

View File

@@ -114,7 +114,7 @@ Allocator main_allocator = { &system_malloc_function, null };
macro malloc($Type)
{
return ($Type*)(mem::alloc($Type.sizeof));
return ($Type*)(mem::alloc($sizeof($Type)));
}
func void* alloc(usize size, usize elements = 1) @inline

View File

@@ -1502,26 +1502,20 @@ extern const char *kw_max;
extern const char *kw_min;
extern const char *kw_elements;
extern const char *kw_align;
extern const char *kw_alignof;
extern const char *kw_deprecated;
extern const char *kw_distinct;
extern const char *kw_ensure;
extern const char *kw_inline;
extern const char *kw_kindof;
extern const char *kw_len;
extern const char *kw_inf;
extern const char *kw_nan;
extern const char *kw_main;
extern const char *kw_nameof;
extern const char *kw_offsetof;
extern const char *kw_ordinal;
extern const char *kw_qnameof;
extern const char *kw_reqparse;
extern const char *kw_require;
extern const char *kw_pure;
extern const char *kw_param;
extern const char *kw_errors;
extern const char *kw_sizeof;
extern const char *kw___ceil;
extern const char *kw___round;
extern const char *kw___sqrt;
@@ -1530,6 +1524,9 @@ extern const char *kw_FILE;
extern const char *kw_FUNC;
extern const char *kw_LINE;
extern const char *kw_LINEREAL;
extern const char *kw_default_iterator;
extern const char *kw_incr;
extern const char *kw_check_assign;
#define AST_NEW_TOKEN(_kind, _token) new_ast(_kind, source_span_from_token_id((_token).id))
#define AST_NEW(_kind, _loc) new_ast(_kind, _loc)
@@ -1711,6 +1708,8 @@ void expr_const_fprint(FILE *__restrict file, ExprConst *expr);
bool expr_const_int_overflowed(const ExprConst *expr);
bool expr_const_compare(const ExprConst *left, const ExprConst *right, BinaryOp op);
bool expr_const_will_overflow(const ExprConst *expr, TypeKind kind);
void expr_insert_addr(Expr *original);
void expr_insert_deref(Expr *expr);
bool expr_is_constant_eval(Expr *expr);
const char *expr_const_to_error_string(const ExprConst *expr);
static inline void expr_set_type(Expr *expr, Type *type)
@@ -1788,6 +1787,7 @@ bool sema_analyse_decl(Context *context, Decl *decl);
bool sema_analyse_ct_assert_stmt(Context *context, Ast *statement);
bool sema_analyse_statement(Context *context, Ast *statement);
bool sema_expr_analyse_assign_right_side(Context *context, Expr *expr, Type *left_type, Expr *right, ExprFailableStatus lhs_is_failable);
bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_expr, Expr *struct_var, Decl *decl);
Decl *sema_resolve_symbol_in_current_dynamic_scope(Context *context, const char *symbol);
Decl *sema_resolve_parameterized_symbol(Context *context, TokenId symbol, Path *path);
@@ -1796,6 +1796,7 @@ Decl *sema_find_extension_method_in_module(Module *module, Type *type, const cha
Decl *sema_resolve_normal_symbol(Context *context, TokenId symbol, Path *path, bool handle_error);
Decl *sema_resolve_string_symbol(Context *context, const char *symbol, SourceSpan span, Path *path);
bool sema_resolve_type(Context *context, Type *type);
bool sema_resolve_type_info(Context *context, TypeInfo *type_info);
bool sema_resolve_type_info_maybe_inferred(Context *context, TypeInfo *type_info, bool allow_inferred_type);
bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow_inferred_type, bool in_shallow);

View File

@@ -333,7 +333,7 @@ Ast *copy_ast(Ast *source)
MACRO_COPY_DECL(ast->foreach_stmt.index);
MACRO_COPY_DECL(ast->foreach_stmt.variable);
MACRO_COPY_EXPR(ast->foreach_stmt.enumeration);
MACRO_COPY_AST(ast->for_stmt.body);
MACRO_COPY_AST(ast->foreach_stmt.body);
return ast;
case AST_IF_STMT:
copy_flow(ast);

View File

@@ -454,7 +454,9 @@ typedef enum
TOKEN_CT_ENDIF, // $endif
TOKEN_CT_ENDSWITCH, // $endswitch
TOKEN_CT_IF, // $if
TOKEN_CT_NAMEOF, // $nameof
TOKEN_CT_OFFSETOF, // $offsetof
TOKEN_CT_QNAMEOF, // $qnameof
TOKEN_CT_SIZEOF, // $sizeof
TOKEN_CT_SWITCH, // $switch
TOKEN_CT_TYPEOF, // $typeof

View File

@@ -1139,5 +1139,7 @@ ParseRule rules[TOKEN_EOF + 1] = {
[TOKEN_CT_SIZEOF] = { parse_ct_call, NULL, PREC_NONE },
[TOKEN_CT_ALIGNOF] = { parse_ct_call, NULL, PREC_NONE },
[TOKEN_CT_OFFSETOF] = { parse_ct_call, NULL, PREC_NONE },
[TOKEN_CT_NAMEOF] = { parse_ct_call, NULL, PREC_NONE },
[TOKEN_CT_QNAMEOF] = { parse_ct_call, NULL, PREC_NONE },
[TOKEN_CT_TYPEOF] = { parse_typeof_expr, NULL, PREC_NONE },
};

View File

@@ -1070,6 +1070,8 @@ Ast *parse_stmt(Context *context)
case TOKEN_CT_OFFSETOF:
case TOKEN_CT_ALIGNOF:
case TOKEN_CT_SIZEOF:
case TOKEN_CT_QNAMEOF:
case TOKEN_CT_NAMEOF:
return parse_expr_stmt(context);
case TOKEN_ASSERT:
return parse_assert_stmt(context);

View File

@@ -88,6 +88,48 @@ void expr_copy_types(Expr *to, Expr *from)
to->original_type = from->original_type;
}
void expr_insert_addr(Expr *original)
{
assert(original->resolve_status == RESOLVE_DONE);
if (original->expr_kind == EXPR_UNARY && original->unary_expr.operator == UNARYOP_DEREF)
{
*original = *original->unary_expr.expr;
return;
}
Expr *inner = expr_alloc();
*inner = *original;
original->expr_kind = EXPR_UNARY;
expr_set_type(original, type_get_ptr(inner->type));
original->unary_expr.operator = UNARYOP_ADDR;
original->unary_expr.expr = inner;
original->pure = false;
original->constant = false;
original->failable = inner->failable;
}
void expr_insert_deref(Expr *original)
{
assert(original->resolve_status == RESOLVE_DONE);
assert(original->type->canonical->type_kind == TYPE_POINTER);
if (original->expr_kind == EXPR_UNARY && original->unary_expr.operator == UNARYOP_ADDR)
{
*original = *original->unary_expr.expr;
return;
}
Type *pointee = original->type->type_kind == TYPE_POINTER ? original->type->pointer : original->type->canonical->pointer;
Expr *inner = expr_alloc();
*inner = *original;
original->expr_kind = EXPR_UNARY;
expr_set_type(original, pointee);
original->unary_expr.operator = UNARYOP_DEREF;
original->unary_expr.expr = inner;
original->pure = false;
original->constant = false;
original->failable = inner->failable;
}
static void expr_unify_binary_properties(Expr *expr, Expr *left, Expr *right)
{
expr->pure = left->pure & right->pure;
@@ -1145,7 +1187,7 @@ static bool sema_check_stmt_compile_time(Context *context, Ast *ast)
}
}
static inline bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_expr, Expr *struct_var, Decl *decl)
bool sema_expr_analyse_macro_call(Context *context, Type *to, Expr *call_expr, Expr *struct_var, Decl *decl)
{
assert(decl->decl_kind == DECL_MACRO);
@@ -1574,12 +1616,8 @@ static inline bool sema_expr_analyse_call(Context *context, Type *to, Expr *expr
if (decl->decl_kind == DECL_FUNC || decl->decl_kind == DECL_MACRO)
{
expr->call_expr.is_type_method = true;
struct_var = expr_new(EXPR_UNARY, func_expr->access_expr.parent->span);
struct_var->unary_expr.expr = func_expr->access_expr.parent;
struct_var->unary_expr.operator = UNARYOP_ADDR;
struct_var->resolve_status = RESOLVE_DONE;
assert(func_expr->access_expr.parent->resolve_status == RESOLVE_DONE);
expr_set_type(struct_var, type_get_ptr(struct_var->unary_expr.expr->type));
expr_insert_addr(func_expr->access_expr.parent);
struct_var = func_expr->access_expr.parent;
if (decl->decl_kind == DECL_MACRO)
{
return sema_expr_analyse_macro_call(context, to, expr, struct_var, decl);
@@ -1843,17 +1881,6 @@ static inline bool sema_expr_analyse_slice(Context *context, Expr *expr)
return true;
}
static inline void insert_access_deref(Expr *expr)
{
Expr *deref = expr_new(EXPR_UNARY, expr->span);
deref->unary_expr.operator = UNARYOP_DEREF;
deref->unary_expr.expr = expr->access_expr.parent;
deref->resolve_status = RESOLVE_DONE;
assert(expr->access_expr.parent->type->canonical->type_kind == TYPE_POINTER);
expr_set_type(deref, expr->access_expr.parent->type->canonical->pointer);
deref->failable = expr->access_expr.parent->failable;
expr->access_expr.parent = deref;
}
static inline bool sema_expr_analyse_group(Context *context, Type *to, Expr *expr)
{
@@ -2093,31 +2120,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b
Type *canonical = parent->type->canonical;
const char *name = TOKSTR(identifier_token);
// Foo.sizeof => return the size in bytes, e.g. 11
if (name == kw_sizeof)
{
expr_rewrite_to_int_const(expr, type_compint, type_size(canonical));
return true;
}
// Foo.alignof => return the alignment, e.g. 4
if (name == kw_alignof)
{
expr_rewrite_to_int_const(expr, type_compint, type_abi_alignment(canonical));
return true;
}
// Foo.nameof => return the name, e.g. "Foo"
if (name == kw_nameof)
{
expr_rewrite_to_string(expr, canonical->name);
return true;
}
// Foo.qnameof => return the qualified name, e.g. "mylib::Foo"
if (name == kw_qnameof)
{
expr_rewrite_to_string(expr, type_generate_qname(canonical));
return true;
}
// 3. Handle float.nan, double.inf etc
if (type_is_float(canonical))
{
if (name == kw_nan)
@@ -2147,7 +2150,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b
return true;
}
}
//
if (!type_may_have_sub_elements(canonical))
{
SEMA_ERROR(expr, "'%s' does not have a property '%s'.", type_to_error_string(parent->type), name);
@@ -2199,6 +2202,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b
case DECL_ERR:
case DECL_UNION:
case DECL_STRUCT:
case DECL_DISTINCT:
break;
default:
UNREACHABLE
@@ -2215,18 +2219,7 @@ static inline bool sema_expr_analyse_type_access(Expr *expr, TypeInfo *parent, b
return true;
}
}
VECEACH(decl->strukt.members, i)
{
Decl *member = decl->strukt.members[i];
if (name == member->name)
{
expr->expr_kind = EXPR_MEMBER_ACCESS;
expr->access_expr.ref = member;
expr_set_type(expr, member->type);
return true;
}
}
SEMA_ERROR(expr, "No function or member '%s.%s' found.", type_to_error_string(parent->type), name);
SEMA_ERROR(expr, "No function '%s.%s' found.", type_to_error_string(parent->type), name);
return false;
}
@@ -2260,16 +2253,6 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr,
expr->resolve_status = RESOLVE_DONE;
return true;
}
if (name == kw_sizeof && !is_macro)
{
expr_rewrite_to_int_const(expr, type_compint, type_size(ref->type));
return true;
}
if (name == kw_alignof && !is_macro)
{
expr_rewrite_to_int_const(expr, type_compint, type_abi_alignment(ref->type));
return true;
}
if (name == kw_ordinal && !is_macro)
{
if (ref->decl_kind == DECL_ENUM_CONSTANT)
@@ -2279,20 +2262,6 @@ static inline bool sema_expr_analyse_member_access(Context *context, Expr *expr,
}
}
if (name == kw_nameof && !is_macro)
{
expr_rewrite_to_string(expr, ref->name);
return true;
}
if (name == kw_qnameof && !is_macro)
{
expr_rewrite_to_string(expr, ref->external_name ?: ref->name);
return true;
}
if (name == kw_kindof && !is_macro)
{
TODO
}
// If we have something like struct Foo { Bar b; int c; struct d { int e; } }
// If we are inspecting Foo.c we're done here. Otherwise handle struct d / Bar b case
// The same way.
@@ -2393,7 +2362,6 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
if (TOKEN_IS_INVALID(identifier_token)) return false;
// 2. If our left hand side is a type, e.g. MyInt.abc, handle this here.
Type *parent_type = parent->type;
if (parent->expr_kind == EXPR_TYPEINFO)
{
return sema_expr_analyse_type_access(expr, parent->type_expr, was_group, is_macro, identifier_token);
@@ -2414,14 +2382,11 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
assert(parent->resolve_status == RESOLVE_DONE);
// 7. Is this a pointer? If so we insert a deref.
Type *type = parent_type->canonical;
bool is_pointer = type->type_kind == TYPE_POINTER;
bool is_pointer = parent->type->canonical->type_kind == TYPE_POINTER;
if (is_pointer)
{
type = type->pointer->canonical;
parent_type = type;
if (!sema_cast_rvalue(context, NULL, parent)) return false;
insert_access_deref(expr);
expr_insert_deref(expr->access_expr.parent);
parent = expr->access_expr.parent;
}
@@ -2429,6 +2394,7 @@ static inline bool sema_expr_analyse_access(Context *context, Expr *expr)
const char *kw = TOKSTR(identifier_token);
Expr *current_parent = parent;
Type *type = parent->type->canonical;
Type *flat_type = type_flatten(type);
CHECK_DEEPER:
@@ -2445,7 +2411,7 @@ CHECK_DEEPER:
}
if (flat_type->type_kind == TYPE_ARRAY)
{
expr_rewrite_to_int_const(expr, type_compint, type->array.len);
expr_rewrite_to_int_const(expr, type_compint, flat_type->array.len);
return true;
}
}
@@ -2453,7 +2419,7 @@ CHECK_DEEPER:
// 9. At this point we may only have distinct, struct, union, error, enum
if (!type_may_have_sub_elements(type))
{
SEMA_ERROR(expr, "There is no member or method '%s' on '%s'", kw, type_to_error_string(parent_type));
SEMA_ERROR(expr, "There is no member or method '%s' on '%s'", kw, type_to_error_string(parent->type));
return false;
}
@@ -5689,6 +5655,74 @@ static inline bool sema_expr_analyse_ct_sizeof(Context *context, Type *to, Expr
return true;
}
static inline bool decl_is_local(Decl *decl)
{
if (decl->decl_kind != DECL_VAR) return false;
VarDeclKind kind = decl->var.kind;
return kind == VARDECL_PARAM_CT_TYPE
|| kind == VARDECL_PARAM
|| kind == VARDECL_PARAM_CT
|| kind == VARDECL_LOCAL
|| kind == VARDECL_LOCAL_CT_TYPE
|| kind == VARDECL_LOCAL_CT
|| kind == VARDECL_PARAM_REF
|| kind == VARDECL_PARAM_EXPR
|| kind == VARDECL_MEMBER;
}
static inline bool sema_expr_analyse_ct_nameof(Context *context, Type *to, Expr *expr)
{
if (expr->resolve_status == RESOLVE_DONE) return true;
Expr **elements = expr->ct_call_expr.arguments;
unsigned count = vec_size(elements);
if (count > 1)
{
SEMA_ERROR(elements[1], "The function only takes one argument.");
return expr_poison(expr);
}
Expr *first_expr = elements[0];
if (!sema_analyse_expr_value(context, NULL, first_expr)) return false;
bool qualified = expr->ct_call_expr.token_type == TOKEN_CT_QNAMEOF;
if (first_expr->expr_kind == EXPR_TYPEINFO)
{
Type *type = first_expr->type_expr->type->canonical;
if (!sema_resolve_type(context, type)) return false;
// TODO type_is_builtin is wrong also this does not cover virtual.
if (!qualified || type_is_builtin(type->type_kind))
{
expr_rewrite_to_string(expr, type->name);
return true;
}
scratch_buffer_clear();
scratch_buffer_append(type->decl->module->name->module);
scratch_buffer_append("::");
scratch_buffer_append(type->name);
expr_rewrite_to_string(expr, scratch_buffer_interned());
return true;
}
if (first_expr->expr_kind != EXPR_IDENTIFIER)
{
SEMA_ERROR(first_expr, "Expected an identifier.");
return false;
}
Decl *decl = first_expr->identifier_expr.decl;
if (!decl->module || !qualified || decl_is_local(decl))
{
expr_rewrite_to_string(expr, decl->name);
return true;
}
scratch_buffer_clear();
scratch_buffer_append(decl->module->name->module);
scratch_buffer_append("::");
scratch_buffer_append(decl->name);
expr_rewrite_to_string(expr, scratch_buffer_interned());
return true;
}
static inline bool sema_expr_analyse_ct_alignof(Context *context, Type *to, Expr *expr)
{
@@ -5696,7 +5730,9 @@ static inline bool sema_expr_analyse_ct_alignof(Context *context, Type *to, Expr
if (!sema_analyse_ct_call_parameters(context, expr)) return false;
Type *type = expr->ct_call_expr.type->canonical;
ExprFlatElement *elements = expr->ct_call_expr.flatpath;
AlignSize align = expr->ct_call_expr.decl ? expr->ct_call_expr.decl->alignment : type_abi_alignment(type);
Decl *decl = expr->ct_call_expr.decl;
AlignSize align = decl && !decl_is_user_defined_type(decl) ? expr->ct_call_expr.decl->alignment : type_abi_alignment(type);
VECEACH(elements, i)
{
ExprFlatElement element = elements[i];
@@ -5744,6 +5780,7 @@ static inline bool sema_expr_analyse_ct_alignof(Context *context, Type *to, Expr
return true;
}
static inline bool sema_expr_analyse_ct_offsetof(Context *context, Type *to, Expr *expr)
{
Expr *first = expr->ct_call_expr.arguments[0];
@@ -5812,6 +5849,10 @@ static inline bool sema_expr_analyse_ct_call(Context *context, Type *to, Expr *e
return sema_expr_analyse_ct_alignof(context, to, expr);
case TOKEN_CT_OFFSETOF:
return sema_expr_analyse_ct_offsetof(context, to, expr);
case TOKEN_CT_QNAMEOF:
return sema_expr_analyse_ct_nameof(context, to, expr);
case TOKEN_CT_NAMEOF:
return sema_expr_analyse_ct_nameof(context, to, expr);
default:
UNREACHABLE
}

View File

@@ -591,7 +591,43 @@ static inline bool sema_analyse_for_stmt(Context *context, Ast *statement)
return success;
}
static inline bool sema_inline_default_iterator(Context *context, Expr *expr)
{
Type *type = expr->type->canonical;
if (!type_may_have_sub_elements(type)) return true;
Decl *ambiguous = NULL;
Decl *private = NULL;
Decl *result = sema_resolve_method(context, type->decl, kw_default_iterator, &ambiguous, &private);
if (!result)
{
SEMA_ERROR(expr, "There are multiple candidates for 'default_iterator' on %s.",
type_quoted_error_string(expr->type));
return false;
}
Expr *call = expr_new(EXPR_CALL, expr->span);
call->call_expr.arguments = NULL;
call->call_expr.body = NULL;
call->call_expr.unsplat_last = false;
call->call_expr.is_type_method = true;
bool success;
switch (result->decl_kind)
{
case DECL_MACRO:
success = sema_expr_analyse_macro_call(context, NULL, call, expr, result);
break;
case DECL_GENERIC:
case DECL_FUNC:
TODO
default:
UNREACHABLE
}
if (success)
{
expr_replace(expr, call);
}
return success;
}
static inline bool sema_analyse_foreach_stmt(Context *context, Ast *statement)
{
// Pull out the relevant data.

View File

@@ -137,6 +137,44 @@ static bool sema_resolve_type_identifier(Context *context, TypeInfo *type_info)
}
bool sema_resolve_type(Context *context, Type *type)
{
switch (type->type_kind)
{
case TYPE_TYPEDEF:
return sema_resolve_type(context, type->canonical);
case TYPE_POISONED:
case ALL_INTS:
case ALL_FLOATS:
case TYPE_VOID:
case TYPE_BOOL:
case TYPE_TYPEID:
case TYPE_VIRTUAL_ANY:
case TYPE_ERR_UNION:
case TYPE_STRLIT:
case TYPE_VECTOR:
return true;
case TYPE_POINTER:
return sema_resolve_type(context, type->pointer);
case TYPE_ENUM:
case TYPE_FUNC:
case TYPE_STRUCT:
case TYPE_UNION:
case TYPE_ERRTYPE:
case TYPE_DISTINCT:
break;
case TYPE_ARRAY:
case TYPE_SUBARRAY:
case TYPE_INFERRED_ARRAY:
return sema_resolve_type(context, type->array.base);
case TYPE_TYPEINFO:
TODO
case TYPE_VIRTUAL:
TODO;
}
return sema_analyse_decl(context, type->decl);
}
bool sema_resolve_type_shallow(Context *context, TypeInfo *type_info, bool allow_inferred_type, bool in_shallow)
{
if (type_info->resolve_status == RESOLVE_DONE) return type_info_ok(type_info);

View File

@@ -37,7 +37,6 @@ static SymTab symtab;
const char *attribute_list[NUMBER_OF_ATTRIBUTES];
const char *kw_align;
const char *kw_alignof;
const char *kw_deprecated;
const char *kw_distinct;
const char *kw_ensure;
@@ -45,21 +44,16 @@ const char *kw_elements;
const char *kw_errors;
const char *kw_inf;
const char *kw_inline;
const char *kw_kindof;
const char *kw_len;
const char *kw_main;
const char *kw_max;
const char *kw_min;
const char *kw_nan;
const char *kw_nameof;
const char *kw_offsetof;
const char *kw_ordinal;
const char *kw_param;
const char *kw_pure;
const char *kw_qnameof;
const char *kw_reqparse;
const char *kw_require;
const char *kw_sizeof;
const char *kw_std;
const char *kw___ceil;
const char *kw___round;
@@ -69,6 +63,9 @@ const char *kw_FILE;
const char *kw_FUNC;
const char *kw_LINE;
const char *kw_LINEREAL;
const char *kw_default_iterator;
const char *kw_incr;
const char *kw_check_assign;
void symtab_init(uint32_t capacity)
{
@@ -103,7 +100,6 @@ void symtab_init(uint32_t capacity)
TokenType type = TOKEN_IDENT;
#define KW_DEF(x) symtab_add(x, sizeof(x) - 1, fnv1a(x, sizeof(x) - 1), &type)
kw_align = KW_DEF("align");
kw_alignof = KW_DEF("alignof");
kw_deprecated = KW_DEF("deprecated");
kw_distinct = KW_DEF("distinct");
kw_elements = KW_DEF("elements");
@@ -111,20 +107,15 @@ void symtab_init(uint32_t capacity)
kw_errors = KW_DEF("errors");
kw_inf = KW_DEF("inf");
kw_inline = KW_DEF("inline");
kw_kindof = KW_DEF("kindof");
kw_len = KW_DEF("len");
kw_main = KW_DEF("main");
kw_max = KW_DEF("max");
kw_min = KW_DEF("min");
kw_nameof = KW_DEF("nameof");
kw_nan = KW_DEF("nan");
kw_offsetof = KW_DEF("offsetof");
kw_ordinal = KW_DEF("ordinal");
kw_param = KW_DEF("param");
kw_pure = KW_DEF("pure");
kw_qnameof = KW_DEF("qnameof");
kw_require = KW_DEF("require");
kw_sizeof = KW_DEF("sizeof");
kw_std = KW_DEF("std");
kw___ceil = KW_DEF("__ceil");
kw___round = KW_DEF("__round");
@@ -134,7 +125,9 @@ void symtab_init(uint32_t capacity)
kw_LINEREAL = KW_DEF("LINEREAL");
kw_FILE = KW_DEF("FILE");
kw_FUNC = KW_DEF("FUNC");
kw_incr = KW_DEF("incr");
kw_default_iterator = KW_DEF("default_iterator");
kw_check_assign = KW_DEF("check_assign");
attribute_list[ATTRIBUTE_INLINE] = kw_inline;
attribute_list[ATTRIBUTE_NOINLINE] = KW_DEF("noinline");
attribute_list[ATTRIBUTE_OPAQUE] = KW_DEF("opaque");

View File

@@ -339,8 +339,12 @@ const char *token_type_to_string(TokenType type)
return "$endswitch";
case TOKEN_CT_IF:
return "$if";
case TOKEN_CT_NAMEOF:
return "$nameof";
case TOKEN_CT_OFFSETOF:
return "$offsetof";
case TOKEN_CT_QNAMEOF:
return "$qnameof";
case TOKEN_CT_SIZEOF:
return "$sizeof";
case TOKEN_CT_SWITCH:

View File

@@ -0,0 +1,55 @@
module qnametest;
extern func int printf(char *, ...);
int x;
struct Blob { int z; int f; }
func void main()
{
int help;
printf("printf: %s\n", $nameof(printf));
printf("printfq: %s\n", $qnameof(printf));
printf("Blobq: %s\n", $qnameof(Blob));
printf("Blob: %s\n", $nameof(Blob));
printf("xq: %s\n", $qnameof(x));
printf("x: %s\n", $nameof(x));
printf("helpq: %s\n", $qnameof(help));
printf("mainq: %s\n", $qnameof(main));
printf("Blob**[3]: %s\n", $nameof(Blob**[3]));
}
// #expect: qnametest.ll
@.str = private constant [12 x i8] c"printf: %s\0A\00", align 1
@.str.1 = private constant [7 x i8] c"printf\00", align 1
@.str.2 = private constant [13 x i8] c"printfq: %s\0A\00", align 1
@.str.3 = private constant [18 x i8] c"qnametest::printf\00", align 1
@.str.4 = private constant [11 x i8] c"Blobq: %s\0A\00", align 1
@.str.5 = private constant [16 x i8] c"qnametest::Blob\00", align 1
@.str.6 = private constant [10 x i8] c"Blob: %s\0A\00", align 1
@.str.7 = private constant [5 x i8] c"Blob\00", align 1
@.str.8 = private constant [8 x i8] c"xq: %s\0A\00", align 1
@.str.9 = private constant [13 x i8] c"qnametest::x\00", align 1
@.str.10 = private constant [7 x i8] c"x: %s\0A\00", align 1
@.str.11 = private constant [2 x i8] c"x\00", align 1
@.str.12 = private constant [11 x i8] c"helpq: %s\0A\00", align 1
@.str.13 = private constant [5 x i8] c"help\00", align 1
@.str.14 = private constant [11 x i8] c"mainq: %s\0A\00", align 1
@.str.15 = private constant [16 x i8] c"qnametest::main\00", align 1
@.str.16 = private constant [15 x i8] c"Blob**[3]: %s\0A\00", align 1
@.str.17 = private constant [10 x i8] c"Blob**[3]\00", align 1
define void @main()
%help = alloca i32, align 4
store i32 0, i32* %help, align 4
%0 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([12 x i8], [12 x i8]* @.str, i32 0, i32 0), i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.1, i32 0, i32 0))
%1 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.2, i32 0, i32 0), i8* getelementptr inbounds ([18 x i8], [18 x i8]* @.str.3, i32 0, i32 0))
%2 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.4, i32 0, i32 0), i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.5, i32 0, i32 0))
%3 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.6, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.7, i32 0, i32 0))
%4 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([8 x i8], [8 x i8]* @.str.8, i32 0, i32 0), i8* getelementptr inbounds ([13 x i8], [13 x i8]* @.str.9, i32 0, i32 0))
%5 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([7 x i8], [7 x i8]* @.str.10, i32 0, i32 0), i8* getelementptr inbounds ([2 x i8], [2 x i8]* @.str.11, i32 0, i32 0))
%6 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.12, i32 0, i32 0), i8* getelementptr inbounds ([5 x i8], [5 x i8]* @.str.13, i32 0, i32 0))
%7 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([11 x i8], [11 x i8]* @.str.14, i32 0, i32 0), i8* getelementptr inbounds ([16 x i8], [16 x i8]* @.str.15, i32 0, i32 0))
%8 = call i32 (i8*, ...) @printf(i8* getelementptr inbounds ([15 x i8], [15 x i8]* @.str.16, i32 0, i32 0), i8* getelementptr inbounds ([10 x i8], [10 x i8]* @.str.17, i32 0, i32 0))
ret void

View File

@@ -8,8 +8,8 @@ enum MyEnum : short
int myenum_max = MyEnum.max;
int myenum_min = MyEnum.min;
int myenum_elements = MyEnum.elements;
int myenum_alignof = MyEnum.alignof;
int myenum_sizeof = MyEnum.sizeof;
int myenum_alignof = $alignof(MyEnum);
int myenum_sizeof = $sizeof(MyEnum);
// #expect: compile_time.ll

View File

@@ -16,7 +16,7 @@ func int Foo.func2(Foo* f, int i)
func void test_unknown_member()
{
int a = Foo.b; // #error: No function or member 'Foo.b' found.
int a = Foo.b; // #error: No function 'Foo.b' found.
}
/*

View File

@@ -6,7 +6,7 @@ struct Foo
long bar;
}
private usize x = Foo.sizeof;
private usize x = $sizeof(Foo);
private Foo foo1 = { 1, 2 };
private Foo foo2 = { .foo = 2 };

View File

@@ -7,7 +7,7 @@ struct Foo1 @packed @align(4)
char foo;
}
$assert(Foo1.sizeof == 12);
$assert($sizeof(Foo1) == 12);
Foo1 foo1 = { 1, 2 };
// <{ i8, i64, [3 x i8] }>
@@ -17,7 +17,7 @@ struct Foo2 @packed @align(4)
long bar;
}
$assert(Foo2.sizeof == 12);
$assert($sizeof(Foo2) == 12);
Foo2 foo2 = { 1, 2 };
// <{ i8, i64, [7 x i8] }>
@@ -28,7 +28,7 @@ struct Foo3 @packed @align(8)
}
Foo3 foo3 = { 1, 2 };
$assert(Foo3.sizeof == 16);
$assert($sizeof(Foo3) == 16);
// <{ i8, i64 }>
struct Foo4 @packed
@@ -37,7 +37,7 @@ struct Foo4 @packed
long bar;
}
$assert(Foo4.sizeof == 9);
$assert($sizeof(Foo4) == 9);
Foo4 foo4 = { 1, 2 };
// { i32, [12 x i8], i8, [15 x i8] }
@@ -47,7 +47,7 @@ struct Foo5
ichar foo @align(16);
}
$assert(Foo5.sizeof == 32);
$assert($sizeof(Foo5) == 32);
Foo5 foo5 = { 1, 2 };
func int test5(ichar x)
@@ -64,7 +64,7 @@ struct Foo6 @packed
short c;
}
$assert(Foo6.sizeof == 8);
$assert($sizeof(Foo6) == 8);
Foo6 foo6 = { 1, 2, 3 };
// #expect: struct2.ll