Struct field tags

This commit is contained in:
gingerBill
2019-08-09 21:59:58 +01:00
parent 65d41d4248
commit 9c63212824
9 changed files with 127 additions and 32 deletions
+12 -8
View File
@@ -435,7 +435,9 @@ Field_Flag :: enum {
C_Vararg,
Auto_Cast,
In,
Results,
Tags,
Default_Parameters,
Typeid_Token,
}
@@ -443,18 +445,19 @@ Field_Flag :: enum {
Field_Flags :: distinct bit_set[Field_Flag];
Field_Flags_Struct :: Field_Flags{
Field_Flag.Using,
.Using,
.Tags,
};
Field_Flags_Record_Poly_Params :: Field_Flags{
Field_Flag.Typeid_Token,
.Typeid_Token,
};
Field_Flags_Signature :: Field_Flags{
Field_Flag.Ellipsis,
Field_Flag.Using,
Field_Flag.No_Alias,
Field_Flag.C_Vararg,
Field_Flag.Auto_Cast,
Field_Flag.Default_Parameters,
.Ellipsis,
.Using,
.No_Alias,
.C_Vararg,
.Auto_Cast,
.Default_Parameters,
};
Field_Flags_Signature_Params :: Field_Flags_Signature | {Field_Flag.Typeid_Token};
@@ -483,6 +486,7 @@ Field :: struct {
names: []^Expr, // Could be polymorphic
type: ^Expr,
default_value: ^Expr,
tag: token.Token,
flags: Field_Flags,
comment: ^Comment_Group,
}
+17 -7
View File
@@ -1388,19 +1388,18 @@ check_field_flag_prefixes :: proc(p: ^Parser, name_count: int, allowed_flags, se
for flag in ast.Field_Flag {
if flag notin allowed_flags && flag in flags {
using ast.Field_Flag;
#complete switch flag {
case Using:
case .Using:
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");
case C_Vararg:
case .C_Vararg:
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");
case In:
case .In:
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");
}
flags &~= {flag};
@@ -1540,6 +1539,7 @@ parse_field_list :: proc(p: ^Parser, follow: token.Kind, allowed_flags: ast.Fiel
type: ^ast.Expr;
default_value: ^ast.Expr;
tag: token.Token;
expect_token_after(p, token.Colon, "field list");
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");
}
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);
field := new_ast_field(names, type, default_value);
field.tag = tag;
field.docs = docs;
field.flags = flags;
field.comment = p.line_comment;
+3 -2
View File
@@ -79,8 +79,9 @@ Type_Info_Tuple :: struct { // Only really used for procedures
Type_Info_Struct :: struct {
types: []^Type_Info,
names: []string,
offsets: []uintptr, // offsets may not be used in tuples
usings: []bool, // usings may not be used in tuples
offsets: []uintptr,
usings: []bool,
tags: []string,
is_packed: bool,
is_raw_union: bool,
custom_align: bool,
+25
View File
@@ -3,6 +3,7 @@ package main
import "core:fmt"
import "core:mem"
import "core:os"
import "core:runtime"
when os.OS == "windows" {
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() {
when true {
general_stuff();
@@ -963,5 +987,6 @@ main :: proc() {
bit_set_type();
diverging_procedures();
deferred_procedure_associations();
struct_field_tags();
}
}
+4 -2
View File
@@ -110,9 +110,10 @@ bool does_field_type_allow_using(Type *t) {
return false;
}
void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<Ast *> const &params,
void check_struct_fields(CheckerContext *ctx, Ast *node, Array<Entity *> *fields, Array<String> *tags, Array<Ast *> const &params,
isize init_field_capacity, Type *struct_type, String context) {
*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(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);
add_entity(ctx->checker, ctx->scope, name, field);
array_add(fields, field);
array_add(tags, p->tag.string);
field_src_index += 1;
}
@@ -504,7 +506,7 @@ void check_struct_type(CheckerContext *ctx, Type *struct_type, Ast *node, Array<
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) {
+33 -4
View File
@@ -174,6 +174,7 @@ gbAllocator ir_allocator(void) {
#define IR_TYPE_INFO_NAMES_NAME "__$type_info_names_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_TAGS_NAME "__$type_info_tags_data"
#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_offsets = 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_member_types_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_usings_index = 0;
gb_global i32 ir_global_type_info_member_tags_index = 0;
isize ir_type_info_count(CheckerInfo *info) {
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);
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;
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_raw_union = ir_const_bool(t->Struct.is_raw_union);
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_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, 5), is_packed);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 6), is_raw_union);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 7), is_custom_align);
}
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_offsets = ir_type_info_member_offsets_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
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 *type_info = ir_emit_ptr_offset(proc, memory_types, 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));
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, 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);
@@ -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, 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, 4), memory_tags, cv);
}
break;
}
+29 -8
View File
@@ -805,13 +805,14 @@ Ast *ast_bad_decl(AstFile *f, Token begin, Token end) {
return result;
}
Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags,
CommentGroup *docs, CommentGroup *comment) {
Ast *ast_field(AstFile *f, Array<Ast *> names, Ast *type, Ast *default_value, u32 flags, Token tag,
CommentGroup *docs, CommentGroup *comment) {
Ast *result = alloc_ast_node(f, Ast_Field);
result->Field.names = names;
result->Field.type = type;
result->Field.default_value = default_value;
result->Field.flags = flags;
result->Field.tag = tag;
result->Field.docs = docs;
result->Field.comment = comment;
return result;
@@ -2740,7 +2741,8 @@ Ast *parse_results(AstFile *f, bool *diverging) {
Array<Ast *> empty_names = {};
auto list = array_make<Ast *>(heap_allocator(), 0, 1);
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);
}
@@ -3095,6 +3097,7 @@ Ast *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKi
Ast *type = nullptr;
Ast *default_value = nullptr;
Token tag = {};
expect_token_after(f, Token_Colon, "field list");
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");
}
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);
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(&params, param);
while (f->curr_token.kind != follow &&
f->curr_token.kind != Token_EOF) {
CommentGroup *docs = f->lead_comment;
u32 set_flags = parse_field_prefixes(f);
Token tag = {};
Array<Ast *> names = parse_ident_list(f, allow_poly_names);
if (names.count == 0) {
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");
}
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);
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(&params, param);
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;
names[0] = ast_ident(f, token);
u32 flags = check_field_prefixes(f, list.count, allowed_flags, list[i].flags);
Ast *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment);
Token tag = {};
Ast *param = ast_field(f, names, list[i].node, nullptr, flags, tag, docs, f->line_comment);
array_add(&params, param);
}
+3 -1
View File
@@ -186,11 +186,12 @@ enum FieldFlag {
FieldFlag_c_vararg = 1<<3,
FieldFlag_auto_cast = 1<<4,
FieldFlag_Tags = 1<<10,
FieldFlag_Results = 1<<16,
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 {
@@ -412,6 +413,7 @@ AST_KIND(_DeclEnd, "", bool) \
Array<Ast *> names; \
Ast * type; \
Ast * default_value; \
Token tag; \
u32 flags; \
CommentGroup * docs; \
CommentGroup * comment; \
+1
View File
@@ -107,6 +107,7 @@ struct BasicType {
struct TypeStruct {
Array<Entity *> fields;
Array<String> tags;
Ast *node;
Scope * scope;