Skip to content

Commit 4f09085

Browse files
authored
Merge pull request odin-lang#5890 from odin-lang/bill/all_or_none
`struct #all_or_none`
2 parents ea5db0e + c937d38 commit 4f09085

File tree

15 files changed

+184
-43
lines changed

15 files changed

+184
-43
lines changed

base/runtime/core.odin

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,10 +118,10 @@ Type_Info_Parameters :: struct { // Only used for procedures parameters and resu
118118

119119
Type_Info_Struct_Flags :: distinct bit_set[Type_Info_Struct_Flag; u8]
120120
Type_Info_Struct_Flag :: enum u8 {
121-
packed = 0,
122-
raw_union = 1,
123-
_ = 2,
124-
align = 3,
121+
packed = 0,
122+
raw_union = 1,
123+
all_or_none = 2,
124+
align = 3,
125125
}
126126

127127
Type_Info_Struct :: struct {

base/runtime/print.odin

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -408,9 +408,9 @@ print_type :: #force_no_inline proc "contextless" (ti: ^Type_Info) {
408408
}
409409

410410
print_string("struct ")
411-
if .packed in info.flags { print_string("#packed ") }
412-
if .raw_union in info.flags { print_string("#raw_union ") }
413-
// if .no_copy in info.flags { print_string("#no_copy ") }
411+
if .packed in info.flags { print_string("#packed ") }
412+
if .raw_union in info.flags { print_string("#raw_union ") }
413+
if .all_or_none in info.flags { print_string("#all_or_none ") }
414414
if .align in info.flags {
415415
print_string("#align(")
416416
print_u64(u64(ti.align))

core/odin/ast/ast.odin

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -790,6 +790,7 @@ Struct_Type :: struct {
790790
is_packed: bool,
791791
is_raw_union: bool,
792792
is_no_copy: bool,
793+
is_all_or_none: bool,
793794
fields: ^Field_List,
794795
name_count: int,
795796
}

core/odin/doc-format/doc_format.odin

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,7 @@ Type_Flag_Struct :: enum u32le {
281281
Polymorphic = 0,
282282
Packed = 1,
283283
Raw_Union = 2,
284+
All_Or_None = 3,
284285
}
285286

286287
Type_Flags_Union :: distinct bit_set[Type_Flag_Union; u32le]

core/odin/parser/parser.odin

Lines changed: 28 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -2658,11 +2658,12 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
26582658
align: ^ast.Expr
26592659
min_field_align: ^ast.Expr
26602660
max_field_align: ^ast.Expr
2661-
is_packed: bool
2662-
is_raw_union: bool
2663-
is_no_copy: bool
2664-
fields: ^ast.Field_List
2665-
name_count: int
2661+
is_packed: bool
2662+
is_raw_union: bool
2663+
is_no_copy: bool
2664+
is_all_or_none: bool
2665+
fields: ^ast.Field_List
2666+
name_count: int
26662667

26672668
if allow_token(p, .Open_Paren) {
26682669
param_count: int
@@ -2684,6 +2685,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
26842685
error(p, tag.pos, "duplicate struct tag '#%s'", tag.text)
26852686
}
26862687
is_packed = true
2688+
case "all_or_none":
2689+
if is_all_or_none {
2690+
error(p, tag.pos, "duplicate struct tag '#%s'", tag.text)
2691+
}
2692+
is_all_or_none = true
26872693
case "align":
26882694
if align != nil {
26892695
error(p, tag.pos, "duplicate struct tag '#%s'", tag.text)
@@ -2726,6 +2732,11 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
27262732
error(p, tok.pos, "'#raw_union' cannot also be '#packed")
27272733
}
27282734

2735+
if is_raw_union && is_all_or_none {
2736+
is_all_or_none = false
2737+
error(p, tok.pos, "'#raw_union' cannot also be '#all_or_none")
2738+
}
2739+
27292740
where_token: tokenizer.Token
27302741
where_clauses: []^ast.Expr
27312742

@@ -2745,17 +2756,18 @@ parse_operand :: proc(p: ^Parser, lhs: bool) -> ^ast.Expr {
27452756
close := expect_closing_brace_of_field_list(p)
27462757

27472758
st := ast.new(ast.Struct_Type, tok.pos, end_pos(close))
2748-
st.poly_params = poly_params
2749-
st.align = align
2750-
st.min_field_align = min_field_align
2751-
st.max_field_align = max_field_align
2752-
st.is_packed = is_packed
2753-
st.is_raw_union = is_raw_union
2754-
st.is_no_copy = is_no_copy
2755-
st.fields = fields
2756-
st.name_count = name_count
2757-
st.where_token = where_token
2758-
st.where_clauses = where_clauses
2759+
st.poly_params = poly_params
2760+
st.align = align
2761+
st.min_field_align = min_field_align
2762+
st.max_field_align = max_field_align
2763+
st.is_packed = is_packed
2764+
st.is_raw_union = is_raw_union
2765+
st.is_no_copy = is_no_copy
2766+
st.is_all_or_none = is_all_or_none
2767+
st.fields = fields
2768+
st.name_count = name_count
2769+
st.where_token = where_token
2770+
st.where_clauses = where_clauses
27592771
return st
27602772

27612773
case .Union:

core/reflect/types.odin

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -696,9 +696,9 @@ write_type_writer :: #force_no_inline proc(w: io.Writer, ti: ^Type_Info, n_writt
696696
}
697697

698698
io.write_string(w, "struct ", &n) or_return
699-
if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return }
700-
if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return }
701-
// if .no_copy in info.flags { io.write_string(w, "#no_copy ", &n) or_return }
699+
if .packed in info.flags { io.write_string(w, "#packed ", &n) or_return }
700+
if .raw_union in info.flags { io.write_string(w, "#raw_union ", &n) or_return }
701+
if .all_or_none in info.flags { io.write_string(w, "#all_or_none ", &n) or_return }
702702
if .align in info.flags {
703703
io.write_string(w, "#align(", &n) or_return
704704
io.write_i64(w, i64(ti.align), 10, &n) or_return

src/check_expr.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9838,6 +9838,51 @@ gb_internal void check_compound_literal_field_values(CheckerContext *c, Slice<As
98389838

98399839
c->bit_field_bit_size = prev_bit_field_bit_size;
98409840
}
9841+
9842+
if (bt->kind == Type_Struct && bt->Struct.is_all_or_none && elems.count > 0 && bt->Struct.fields.count > 0) {
9843+
PtrSet<Entity *> missing_fields = {};
9844+
defer (ptr_set_destroy(&missing_fields));
9845+
9846+
for_array(i, bt->Struct.fields) {
9847+
Entity *field = bt->Struct.fields[i];
9848+
String name = field->token.string;
9849+
if (is_blank_ident(name) || name == "") {
9850+
continue;
9851+
}
9852+
bool found = string_set_exists(&fields_visited, name);
9853+
String *raw_union = string_map_get(&fields_visited_through_raw_union, name);
9854+
if (!found && raw_union == nullptr) {
9855+
ptr_set_add(&missing_fields, field);
9856+
}
9857+
}
9858+
9859+
if (missing_fields.count > 0) {
9860+
ERROR_BLOCK();
9861+
9862+
if (build_context.terse_errors) {
9863+
gbString fields_string = gb_string_make(heap_allocator(), "");
9864+
defer (gb_string_free(fields_string));
9865+
isize i = 0;
9866+
FOR_PTR_SET(field, missing_fields) {
9867+
if (i > 0) {
9868+
fields_string = gb_string_appendc(fields_string, ", ");
9869+
}
9870+
String name = field->token.string;
9871+
fields_string = gb_string_append_length(fields_string, name.text, name.len);
9872+
i += 1;
9873+
}
9874+
9875+
error(o->expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields: %s", fields_string);
9876+
} else {
9877+
error(o->expr, "All or none of the fields must be assigned to a struct with '#all_or_none' applied, missing fields:");
9878+
FOR_PTR_SET(field, missing_fields) {
9879+
gbString s = type_to_string(field->type);
9880+
error_line("\t%.*s: %s\n", LIT(field->token.string), s);
9881+
gb_string_free(s);
9882+
}
9883+
}
9884+
}
9885+
}
98419886
}
98429887

98439888
gb_internal bool is_expr_inferred_fixed_array(Ast *type_expr) {

src/check_type.cpp

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -654,9 +654,10 @@ gb_internal void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *
654654
context = str_lit("struct #raw_union");
655655
}
656656

657-
struct_type->Struct.node = node;
658-
struct_type->Struct.scope = ctx->scope;
659-
struct_type->Struct.is_packed = st->is_packed;
657+
struct_type->Struct.node = node;
658+
struct_type->Struct.scope = ctx->scope;
659+
struct_type->Struct.is_packed = st->is_packed;
660+
struct_type->Struct.is_all_or_none = st->is_all_or_none;
660661
struct_type->Struct.polymorphic_params = check_record_polymorphic_params(
661662
ctx, st->polymorphic_params,
662663
&struct_type->Struct.is_polymorphic,

src/docs_format.cpp

Lines changed: 59 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@ enum OdinDocTypeFlag_Struct : u32 {
9494
OdinDocTypeFlag_Struct_polymorphic = 1<<0,
9595
OdinDocTypeFlag_Struct_packed = 1<<1,
9696
OdinDocTypeFlag_Struct_raw_union = 1<<2,
97+
OdinDocTypeFlag_Struct_all_or_none = 1<<3,
9798
};
9899

99100
enum OdinDocTypeFlag_Union : u32 {
@@ -124,21 +125,76 @@ enum {
124125

125126
struct OdinDocType {
126127
OdinDocTypeKind kind;
128+
// Type_Kind specific used by some types
129+
// Underlying flag types:
130+
// .Basic - Type_Flags_Basic
131+
// .Struct - Type_Flags_Struct
132+
// .Union - Type_Flags_Union
133+
// .Proc - Type_Flags_Proc
134+
// .Bit_Set - Type_Flags_Bit_Set
127135
u32 flags;
136+
137+
// Used by:
138+
// .Basic
139+
// .Named
140+
// .Generic
128141
OdinDocString name;
142+
143+
// Used By: .Struct, .Union
129144
OdinDocString custom_align;
130145

131-
// Used by some types
146+
// Used by:
147+
// .Array - 1 count: 0=len
148+
// .Enumerated_Array - 1 count: 0=len
149+
// .SOA_Struct_Fixed - 1 count: 0=len
150+
// .Bit_Set - 2 count: 0=lower, 1=upper
151+
// .Simd_Vector - 1 count: 0=len
152+
// .Matrix - 2 count: 0=row_count, 1=column_count
153+
// .Struct - <=2 count: 0=min_field_align, 1=max_field_align
132154
u32 elem_count_len;
133155
i64 elem_counts[OdinDocType_ElemsCap];
134156

135-
// Each of these is esed by some types, not all
157+
// Used by: .Procedures
158+
// blank implies the "odin" calling convention
136159
OdinDocString calling_convention;
160+
161+
// Used by:
162+
// .Named - 1 type: 0=base type
163+
// .Generic - <1 type: 0=specialization
164+
// .Pointer - 1 type: 0=element
165+
// .Array - 1 type: 0=element
166+
// .Enumerated_Array - 2 types: 0=index and 1=element
167+
// .Slice - 1 type: 0=element
168+
// .Dynamic_Array - 1 type: 0=element
169+
// .Map - 2 types: 0=key, 1=value
170+
// .SOA_Struct_Fixed - 1 type: underlying SOA struct element
171+
// .SOA_Struct_Slice - 1 type: underlying SOA struct element
172+
// .SOA_Struct_Dynamic - 1 type: underlying SOA struct element
173+
// .Union - 0+ types: variants
174+
// .Enum - <1 type: 0=base type
175+
// .Proc - 2 types: 0=parameters, 1=results
176+
// .Bit_Set - <=2 types: 0=element type, 1=underlying type (Underlying_Type flag will be set)
177+
// .Simd_Vector - 1 type: 0=element
178+
// .Relative_Pointer - 2 types: 0=pointer type, 1=base integer
179+
// .Multi_Pointer - 1 type: 0=element
180+
// .Matrix - 1 type: 0=element
181+
// .Soa_Pointer - 1 type: 0=element
182+
// .Bit_Field - 1 type: 0=backing type
137183
OdinDocArray<OdinDocTypeIndex> types;
184+
185+
// Used by:
186+
// .Named - 1 field for the definition
187+
// .Struct - fields
188+
// .Enum - fields
189+
// .Parameters - parameters (procedures only)
138190
OdinDocArray<OdinDocEntityIndex> entities;
191+
192+
// Used By: .Struct, .Union
139193
OdinDocTypeIndex polmorphic_params;
194+
// Used By: .Struct, .Union
140195
OdinDocArray<OdinDocString> where_clauses;
141-
OdinDocArray<OdinDocString> tags; // struct field tags
196+
// Used By: .Struct
197+
OdinDocArray<OdinDocString> tags;
142198
};
143199

144200
struct OdinDocAttribute {

src/docs_writer.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -620,6 +620,13 @@ gb_internal OdinDocTypeIndex odin_doc_type(OdinDocWriter *w, Type *type, bool ca
620620
if (type->Struct.is_polymorphic) { doc_type.flags |= OdinDocTypeFlag_Struct_polymorphic; }
621621
if (type->Struct.is_packed) { doc_type.flags |= OdinDocTypeFlag_Struct_packed; }
622622
if (type->Struct.is_raw_union) { doc_type.flags |= OdinDocTypeFlag_Struct_raw_union; }
623+
if (type->Struct.is_all_or_none) { doc_type.flags |= OdinDocTypeFlag_Struct_all_or_none; }
624+
625+
if (type->Struct.custom_min_field_align > 0 || type->Struct.custom_max_field_align > 0) {
626+
doc_type.elem_count_len = 2;
627+
doc_type.elem_counts[0] = cast(u32)gb_max(type->Struct.custom_min_field_align, 0);
628+
doc_type.elem_counts[1] = cast(u32)gb_max(type->Struct.custom_max_field_align, 0);
629+
}
623630

624631
auto fields = array_make<OdinDocEntityIndex>(heap_allocator(), type->Struct.fields.count);
625632
defer (array_free(&fields));

0 commit comments

Comments
 (0)