mirror of
https://github.com/Ed94/Odin.git
synced 2026-08-07 08:08:50 +00:00
Struct field tags
This commit is contained in:
+12
-8
@@ -435,7 +435,9 @@ Field_Flag :: enum {
|
|||||||
C_Vararg,
|
C_Vararg,
|
||||||
Auto_Cast,
|
Auto_Cast,
|
||||||
In,
|
In,
|
||||||
|
|
||||||
Results,
|
Results,
|
||||||
|
Tags,
|
||||||
Default_Parameters,
|
Default_Parameters,
|
||||||
Typeid_Token,
|
Typeid_Token,
|
||||||
}
|
}
|
||||||
@@ -443,18 +445,19 @@ Field_Flag :: enum {
|
|||||||
Field_Flags :: distinct bit_set[Field_Flag];
|
Field_Flags :: distinct bit_set[Field_Flag];
|
||||||
|
|
||||||
Field_Flags_Struct :: Field_Flags{
|
Field_Flags_Struct :: Field_Flags{
|
||||||
Field_Flag.Using,
|
.Using,
|
||||||
|
.Tags,
|
||||||
};
|
};
|
||||||
Field_Flags_Record_Poly_Params :: Field_Flags{
|
Field_Flags_Record_Poly_Params :: Field_Flags{
|
||||||
Field_Flag.Typeid_Token,
|
.Typeid_Token,
|
||||||
};
|
};
|
||||||
Field_Flags_Signature :: Field_Flags{
|
Field_Flags_Signature :: Field_Flags{
|
||||||
Field_Flag.Ellipsis,
|
.Ellipsis,
|
||||||
Field_Flag.Using,
|
.Using,
|
||||||
Field_Flag.No_Alias,
|
.No_Alias,
|
||||||
Field_Flag.C_Vararg,
|
.C_Vararg,
|
||||||
Field_Flag.Auto_Cast,
|
.Auto_Cast,
|
||||||
Field_Flag.Default_Parameters,
|
.Default_Parameters,
|
||||||
};
|
};
|
||||||
|
|
||||||
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
|
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
|
||||||
@@ -483,6 +486,7 @@ Field :: struct {
|
|||||||
names: []^Expr, // Could be polymorphic
|
names: []^Expr, // Could be polymorphic
|
||||||
type: ^Expr,
|
type: ^Expr,
|
||||||
default_value: ^Expr,
|
default_value: ^Expr,
|
||||||
|
tag: token.Token,
|
||||||
flags: Field_Flags,
|
flags: Field_Flags,
|
||||||
comment: ^Comment_Group,
|
comment: ^Comment_Group,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1388,19 +1388,18 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
|
|||||||
|
|
||||||
for flag in ast.Field_Flag {
|
for flag in ast.Field_Flag {
|
||||||
if flag notin allowed_flags && flag in flags {
|
if flag notin allowed_flags && flag in flags {
|
||||||
using ast.Field_Flag;
|
|
||||||
#complete switch flag {
|
#complete switch flag {
|
||||||
case Using:
|
case .Using:
|
||||||
error(p, p.curr_tok.pos, "'using' is not allowed within this field list");
|
error(p, p.curr_tok.pos, "'using' is not allowed within this field list");
|
||||||
case No_Alias:
|
case .No_Alias:
|
||||||
error(p, p.curr_tok.pos, "'#no_alias' is not allowed within this field list");
|
error(p, p.curr_tok.pos, "'#no_alias' is not allowed within this field list");
|
||||||
case C_Vararg:
|
case .C_Vararg:
|
||||||
error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list");
|
error(p, p.curr_tok.pos, "'#c_vararg' is not allowed within this field list");
|
||||||
case Auto_Cast:
|
case .Auto_Cast:
|
||||||
error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list");
|
error(p, p.curr_tok.pos, "'auto_cast' is not allowed within this field list");
|
||||||
case In:
|
case .In:
|
||||||
error(p, p.curr_tok.pos, "'in' is not allowed within this field list");
|
error(p, p.curr_tok.pos, "'in' is not allowed within this field list");
|
||||||
case Ellipsis, Results, Default_Parameters, Typeid_Token:
|
case .Tags, .Ellipsis, .Results, .Default_Parameters, .Typeid_Token:
|
||||||
panic("Impossible prefixes");
|
panic("Impossible prefixes");
|
||||||
}
|
}
|
||||||
flags &~= {flag};
|
flags &~= {flag};
|
||||||
@@ -1540,6 +1539,7 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel
|
|||||||
|
|
||||||
type: ^ast.Expr;
|
type: ^ast.Expr;
|
||||||
default_value: ^ast.Expr;
|
default_value: ^ast.Expr;
|
||||||
|
tag: token.Token;
|
||||||
|
|
||||||
expect_token_after(p, token.Colon, "field list");
|
expect_token_after(p, token.Colon, "field list");
|
||||||
if p.curr_tok.kind != token.Eq {
|
if p.curr_tok.kind != token.Eq {
|
||||||
@@ -1579,9 +1579,19 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel
|
|||||||
error(p, p.curr_tok.pos, "extra parameter after ellipsis without a default value");
|
error(p, p.curr_tok.pos, "extra parameter after ellipsis without a default value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if type != nil && default_value == nil {
|
||||||
|
if p.curr_tok.kind == token.String {
|
||||||
|
tag = expect_token(p, token.String);
|
||||||
|
if .Tags notin allowed_flags {
|
||||||
|
error(p, tag.pos, "Field tags are only allowed within structures");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
ok := expect_field_separator(p, type);
|
ok := expect_field_separator(p, type);
|
||||||
|
|
||||||
field := new_ast_field(names, type, default_value);
|
field := new_ast_field(names, type, default_value);
|
||||||
|
field.tag = tag;
|
||||||
field.docs = docs;
|
field.docs = docs;
|
||||||
field.flags = flags;
|
field.flags = flags;
|
||||||
field.comment = p.line_comment;
|
field.comment = p.line_comment;
|
||||||
|
|||||||
@@ -79,8 +79,9 @@ Type_Info_Tuple :: struct { // Only really used for procedures
|
|||||||
Type_Info_Struct :: struct {
|
Type_Info_Struct :: struct {
|
||||||
types: []^Type_Info,
|
types: []^Type_Info,
|
||||||
names: []string,
|
names: []string,
|
||||||
offsets: []uintptr, // offsets may not be used in tuples
|
offsets: []uintptr,
|
||||||
usings: []bool, // usings may not be used in tuples
|
usings: []bool,
|
||||||
|
tags: []string,
|
||||||
is_packed: bool,
|
is_packed: bool,
|
||||||
is_raw_union: bool,
|
is_raw_union: bool,
|
||||||
custom_align: bool,
|
custom_align: bool,
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ package main
|
|||||||
import "core:fmt"
|
import "core:fmt"
|
||||||
import "core:mem"
|
import "core:mem"
|
||||||
import "core:os"
|
import "core:os"
|
||||||
|
import "core:runtime"
|
||||||
|
|
||||||
when os.OS == "windows" {
|
when os.OS == "windows" {
|
||||||
import "core:thread"
|
import "core:thread"
|
||||||
@@ -945,6 +946,29 @@ deferred_procedure_associations :: proc() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct_field_tags :: proc() {
|
||||||
|
fmt.println("# struct_field_tags");
|
||||||
|
|
||||||
|
Foo :: struct {
|
||||||
|
x: int `tag1`,
|
||||||
|
y: string `tag2`,
|
||||||
|
z: bool, // no tag
|
||||||
|
}
|
||||||
|
|
||||||
|
f: Foo;
|
||||||
|
ti := runtime.type_info_base(type_info_of(Foo));
|
||||||
|
s := ti.variant.(runtime.Type_Info_Struct);
|
||||||
|
fmt.println("Foo :: struct {");
|
||||||
|
for _, i in s.names {
|
||||||
|
if tag := s.tags[i]; tag != "" {
|
||||||
|
fmt.printf("\t%s: %T `%s`,\n", s.names[i], s.types[i], tag);
|
||||||
|
} else {
|
||||||
|
fmt.printf("\t%s: %T,\n", s.names[i], s.types[i]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
fmt.println("}");
|
||||||
|
}
|
||||||
|
|
||||||
main :: proc() {
|
main :: proc() {
|
||||||
when true {
|
when true {
|
||||||
general_stuff();
|
general_stuff();
|
||||||
@@ -963,5 +987,6 @@ main :: proc() {
|
|||||||
bit_set_type();
|
bit_set_type();
|
||||||
diverging_procedures();
|
diverging_procedures();
|
||||||
deferred_procedure_associations();
|
deferred_procedure_associations();
|
||||||
|
struct_field_tags();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+4
-2
@@ -110,9 +110,10 @@ bool does_field_type_allow_using(Type *t) {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<Ast *> const ¶ms,
|
void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<String> *tags, Array<Ast *> const ¶ms,
|
||||||
isize init_field_capacity, Type *struct_type, String context) {
|
isize init_field_capacity, Type *struct_type, String context) {
|
||||||
*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
|
*fields = array_make<Entity *>(heap_allocator(), 0, init_field_capacity);
|
||||||
|
*tags = array_make<String>(heap_allocator(), 0, init_field_capacity);
|
||||||
|
|
||||||
GB_ASSERT(node->kind == Ast_StructType);
|
GB_ASSERT(node->kind == Ast_StructType);
|
||||||
GB_ASSERT(struct_type->kind == Type_Struct);
|
GB_ASSERT(struct_type->kind == Type_Struct);
|
||||||
@@ -171,6 +172,7 @@ void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields
|
|||||||
Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
|
Entity *field = alloc_entity_field(ctx->scope, name_token, type, is_using, field_src_index);
|
||||||
add_entity(ctx->checker, ctx->scope, name, field);
|
add_entity(ctx->checker, ctx->scope, name, field);
|
||||||
array_add(fields, field);
|
array_add(fields, field);
|
||||||
|
array_add(tags, p->tag.string);
|
||||||
|
|
||||||
field_src_index += 1;
|
field_src_index += 1;
|
||||||
}
|
}
|
||||||
@@ -504,7 +506,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
|
|||||||
|
|
||||||
|
|
||||||
if (!is_polymorphic) {
|
if (!is_polymorphic) {
|
||||||
check_struct_fields(ctx, node, &struct_type->Struct.fields, st->fields, min_field_count, struct_type, context);
|
check_struct_fields(ctx, node, &struct_type->Struct.fields, &struct_type->Struct.tags, st->fields, min_field_count, struct_type, context);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (st->align != nullptr) {
|
if (st->align != nullptr) {
|
||||||
|
|||||||
+33
-4
@@ -174,6 +174,7 @@ gbAllocator ir_allocator(void) {
|
|||||||
#define IR_TYPE_INFO_NAMES_NAME "__$type_info_names_data"
|
#define IR_TYPE_INFO_NAMES_NAME "__$type_info_names_data"
|
||||||
#define IR_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data"
|
#define IR_TYPE_INFO_OFFSETS_NAME "__$type_info_offsets_data"
|
||||||
#define IR_TYPE_INFO_USINGS_NAME "__$type_info_usings_data"
|
#define IR_TYPE_INFO_USINGS_NAME "__$type_info_usings_data"
|
||||||
|
#define IR_TYPE_INFO_TAGS_NAME "__$type_info_tags_data"
|
||||||
|
|
||||||
|
|
||||||
#define IR_INSTR_KINDS \
|
#define IR_INSTR_KINDS \
|
||||||
@@ -5271,12 +5272,14 @@ gb_global irValue *ir_global_type_info_member_types = nullptr;
|
|||||||
gb_global irValue *ir_global_type_info_member_names = nullptr;
|
gb_global irValue *ir_global_type_info_member_names = nullptr;
|
||||||
gb_global irValue *ir_global_type_info_member_offsets = nullptr;
|
gb_global irValue *ir_global_type_info_member_offsets = nullptr;
|
||||||
gb_global irValue *ir_global_type_info_member_usings = nullptr;
|
gb_global irValue *ir_global_type_info_member_usings = nullptr;
|
||||||
|
gb_global irValue *ir_global_type_info_member_tags = nullptr;
|
||||||
|
|
||||||
gb_global i32 ir_global_type_info_data_index = 0;
|
gb_global i32 ir_global_type_info_data_index = 0;
|
||||||
gb_global i32 ir_global_type_info_member_types_index = 0;
|
gb_global i32 ir_global_type_info_member_types_index = 0;
|
||||||
gb_global i32 ir_global_type_info_member_names_index = 0;
|
gb_global i32 ir_global_type_info_member_names_index = 0;
|
||||||
gb_global i32 ir_global_type_info_member_offsets_index = 0;
|
gb_global i32 ir_global_type_info_member_offsets_index = 0;
|
||||||
gb_global i32 ir_global_type_info_member_usings_index = 0;
|
gb_global i32 ir_global_type_info_member_usings_index = 0;
|
||||||
|
gb_global i32 ir_global_type_info_member_tags_index = 0;
|
||||||
|
|
||||||
isize ir_type_info_count(CheckerInfo *info) {
|
isize ir_type_info_count(CheckerInfo *info) {
|
||||||
return info->minimum_dependency_type_info_set.entries.count+1;
|
return info->minimum_dependency_type_info_set.entries.count+1;
|
||||||
@@ -9587,6 +9590,16 @@ void ir_init_module(irModule *m, Checker *c) {
|
|||||||
map_set(&m->members, hash_string(name), g);
|
map_set(&m->members, hash_string(name), g);
|
||||||
ir_global_type_info_member_usings = g;
|
ir_global_type_info_member_usings = g;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
{
|
||||||
|
String name = str_lit(IR_TYPE_INFO_TAGS_NAME);
|
||||||
|
Entity *e = alloc_entity_variable(nullptr, make_token_ident(name),
|
||||||
|
alloc_type_array(t_string, count), false);
|
||||||
|
irValue *g = ir_value_global(e, nullptr);
|
||||||
|
ir_module_add_value(m, e, g);
|
||||||
|
map_set(&m->members, hash_string(name), g);
|
||||||
|
ir_global_type_info_member_tags = g;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -9720,6 +9733,11 @@ irValue *ir_type_info_member_usings_offset(irProcedure *proc, isize count) {
|
|||||||
ir_global_type_info_member_usings_index += cast(i32)count;
|
ir_global_type_info_member_usings_index += cast(i32)count;
|
||||||
return offset;
|
return offset;
|
||||||
}
|
}
|
||||||
|
irValue *ir_type_info_member_tags_offset(irProcedure *proc, isize count) {
|
||||||
|
irValue *offset = ir_emit_array_epi(proc, ir_global_type_info_member_tags, ir_global_type_info_member_tags_index);
|
||||||
|
ir_global_type_info_member_tags_index += cast(i32)count;
|
||||||
|
return offset;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -10065,9 +10083,9 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
|||||||
irValue *is_packed = ir_const_bool(t->Struct.is_packed);
|
irValue *is_packed = ir_const_bool(t->Struct.is_packed);
|
||||||
irValue *is_raw_union = ir_const_bool(t->Struct.is_raw_union);
|
irValue *is_raw_union = ir_const_bool(t->Struct.is_raw_union);
|
||||||
irValue *is_custom_align = ir_const_bool(t->Struct.custom_align != 0);
|
irValue *is_custom_align = ir_const_bool(t->Struct.custom_align != 0);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 4), is_packed);
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_packed);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 5), is_raw_union);
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union);
|
||||||
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_custom_align);
|
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align);
|
||||||
}
|
}
|
||||||
|
|
||||||
isize count = t->Struct.fields.count;
|
isize count = t->Struct.fields.count;
|
||||||
@@ -10076,6 +10094,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
|||||||
irValue *memory_names = ir_type_info_member_names_offset (proc, count);
|
irValue *memory_names = ir_type_info_member_names_offset (proc, count);
|
||||||
irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, count);
|
irValue *memory_offsets = ir_type_info_member_offsets_offset(proc, count);
|
||||||
irValue *memory_usings = ir_type_info_member_usings_offset (proc, count);
|
irValue *memory_usings = ir_type_info_member_usings_offset (proc, count);
|
||||||
|
irValue *memory_tags = ir_type_info_member_tags_offset (proc, count);
|
||||||
|
|
||||||
type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet
|
type_set_offsets(t); // NOTE(bill): Just incase the offsets have not been set yet
|
||||||
for (isize source_index = 0; source_index < count; source_index++) {
|
for (isize source_index = 0; source_index < count; source_index++) {
|
||||||
@@ -10091,7 +10110,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
|||||||
irValue *index = ir_const_int(source_index);
|
irValue *index = ir_const_int(source_index);
|
||||||
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
|
irValue *type_info = ir_emit_ptr_offset(proc, memory_types, index);
|
||||||
irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, index);
|
irValue *offset = ir_emit_ptr_offset(proc, memory_offsets, index);
|
||||||
irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index);
|
irValue *is_using = ir_emit_ptr_offset(proc, memory_usings, index);
|
||||||
|
|
||||||
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
|
ir_emit_store(proc, type_info, ir_type_info(proc, f->type));
|
||||||
if (f->token.string.len > 0) {
|
if (f->token.string.len > 0) {
|
||||||
@@ -10100,6 +10119,15 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
|||||||
}
|
}
|
||||||
ir_emit_store(proc, offset, ir_const_uintptr(foffset));
|
ir_emit_store(proc, offset, ir_const_uintptr(foffset));
|
||||||
ir_emit_store(proc, is_using, ir_const_bool((f->flags&EntityFlag_Using) != 0));
|
ir_emit_store(proc, is_using, ir_const_bool((f->flags&EntityFlag_Using) != 0));
|
||||||
|
|
||||||
|
if (t->Struct.tags.count > 0) {
|
||||||
|
String tag_string = t->Struct.tags[source_index];
|
||||||
|
if (tag_string.len > 0) {
|
||||||
|
irValue *tag_ptr = ir_emit_ptr_offset(proc, memory_tags, index);
|
||||||
|
ir_emit_store(proc, tag_ptr, ir_const_string(tag_string));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
irValue *cv = ir_const_int(count);
|
irValue *cv = ir_const_int(count);
|
||||||
@@ -10107,6 +10135,7 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
|
|||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, cv);
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 1), memory_names, cv);
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, cv);
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 2), memory_offsets, cv);
|
||||||
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings, cv);
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 3), memory_usings, cv);
|
||||||
|
ir_fill_slice(proc, ir_emit_struct_ep(proc, tag, 4), memory_tags, cv);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|||||||
+29
-8
@@ -805,13 +805,14 @@ Ast *ast_bad_decl(AstFile *f, Token begin, Token end) {
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags,
|
Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags, Token tag,
|
||||||
CommentGroup *docs, CommentGroup *comment) {
|
CommentGroup *docs, CommentGroup *comment) {
|
||||||
Ast *result = alloc_ast_node(f, Ast_Field);
|
Ast *result = alloc_ast_node(f, Ast_Field);
|
||||||
result->Field.names = names;
|
result->Field.names = names;
|
||||||
result->Field.type = type;
|
result->Field.type = type;
|
||||||
result->Field.default_value = default_value;
|
result->Field.default_value = default_value;
|
||||||
result->Field.flags = flags;
|
result->Field.flags = flags;
|
||||||
|
result->Field.tag = tag;
|
||||||
result->Field.docs = docs;
|
result->Field.docs = docs;
|
||||||
result->Field.comment = comment;
|
result->Field.comment = comment;
|
||||||
return result;
|
return result;
|
||||||
@@ -2740,7 +2741,8 @@ Ast *parse_results(AstFile *f, bool *diverging) {
|
|||||||
Array<Ast *> empty_names = {};
|
Array<Ast *> empty_names = {};
|
||||||
auto list = array_make<Ast *>(heap_allocator(), 0, 1);
|
auto list = array_make<Ast *>(heap_allocator(), 0, 1);
|
||||||
Ast *type = parse_type(f);
|
Ast *type = parse_type(f);
|
||||||
array_add(&list, ast_field(f, empty_names, type, nullptr, 0, nullptr, nullptr));
|
Token tag = {};
|
||||||
|
array_add(&list, ast_field(f, empty_names, type, nullptr, 0, tag, nullptr, nullptr));
|
||||||
return ast_field_list(f, begin_token, list);
|
return ast_field_list(f, begin_token, list);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -3095,6 +3097,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
|
|
||||||
Ast *type = nullptr;
|
Ast *type = nullptr;
|
||||||
Ast *default_value = nullptr;
|
Ast *default_value = nullptr;
|
||||||
|
Token tag = {};
|
||||||
|
|
||||||
expect_token_after(f, Token_Colon, "field list");
|
expect_token_after(f, Token_Colon, "field list");
|
||||||
if (f->curr_token.kind != Token_Eq) {
|
if (f->curr_token.kind != Token_Eq) {
|
||||||
@@ -3132,16 +3135,25 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
|
syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type != nullptr && default_value == nullptr) {
|
||||||
|
if (f->curr_token.kind == Token_String) {
|
||||||
|
tag = expect_token(f, Token_String);
|
||||||
|
if ((allowed_flags & FieldFlag_Tags) == 0) {
|
||||||
|
syntax_error(tag, "Field tags are only allowed within structures");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
parse_expect_field_separator(f, type);
|
parse_expect_field_separator(f, type);
|
||||||
Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
|
Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
|
||||||
array_add(¶ms, param);
|
array_add(¶ms, param);
|
||||||
|
|
||||||
|
|
||||||
while (f->curr_token.kind != follow &&
|
while (f->curr_token.kind != follow &&
|
||||||
f->curr_token.kind != Token_EOF) {
|
f->curr_token.kind != Token_EOF) {
|
||||||
CommentGroup *docs = f->lead_comment;
|
CommentGroup *docs = f->lead_comment;
|
||||||
|
|
||||||
u32 set_flags = parse_field_prefixes(f);
|
u32 set_flags = parse_field_prefixes(f);
|
||||||
|
Token tag = {};
|
||||||
Array<Ast *> names = parse_ident_list(f, allow_poly_names);
|
Array<Ast *> names = parse_ident_list(f, allow_poly_names);
|
||||||
if (names.count == 0) {
|
if (names.count == 0) {
|
||||||
syntax_error(f->curr_token, "Empty field declaration");
|
syntax_error(f->curr_token, "Empty field declaration");
|
||||||
@@ -3184,9 +3196,18 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
|
syntax_error(f->curr_token, "Extra parameter after ellipsis without a default value");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (type != nullptr && default_value == nullptr) {
|
||||||
|
if (f->curr_token.kind == Token_String) {
|
||||||
|
tag = expect_token(f, Token_String);
|
||||||
|
if ((allowed_flags & FieldFlag_Tags) == 0) {
|
||||||
|
syntax_error(tag, "Field tags are only allowed within structures");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
bool ok = parse_expect_field_separator(f, param);
|
bool ok = parse_expect_field_separator(f, param);
|
||||||
Ast *param = ast_field(f, names, type, default_value, set_flags, docs, f->line_comment);
|
Ast *param = ast_field(f, names, type, default_value, set_flags, tag, docs, f->line_comment);
|
||||||
array_add(¶ms, param);
|
array_add(¶ms, param);
|
||||||
|
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
@@ -3210,8 +3231,8 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
|
|||||||
token.pos = ast_token(type).pos;
|
token.pos = ast_token(type).pos;
|
||||||
names[0] = ast_ident(f, token);
|
names[0] = ast_ident(f, token);
|
||||||
u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags);
|
u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags);
|
||||||
|
Token tag = {};
|
||||||
Ast *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment);
|
Ast *param = ast_field(f, names, list[i].node, nullptr, flags, tag, docs, f->line_comment);
|
||||||
array_add(¶ms, param);
|
array_add(¶ms, param);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+3
-1
@@ -186,11 +186,12 @@ enum FieldFlag {
|
|||||||
FieldFlag_c_vararg = 1<<3,
|
FieldFlag_c_vararg = 1<<3,
|
||||||
FieldFlag_auto_cast = 1<<4,
|
FieldFlag_auto_cast = 1<<4,
|
||||||
|
|
||||||
|
FieldFlag_Tags = 1<<10,
|
||||||
|
|
||||||
FieldFlag_Results = 1<<16,
|
FieldFlag_Results = 1<<16,
|
||||||
|
|
||||||
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast,
|
FieldFlag_Signature = FieldFlag_ellipsis|FieldFlag_using|FieldFlag_no_alias|FieldFlag_c_vararg|FieldFlag_auto_cast,
|
||||||
FieldFlag_Struct = FieldFlag_using,
|
FieldFlag_Struct = FieldFlag_using|FieldFlag_Tags,
|
||||||
};
|
};
|
||||||
|
|
||||||
enum StmtAllowFlag {
|
enum StmtAllowFlag {
|
||||||
@@ -412,6 +413,7 @@ AST_KIND(_DeclEnd, "", bool) \
|
|||||||
Array<Ast *> names; \
|
Array<Ast *> names; \
|
||||||
Ast * type; \
|
Ast * type; \
|
||||||
Ast * default_value; \
|
Ast * default_value; \
|
||||||
|
Token tag; \
|
||||||
u32 flags; \
|
u32 flags; \
|
||||||
CommentGroup * docs; \
|
CommentGroup * docs; \
|
||||||
CommentGroup * comment; \
|
CommentGroup * comment; \
|
||||||
|
|||||||
@@ -107,6 +107,7 @@ struct BasicType {
|
|||||||
|
|
||||||
struct TypeStruct {
|
struct TypeStruct {
|
||||||
Array<Entity *> fields;
|
Array<Entity *> fields;
|
||||||
|
Array<String> tags;
|
||||||
Ast *node;
|
Ast *node;
|
||||||
Scope * scope;
|
Scope * scope;
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user