mirror of
https://github.com/odin-lang/Odin.git
synced 2026-04-18 12:30:28 +00:00
Merge branch 'master' into llvm-17
This commit is contained in:
@@ -343,7 +343,7 @@ unquote_string :: proc(token: Token, spec: Specification, allocator := context.a
|
||||
i += 1
|
||||
continue
|
||||
}
|
||||
r, w := utf8.decode_rune_in_string(s)
|
||||
r, w := utf8.decode_rune_in_string(s[i:])
|
||||
if r == utf8.RUNE_ERROR && w == 1 {
|
||||
break
|
||||
}
|
||||
|
||||
@@ -39,12 +39,12 @@ write_int :: proc(w: Writer, i: int, base: int = 10, n_written: ^int = nil) -> (
|
||||
}
|
||||
|
||||
write_u128 :: proc(w: Writer, i: u128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
buf: [32]byte
|
||||
buf: [39]byte
|
||||
s := strconv.append_bits_128(buf[:], i, base, false, 128, strconv.digits, nil)
|
||||
return write_string(w, s, n_written)
|
||||
}
|
||||
write_i128 :: proc(w: Writer, i: i128, base: int = 10, n_written: ^int = nil) -> (n: int, err: Error) {
|
||||
buf: [32]byte
|
||||
buf: [40]byte
|
||||
s := strconv.append_bits_128(buf[:], u128(i), base, true, 128, strconv.digits, nil)
|
||||
return write_string(w, s, n_written)
|
||||
}
|
||||
|
||||
@@ -413,6 +413,48 @@ cstring_to_string :: proc "contextless" (s: cstring) -> string {
|
||||
}
|
||||
|
||||
|
||||
cstring_eq :: proc "contextless" (lhs, rhs: cstring) -> bool {
|
||||
x := ([^]byte)(lhs)
|
||||
y := ([^]byte)(rhs)
|
||||
if x == y {
|
||||
return true
|
||||
}
|
||||
if (x == nil) ~ (y == nil) {
|
||||
return false
|
||||
}
|
||||
xn := cstring_len(lhs)
|
||||
yn := cstring_len(rhs)
|
||||
if xn != yn {
|
||||
return false
|
||||
}
|
||||
return #force_inline memory_equal(x, y, xn)
|
||||
}
|
||||
|
||||
cstring_cmp :: proc "contextless" (lhs, rhs: cstring) -> int {
|
||||
x := ([^]byte)(lhs)
|
||||
y := ([^]byte)(rhs)
|
||||
if x == y {
|
||||
return 0
|
||||
}
|
||||
if (x == nil) ~ (y == nil) {
|
||||
return -1 if x == nil else +1
|
||||
}
|
||||
xn := cstring_len(lhs)
|
||||
yn := cstring_len(rhs)
|
||||
ret := memory_compare(x, y, min(xn, yn))
|
||||
if ret == 0 && xn != yn {
|
||||
return -1 if xn < yn else +1
|
||||
}
|
||||
return ret
|
||||
}
|
||||
|
||||
cstring_ne :: #force_inline proc "contextless" (a, b: cstring) -> bool { return !cstring_eq(a, b) }
|
||||
cstring_lt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) < 0 }
|
||||
cstring_gt :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) > 0 }
|
||||
cstring_le :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) <= 0 }
|
||||
cstring_ge :: #force_inline proc "contextless" (a, b: cstring) -> bool { return cstring_cmp(a, b) >= 0 }
|
||||
|
||||
|
||||
complex32_eq :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) == real(b) && imag(a) == imag(b) }
|
||||
complex32_ne :: #force_inline proc "contextless" (a, b: complex32) -> bool { return real(a) != real(b) || imag(a) != imag(b) }
|
||||
|
||||
|
||||
@@ -2120,7 +2120,7 @@ gb_internal bool check_builtin_procedure(CheckerContext *c, Operand *operand, As
|
||||
return false;
|
||||
}
|
||||
Type *t = o.type;
|
||||
if (t == nullptr || t == t_invalid || is_type_asm_proc(o.type) || is_type_polymorphic(operand->type)) {
|
||||
if (t == nullptr || t == t_invalid || is_type_asm_proc(t) || is_type_polymorphic(t)) {
|
||||
error(ce->args[0], "Invalid argument for '%.*s'", LIT(builtin_name));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -2462,8 +2462,9 @@ gb_internal void add_comparison_procedures_for_fields(CheckerContext *c, Type *t
|
||||
add_package_dependency(c, "runtime", "quaternion256_ne");
|
||||
break;
|
||||
case Basic_cstring:
|
||||
add_package_dependency(c, "runtime", "cstring_to_string");
|
||||
/*fallthrough*/
|
||||
add_package_dependency(c, "runtime", "cstring_eq");
|
||||
add_package_dependency(c, "runtime", "cstring_ne");
|
||||
break;
|
||||
case Basic_string:
|
||||
add_package_dependency(c, "runtime", "string_eq");
|
||||
add_package_dependency(c, "runtime", "string_ne");
|
||||
@@ -2621,7 +2622,16 @@ gb_internal void check_comparison(CheckerContext *c, Ast *node, Operand *x, Oper
|
||||
if (!is_type_untyped(x->type)) size = gb_max(size, type_size_of(x->type));
|
||||
if (!is_type_untyped(y->type)) size = gb_max(size, type_size_of(y->type));
|
||||
|
||||
if (is_type_string(x->type) || is_type_string(y->type)) {
|
||||
if (is_type_cstring(x->type) && is_type_cstring(y->type)) {
|
||||
switch (op) {
|
||||
case Token_CmpEq: add_package_dependency(c, "runtime", "cstring_eq"); break;
|
||||
case Token_NotEq: add_package_dependency(c, "runtime", "cstring_ne"); break;
|
||||
case Token_Lt: add_package_dependency(c, "runtime", "cstring_lt"); break;
|
||||
case Token_Gt: add_package_dependency(c, "runtime", "cstring_gt"); break;
|
||||
case Token_LtEq: add_package_dependency(c, "runtime", "cstring_le"); break;
|
||||
case Token_GtEq: add_package_dependency(c, "runtime", "cstring_gt"); break;
|
||||
}
|
||||
} else if (is_type_string(x->type) || is_type_string(y->type)) {
|
||||
switch (op) {
|
||||
case Token_CmpEq: add_package_dependency(c, "runtime", "string_eq"); break;
|
||||
case Token_NotEq: add_package_dependency(c, "runtime", "string_ne"); break;
|
||||
|
||||
@@ -1893,7 +1893,7 @@ gb_internal void check_value_decl_stmt(CheckerContext *ctx, Ast *node, u32 mod_f
|
||||
}
|
||||
|
||||
if (is_arch_wasm() && e->Variable.thread_local_model.len != 0) {
|
||||
error(e->token, "@(thread_local) is not supported for this target platform");
|
||||
// error(e->token, "@(thread_local) is not supported for this target platform");
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -613,6 +613,9 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
|
||||
|
||||
scope_reserve(ctx->scope, min_field_count);
|
||||
|
||||
rw_mutex_lock(&struct_type->Struct.fields_mutex);
|
||||
defer (rw_mutex_unlock(&struct_type->Struct.fields_mutex));
|
||||
|
||||
if (st->is_raw_union && min_field_count > 1) {
|
||||
struct_type->Struct.is_raw_union = true;
|
||||
context = str_lit("struct #raw_union");
|
||||
|
||||
@@ -2029,6 +2029,9 @@ gb_internal void add_type_info_type_internal(CheckerContext *c, Type *t) {
|
||||
break;
|
||||
|
||||
|
||||
case Type_Generic:
|
||||
break;
|
||||
|
||||
default:
|
||||
GB_PANIC("Unhandled type: %*.s %d", LIT(type_strings[bt->kind]), bt->kind);
|
||||
break;
|
||||
|
||||
@@ -356,7 +356,9 @@ gb_internal void error_out_coloured(char const *str, TerminalStyle style, Termin
|
||||
|
||||
gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
global_error_collector.count.fetch_add(1);
|
||||
|
||||
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
|
||||
gb_exit(1);
|
||||
}
|
||||
mutex_lock(&global_error_collector.mutex);
|
||||
// NOTE(bill): Duplicate error, skip it
|
||||
if (pos.line == 0) {
|
||||
@@ -372,11 +374,10 @@ gb_internal void error_va(TokenPos const &pos, TokenPos end, char const *fmt, va
|
||||
error_out_va(fmt, va);
|
||||
error_out("\n");
|
||||
show_error_on_line(pos, end);
|
||||
} else {
|
||||
global_error_collector.count.fetch_sub(1);
|
||||
}
|
||||
mutex_unlock(&global_error_collector.mutex);
|
||||
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
|
||||
gb_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal void warning_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
@@ -410,8 +411,11 @@ gb_internal void error_line_va(char const *fmt, va_list va) {
|
||||
}
|
||||
|
||||
gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_list va) {
|
||||
mutex_lock(&global_error_collector.mutex);
|
||||
global_error_collector.count.fetch_add(1);
|
||||
if (global_error_collector.count.load() > MAX_ERROR_COLLECTOR_COUNT()) {
|
||||
gb_exit(1);
|
||||
}
|
||||
mutex_lock(&global_error_collector.mutex);
|
||||
// NOTE(bill): Duplicate error, skip it
|
||||
if (pos.line == 0) {
|
||||
error_out_coloured("Error: ", TerminalStyle_Normal, TerminalColour_Red);
|
||||
@@ -425,15 +429,15 @@ gb_internal void error_no_newline_va(TokenPos const &pos, char const *fmt, va_li
|
||||
error_out_va(fmt, va);
|
||||
}
|
||||
mutex_unlock(&global_error_collector.mutex);
|
||||
if (global_error_collector.count.load() > MAX_ERROR_COLLECTOR_COUNT()) {
|
||||
gb_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
global_error_collector.count.fetch_add(1);
|
||||
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
|
||||
gb_exit(1);
|
||||
}
|
||||
mutex_lock(&global_error_collector.mutex);
|
||||
global_error_collector.count++;
|
||||
// NOTE(bill): Duplicate error, skip it
|
||||
if (global_error_collector.prev != pos) {
|
||||
global_error_collector.prev = pos;
|
||||
@@ -447,16 +451,14 @@ gb_internal void syntax_error_va(TokenPos const &pos, TokenPos end, char const *
|
||||
error_out_va(fmt, va);
|
||||
error_out("\n");
|
||||
}
|
||||
|
||||
mutex_unlock(&global_error_collector.mutex);
|
||||
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
|
||||
gb_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end, char const *fmt, va_list va) {
|
||||
global_error_collector.count.fetch_add(1);
|
||||
|
||||
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
|
||||
gb_exit(1);
|
||||
}
|
||||
mutex_lock(&global_error_collector.mutex);
|
||||
// NOTE(bill): Duplicate error, skip it
|
||||
if (pos.line == 0) {
|
||||
@@ -474,9 +476,6 @@ gb_internal void syntax_error_with_verbose_va(TokenPos const &pos, TokenPos end,
|
||||
show_error_on_line(pos, end);
|
||||
}
|
||||
mutex_unlock(&global_error_collector.mutex);
|
||||
if (global_error_collector.count > MAX_ERROR_COLLECTOR_COUNT()) {
|
||||
gb_exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -578,7 +577,3 @@ gb_internal void compiler_error(char const *fmt, ...) {
|
||||
GB_DEBUG_TRAP();
|
||||
gb_exit(1);
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -2414,7 +2414,28 @@ gb_internal lbValue lb_emit_comp(lbProcedure *p, TokenKind op_kind, lbValue left
|
||||
}
|
||||
|
||||
if (is_type_string(a)) {
|
||||
if (is_type_cstring(a)) {
|
||||
if (is_type_cstring(a) && is_type_cstring(b)) {
|
||||
left = lb_emit_conv(p, left, t_cstring);
|
||||
right = lb_emit_conv(p, right, t_cstring);
|
||||
char const *runtime_procedure = nullptr;
|
||||
switch (op_kind) {
|
||||
case Token_CmpEq: runtime_procedure = "cstring_eq"; break;
|
||||
case Token_NotEq: runtime_procedure = "cstring_ne"; break;
|
||||
case Token_Lt: runtime_procedure = "cstring_lt"; break;
|
||||
case Token_Gt: runtime_procedure = "cstring_gt"; break;
|
||||
case Token_LtEq: runtime_procedure = "cstring_le"; break;
|
||||
case Token_GtEq: runtime_procedure = "cstring_gt"; break;
|
||||
}
|
||||
GB_ASSERT(runtime_procedure != nullptr);
|
||||
|
||||
auto args = array_make<lbValue>(permanent_allocator(), 2);
|
||||
args[0] = left;
|
||||
args[1] = right;
|
||||
return lb_emit_runtime_call(p, runtime_procedure, args);
|
||||
}
|
||||
|
||||
|
||||
if (is_type_cstring(a) ^ is_type_cstring(b)) {
|
||||
left = lb_emit_conv(p, left, t_string);
|
||||
right = lb_emit_conv(p, right, t_string);
|
||||
}
|
||||
|
||||
@@ -1361,6 +1361,22 @@ gb_internal Token peek_token(AstFile *f) {
|
||||
return {};
|
||||
}
|
||||
|
||||
gb_internal Token peek_token_n(AstFile *f, isize n) {
|
||||
Token found = {};
|
||||
for (isize i = f->curr_token_index+1; i < f->tokens.count; i++) {
|
||||
Token tok = f->tokens[i];
|
||||
if (tok.kind == Token_Comment) {
|
||||
continue;
|
||||
}
|
||||
found = tok;
|
||||
if (n-- == 0) {
|
||||
return found;
|
||||
}
|
||||
}
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
gb_internal bool skip_possible_newline(AstFile *f) {
|
||||
if (token_is_newline(f->curr_token)) {
|
||||
advance_token(f);
|
||||
@@ -2206,6 +2222,10 @@ gb_internal Ast *parse_operand(AstFile *f, bool lhs) {
|
||||
Ast *tag = ast_basic_directive(f, token, name);
|
||||
Ast *original_expr = parse_expr(f, lhs);
|
||||
Ast *expr = unparen_expr(original_expr);
|
||||
if (expr == nullptr) {
|
||||
syntax_error(name, "Expected a compound literal after #%.*s", LIT(name.string));
|
||||
return ast_bad_expr(f, token, name);
|
||||
}
|
||||
switch (expr->kind) {
|
||||
case Ast_ArrayType:
|
||||
syntax_error(expr, "#partial has been replaced with #sparse for non-contiguous enumerated array types");
|
||||
@@ -3419,6 +3439,18 @@ gb_internal Ast *parse_simple_stmt(AstFile *f, u32 flags) {
|
||||
case Token_Colon:
|
||||
expect_token_after(f, Token_Colon, "identifier list");
|
||||
if ((flags&StmtAllowFlag_Label) && lhs.count == 1) {
|
||||
bool is_partial = false;
|
||||
Token partial_token = {};
|
||||
if (f->curr_token.kind == Token_Hash) {
|
||||
// NOTE(bill): This is purely for error messages
|
||||
Token name = peek_token_n(f, 0);
|
||||
if (name.kind == Token_Ident && name.string == "partial" &&
|
||||
peek_token_n(f, 1).kind == Token_switch) {
|
||||
partial_token = expect_token(f, Token_Hash);
|
||||
expect_token(f, Token_Ident);
|
||||
is_partial = true;
|
||||
}
|
||||
}
|
||||
switch (f->curr_token.kind) {
|
||||
case Token_OpenBrace: // block statement
|
||||
case Token_if:
|
||||
@@ -3440,6 +3472,19 @@ gb_internal Ast *parse_simple_stmt(AstFile *f, u32 flags) {
|
||||
break;
|
||||
}
|
||||
#undef _SET_LABEL
|
||||
|
||||
if (is_partial) {
|
||||
switch (stmt->kind) {
|
||||
case Ast_SwitchStmt:
|
||||
stmt->SwitchStmt.partial = true;
|
||||
break;
|
||||
case Ast_TypeSwitchStmt:
|
||||
stmt->TypeSwitchStmt.partial = true;
|
||||
break;
|
||||
}
|
||||
syntax_error(partial_token, "Incorrect use of directive, use '#partial %.*s: switch'", LIT(ast_token(name).string));
|
||||
}
|
||||
|
||||
return stmt;
|
||||
} break;
|
||||
}
|
||||
@@ -3984,7 +4029,9 @@ gb_internal Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_fl
|
||||
if (f->curr_token.kind != Token_Eq) {
|
||||
type = parse_var_type(f, allow_ellipsis, allow_typeid_token);
|
||||
Ast *tt = unparen_expr(type);
|
||||
if (is_signature && !any_polymorphic_names && tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
|
||||
if (is_signature && !any_polymorphic_names &&
|
||||
tt != nullptr &&
|
||||
tt->kind == Ast_TypeidType && tt->TypeidType.specialization != nullptr) {
|
||||
syntax_error(type, "Specialization of typeid is not allowed without polymorphic names");
|
||||
}
|
||||
}
|
||||
@@ -5941,6 +5988,16 @@ gb_internal ParseFileError process_imported_file(Parser *p, ImportedFile importe
|
||||
}
|
||||
}
|
||||
|
||||
{
|
||||
String name = file->fullpath;
|
||||
name = remove_directory_from_path(name);
|
||||
name = remove_extension_from_path(name);
|
||||
|
||||
if (string_starts_with(name, str_lit("_"))) {
|
||||
syntax_error(pos, "Files cannot start with '_', got '%.*s'", LIT(file->fullpath));
|
||||
}
|
||||
}
|
||||
|
||||
if (build_context.command_kind == Command_test) {
|
||||
String name = file->fullpath;
|
||||
name = remove_extension_from_path(name);
|
||||
@@ -5951,6 +6008,7 @@ gb_internal ParseFileError process_imported_file(Parser *p, ImportedFile importe
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
if (parse_file(p, file)) {
|
||||
MUTEX_GUARD_BLOCK(&pkg->files_mutex) {
|
||||
array_add(&pkg->files, file);
|
||||
|
||||
@@ -143,7 +143,8 @@ struct TypeStruct {
|
||||
Type * soa_elem;
|
||||
i32 soa_count;
|
||||
StructSoaKind soa_kind;
|
||||
BlockingMutex mutex; // for settings offsets
|
||||
RwMutex fields_mutex;
|
||||
BlockingMutex offset_mutex; // for settings offsets
|
||||
|
||||
bool is_polymorphic;
|
||||
bool are_offsets_set : 1;
|
||||
@@ -2645,10 +2646,14 @@ gb_internal bool are_types_identical_internal(Type *x, Type *y, bool check_tuple
|
||||
return are_types_identical(x->Slice.elem, y->Slice.elem);
|
||||
|
||||
case Type_BitSet:
|
||||
return are_types_identical(x->BitSet.elem, y->BitSet.elem) &&
|
||||
are_types_identical(x->BitSet.underlying, y->BitSet.underlying) &&
|
||||
x->BitSet.lower == y->BitSet.lower &&
|
||||
x->BitSet.upper == y->BitSet.upper;
|
||||
if (are_types_identical(x->BitSet.elem, y->BitSet.elem) &&
|
||||
are_types_identical(x->BitSet.underlying, y->BitSet.underlying)) {
|
||||
if (is_type_enum(x->BitSet.elem)) {
|
||||
return true;
|
||||
}
|
||||
return x->BitSet.lower == y->BitSet.lower && x->BitSet.upper == y->BitSet.upper;
|
||||
}
|
||||
return false;
|
||||
|
||||
|
||||
case Type_Enum:
|
||||
@@ -2951,7 +2956,11 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) {
|
||||
gbAllocator a = permanent_allocator();
|
||||
isize max_count = 0;
|
||||
switch (type->kind) {
|
||||
case Type_Struct: max_count = type->Struct.fields.count; break;
|
||||
case Type_Struct:
|
||||
rw_mutex_shared_lock(&type->Struct.fields_mutex);
|
||||
max_count = type->Struct.fields.count;
|
||||
rw_mutex_shared_unlock(&type->Struct.fields_mutex);
|
||||
break;
|
||||
case Type_Tuple: max_count = type->Tuple.variables.count; break;
|
||||
}
|
||||
|
||||
@@ -2960,7 +2969,9 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) {
|
||||
}
|
||||
|
||||
switch (type->kind) {
|
||||
case Type_Struct:
|
||||
case Type_Struct: {
|
||||
rw_mutex_shared_lock(&type->Struct.fields_mutex);
|
||||
defer (rw_mutex_shared_unlock(&type->Struct.fields_mutex));
|
||||
for (isize i = 0; i < max_count; i++) {
|
||||
Entity *f = type->Struct.fields[i];
|
||||
if (f->kind == Entity_Variable) {
|
||||
@@ -2971,7 +2982,8 @@ gb_internal Selection lookup_field_from_index(Type *type, i64 index) {
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
} break;
|
||||
|
||||
case Type_Tuple:
|
||||
for (isize i = 0; i < max_count; i++) {
|
||||
Entity *f = type->Tuple.variables[i];
|
||||
@@ -3024,7 +3036,10 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
|
||||
}
|
||||
}
|
||||
if (type->kind == Type_Struct) {
|
||||
for_array(i, type->Struct.fields) {
|
||||
rw_mutex_shared_lock(&type->Struct.fields_mutex);
|
||||
isize field_count = type->Struct.fields.count;
|
||||
rw_mutex_shared_unlock(&type->Struct.fields_mutex);
|
||||
if (field_count != 0) for_array(i, type->Struct.fields) {
|
||||
Entity *f = type->Struct.fields[i];
|
||||
if (f->flags&EntityFlag_Using) {
|
||||
sel = lookup_field_with_selection(f->type, field_name, is_type, sel, allow_blank_ident);
|
||||
@@ -3052,7 +3067,9 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
|
||||
}
|
||||
|
||||
if (type->kind == Type_Struct) {
|
||||
rw_mutex_shared_lock(&type->Struct.fields_mutex);
|
||||
Scope *s = type->Struct.scope;
|
||||
rw_mutex_shared_unlock(&type->Struct.fields_mutex);
|
||||
if (s != nullptr) {
|
||||
Entity *found = scope_lookup_current(s, field_name);
|
||||
if (found != nullptr && found->kind != Entity_Variable) {
|
||||
@@ -3100,7 +3117,10 @@ gb_internal Selection lookup_field_with_selection(Type *type_, String field_name
|
||||
}
|
||||
}
|
||||
|
||||
for_array(i, type->Struct.fields) {
|
||||
rw_mutex_shared_lock(&type->Struct.fields_mutex);
|
||||
isize field_count = type->Struct.fields.count;
|
||||
rw_mutex_shared_unlock(&type->Struct.fields_mutex);
|
||||
if (field_count != 0) for_array(i, type->Struct.fields) {
|
||||
Entity *f = type->Struct.fields[i];
|
||||
if (f->kind != Entity_Variable || (f->flags & EntityFlag_Field) == 0) {
|
||||
continue;
|
||||
@@ -3680,7 +3700,7 @@ gb_internal i64 *type_set_offsets_of(Slice<Entity *> const &fields, bool is_pack
|
||||
gb_internal bool type_set_offsets(Type *t) {
|
||||
t = base_type(t);
|
||||
if (t->kind == Type_Struct) {
|
||||
MUTEX_GUARD(&t->Struct.mutex);
|
||||
MUTEX_GUARD(&t->Struct.offset_mutex);
|
||||
if (!t->Struct.are_offsets_set) {
|
||||
t->Struct.are_offsets_being_processed = true;
|
||||
t->Struct.offsets = type_set_offsets_of(t->Struct.fields, t->Struct.is_packed, t->Struct.is_raw_union);
|
||||
|
||||
@@ -33,6 +33,7 @@ main :: proc() {
|
||||
marshal_json(&t)
|
||||
unmarshal_json(&t)
|
||||
surrogate(&t)
|
||||
utf8_string_of_multibyte_characters(&t)
|
||||
|
||||
fmt.printf("%v/%v tests successful.\n", TEST_count - TEST_fail, TEST_count)
|
||||
if TEST_fail > 0 {
|
||||
@@ -359,3 +360,10 @@ surrogate :: proc(t: ^testing.T) {
|
||||
expect(t, uerr == nil, fmt.tprintf("Expected `json.unmarshal(%q)` to return a nil error, got %v", string(out), uerr))
|
||||
expect(t, back == input, fmt.tprintf("Expected `json.unmarshal(%q)` to return %q, got %v", string(out), input, uerr))
|
||||
}
|
||||
|
||||
@test
|
||||
utf8_string_of_multibyte_characters :: proc(t: ^testing.T) {
|
||||
_, err := json.parse_string(`"🐛✅"`)
|
||||
msg := fmt.tprintf("Expected `json.parse` to return nil, got %v", err)
|
||||
expect(t, err == nil, msg)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user