Make record semicolon syntax more consistent

This commit is contained in:
Ginger Bill
2017-07-10 14:52:58 +01:00
parent 66e4aaffc5
commit 069a47220e
5 changed files with 118 additions and 160 deletions
+1 -1
View File
@@ -253,7 +253,7 @@ explicit_parametric_polymorphic_procedures :: proc() {
// A more complicated example using subtyping // A more complicated example using subtyping
// Something like this could be used in a game // Something like this could be used in a game
Vector2 :: struct {x, y: f32}; Vector2 :: struct {x, y: f32;};
Entity :: struct { Entity :: struct {
using position: Vector2; using position: Vector2;
+2 -2
View File
@@ -8,12 +8,12 @@ __multi3 :: proc(a, b: u128) -> u128 #cc_c #link_name "__multi3" {
when ODIN_ENDIAN == "bit" { when ODIN_ENDIAN == "bit" {
TWords :: raw_union { TWords :: raw_union {
all: u128; all: u128;
using _: struct {lo, hi: u64}; using _: struct {lo, hi: u64;};
}; };
} else { } else {
TWords :: raw_union { TWords :: raw_union {
all: u128; all: u128;
using _: struct {hi, lo: u64}; using _: struct {hi, lo: u64;};
}; };
} }
+2 -2
View File
@@ -10,8 +10,8 @@ import (
_BUFFER_SIZE :: 1<<12; _BUFFER_SIZE :: 1<<12;
StringBuffer :: union { StringBuffer :: union {
Static {buf: []u8}; Static {buf: []u8;};
Dynamic{buf: [dynamic]u8}; Dynamic{buf: [dynamic]u8;};
} }
FmtInfo :: struct { FmtInfo :: struct {
+40 -20
View File
@@ -710,21 +710,36 @@ isize check_fields(Checker *c, AstNode *node, Array<AstNode *> decls,
isize field_index = 0; isize field_index = 0;
for_array(decl_index, decls) { for_array(decl_index, decls) {
AstNode *decl = decls[decl_index]; AstNode *decl = decls[decl_index];
if (decl->kind != AstNode_Field) { if (decl->kind != AstNode_ValueDecl) {
continue; continue;
} }
ast_node(f, Field, decl); ast_node(vd, ValueDecl, decl);
Type *type = check_type(c, f->type); Type *type = nullptr;
bool is_using = (f->flags&FieldFlag_using) != 0; if (vd->type != nullptr) {
type = check_type(c, vd->type);
} else {
error(vd->names[0], "Expected a type for this field");
type = t_invalid;
}
bool is_using = (vd->flags&VarDeclFlag_using) != 0;
if (is_using && f->names.count > 1) { if (is_using && vd->names.count > 1) {
error(f->names[0], "Cannot apply `using` to more than one of the same type"); error(vd->names[0], "Cannot apply `using` to more than one of the same type");
is_using = false; is_using = false;
} }
for_array(name_index, f->names) { if (!vd->is_mutable) {
AstNode *name = f->names[name_index]; error(vd->names[0], "Immutable values in a %.*s are not yet supported", LIT(context));
continue;
}
if (vd->values.count) {
error(vd->values[0], "Default values are not allowed within a %.*s", LIT(context));
}
for_array(name_index, vd->names) {
AstNode *name = vd->names[name_index];
if (!ast_node_expect(name, AstNode_Ident)) { if (!ast_node_expect(name, AstNode_Ident)) {
continue; continue;
} }
@@ -759,16 +774,16 @@ isize check_fields(Checker *c, AstNode *node, Array<AstNode *> decls,
if (is_using) { if (is_using) {
Type *t = base_type(type_deref(type)); Type *t = base_type(type_deref(type));
if (!is_type_struct(t) && !is_type_raw_union(t) && !is_type_bit_field(t) && if (!is_type_struct(t) && !is_type_raw_union(t) && !is_type_bit_field(t) &&
f->names.count >= 1 && vd->names.count >= 1 &&
f->names[0]->kind == AstNode_Ident) { vd->names[0]->kind == AstNode_Ident) {
Token name_token = f->names[0]->Ident.token; Token name_token = vd->names[0]->Ident.token;
if (is_type_indexable(t)) { if (is_type_indexable(t)) {
bool ok = true; bool ok = true;
for_array(emi, entity_map.entries) { for_array(emi, entity_map.entries) {
Entity *e = entity_map.entries[emi].value; Entity *e = entity_map.entries[emi].value;
if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) { if (e->kind == Entity_Variable && e->flags & EntityFlag_Using) {
if (is_type_indexable(e->type)) { if (is_type_indexable(e->type)) {
if (e->identifier != f->names[0]) { if (e->identifier != vd->names[0]) {
ok = false; ok = false;
using_index_expr = e; using_index_expr = e;
break; break;
@@ -852,7 +867,7 @@ void check_struct_type(Checker *c, Type *struct_type, AstNode *node) {
for_array(field_index, st->fields) { for_array(field_index, st->fields) {
AstNode *field = st->fields[field_index]; AstNode *field = st->fields[field_index];
switch (field->kind) { switch (field->kind) {
case_ast_node(f, Field, field); case_ast_node(f, ValueDecl, field);
field_count += f->names.count; field_count += f->names.count;
case_end; case_end;
} }
@@ -947,9 +962,10 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
isize field_count = 0; isize field_count = 0;
for_array(i, ut->fields) { for_array(i, ut->fields) {
AstNode *field = ut->fields[i]; AstNode *field = ut->fields[i];
if (field->kind == AstNode_Field) { switch (field->kind) {
ast_node(f, Field, field); case_ast_node(f, ValueDecl, field);
field_count += f->names.count; field_count += f->names.count;
case_end;
} }
} }
@@ -1005,8 +1021,12 @@ void check_union_type(Checker *c, Type *named_type, Type *union_type, AstNode *n
isize list_count = 0; isize list_count = 0;
for_array(j, list) { for_array(j, list) {
ast_node(f, Field, list[j]); if (list[j]->kind == AstNode_Field) {
list_count += f->names.count; list_count += list[j]->Field.names.count;
} else {
ast_node(f, ValueDecl, list[j]);
list_count += f->names.count;
}
} }
@@ -1067,10 +1087,10 @@ void check_raw_union_type(Checker *c, Type *union_type, AstNode *node) {
ast_node(ut, RawUnionType, node); ast_node(ut, RawUnionType, node);
isize field_count = 0; isize field_count = 0;
for_array(field_index, ut->fields) { for_array(i, ut->fields) {
AstNode *field = ut->fields[field_index]; AstNode *field = ut->fields[i];
switch (field->kind) { switch (field->kind) {
case_ast_node(f, Field, field); case_ast_node(f, ValueDecl, field);
field_count += f->names.count; field_count += f->names.count;
case_end; case_end;
} }
+73 -135
View File
@@ -1880,13 +1880,11 @@ void expect_semicolon(AstFile *f, AstNode *s) {
return; return;
} }
} else { } else {
// switch (s->kind) { if (s->kind == AstNode_ValueDecl) {
// case AstNode_GiveExpr: if (f->curr_token.kind == Token_CloseBrace) {
// if (f->curr_token.kind == Token_CloseBrace) { return;
// return; }
// } }
// break;
// }
} }
String node_string = ast_node_strings[s->kind]; String node_string = ast_node_strings[s->kind];
if (s->kind == AstNode_GenDecl) { if (s->kind == AstNode_GenDecl) {
@@ -3007,7 +3005,6 @@ AstNode *parse_value_decl(AstFile *f, Array<AstNode *> names, CommentGroup docs)
} }
} }
if (is_mutable) { if (is_mutable) {
if (type == nullptr && values.count == 0) { if (type == nullptr && values.count == 0) {
syntax_error(f->curr_token, "Missing variable type or initialization"); syntax_error(f->curr_token, "Missing variable type or initialization");
@@ -3029,7 +3026,12 @@ AstNode *parse_value_decl(AstFile *f, Array<AstNode *> names, CommentGroup docs)
if (!is_mutable && values.count > 0) { if (!is_mutable && values.count > 0) {
end = values[values.count-1]; end = values[values.count-1];
} }
expect_semicolon(f, end); if (f->curr_token.kind == Token_CloseBrace &&
f->curr_token.pos.line == f->prev_token.pos.line) {
} else {
expect_semicolon(f, end);
}
} }
return ast_value_decl(f, names, type, values, is_mutable, docs, f->line_comment); return ast_value_decl(f, names, type, values, is_mutable, docs, f->line_comment);
@@ -3377,98 +3379,36 @@ bool parse_expect_struct_separator(AstFile *f, AstNode *param) {
} }
AstNode *parse_struct_field_list(AstFile *f, isize *name_count_) { AstNode *parse_record_field_list(AstFile *f, isize *name_count_) {
CommentGroup docs = f->lead_comment; CommentGroup docs = f->lead_comment;
Token start_token = f->curr_token; Token start_token = f->curr_token;
Array<AstNode *> params = make_ast_node_array(f); Array<AstNode *> decls = make_ast_node_array(f);
Array<AstNodeAndFlags> list = {}; array_init(&list, heap_allocator());
defer (array_free(&list));
isize total_name_count = 0; isize total_name_count = 0;
while (f->curr_token.kind != Token_CloseBrace && while (f->curr_token.kind != Token_CloseBrace &&
f->curr_token.kind != Token_Colon &&
f->curr_token.kind != Token_EOF) { f->curr_token.kind != Token_EOF) {
u32 flags = parse_field_prefixes(f); AstNode *decl = parse_stmt(f);
AstNode *param = parse_var_type(f, false, false); if (decl->kind != AstNode_ValueDecl) {
AstNodeAndFlags naf = {param, flags}; error(decl, "Expected a field list, got %.*s", LIT(ast_node_strings[decl->kind]));
array_add(&list, naf); } else {
if (f->curr_token.kind != Token_Comma) { ast_node(vd, ValueDecl, decl);
break; if (vd->is_mutable) {
} if (vd->flags&VarDeclFlag_thread_local) {
next_token(f); vd->flags &= ~VarDeclFlag_thread_local;
} error(decl, "Field values cannot be #thread_local");
}
if (f->curr_token.kind == Token_Colon) { array_add(&decls, decl);
Array<AstNode *> names = convert_to_ident_list(f, list, true); // Copy for semantic reasons total_name_count += vd->names.count;
if (names.count == 0) { } else {
syntax_error(f->curr_token, "Empty field declaration"); error(decl, "Only variable declarations are allowed at the moment");
}
u32 set_flags = 0;
if (list.count > 0) {
set_flags = list[0].flags;
}
set_flags = check_field_prefixes(f, names.count, FieldFlag_using, set_flags);
total_name_count += names.count;
AstNode *type = nullptr;
expect_token_after(f, Token_Colon, "field list");
type = parse_var_type(f, false, false);
parse_expect_struct_separator(f, type);
AstNode *param = ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment);
array_add(&params, param);
while (f->curr_token.kind != Token_CloseBrace &&
f->curr_token.kind != Token_EOF) {
CommentGroup docs = f->lead_comment;
u32 set_flags = parse_field_prefixes(f);
Array<AstNode *> names = parse_ident_list(f);
if (names.count == 0) {
syntax_error(f->curr_token, "Empty field declaration");
break;
}
set_flags = check_field_prefixes(f, names.count, FieldFlag_using, set_flags);
total_name_count += names.count;
AstNode *type = nullptr;
expect_token_after(f, Token_Colon, "field list");
type = parse_var_type(f, false, false);
bool ok = parse_expect_struct_separator(f, param);
AstNode *param = ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment);
array_add(&params, param);
if (!ok) {
break;
} }
} }
if (name_count_) *name_count_ = total_name_count;
return ast_field_list(f, start_token, params);
}
for_array(i, list) {
Array<AstNode *> names = {};
AstNode *type = list[i].node;
Token token = blank_token;
array_init_count(&names, heap_allocator(), 1);
token.pos = ast_node_token(type).pos;
names[0] = ast_ident(f, token);
u32 flags = check_field_prefixes(f, list.count, FieldFlag_using, list[i].flags);
AstNode *param = ast_field(f, names, list[i].node, nullptr, flags, docs, f->line_comment);
array_add(&params, param);
} }
if (name_count_) *name_count_ = total_name_count; if (name_count_) *name_count_ = total_name_count;
return ast_field_list(f, start_token, params); return ast_field_list(f, start_token, decls);
} }
AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters) { AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, TokenKind follow, bool allow_default_parameters) {
@@ -3597,11 +3537,6 @@ AstNode *parse_field_list(AstFile *f, isize *name_count_, u32 allowed_flags, Tok
return ast_field_list(f, start_token, params); return ast_field_list(f, start_token, params);
} }
AstNode *parse_record_fields(AstFile *f, isize *field_count_, u32 flags, String context) {
return parse_field_list(f, field_count_, flags, Token_CloseBrace, false);
}
AstNode *parse_type_or_ident(AstFile *f) { AstNode *parse_type_or_ident(AstFile *f) {
switch (f->curr_token.kind) { switch (f->curr_token.kind) {
case Token_Dollar: { case Token_Dollar: {
@@ -3748,7 +3683,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
Token open = expect_token_after(f, Token_OpenBrace, "struct"); Token open = expect_token_after(f, Token_OpenBrace, "struct");
isize name_count = 0; isize name_count = 0;
AstNode *fields = parse_struct_field_list(f, &name_count); AstNode *fields = parse_record_field_list(f, &name_count);
Token close = expect_token(f, Token_CloseBrace); Token close = expect_token(f, Token_CloseBrace);
Array<AstNode *> decls = {}; Array<AstNode *> decls = {};
@@ -3767,50 +3702,57 @@ AstNode *parse_type_or_ident(AstFile *f) {
Array<AstNode *> variants = make_ast_node_array(f); Array<AstNode *> variants = make_ast_node_array(f);
isize total_decl_name_count = 0; isize total_decl_name_count = 0;
CommentGroup docs = f->lead_comment;
Token start_token = f->curr_token;
while (f->curr_token.kind != Token_CloseBrace && while (f->curr_token.kind != Token_CloseBrace &&
f->curr_token.kind != Token_EOF) { f->curr_token.kind != Token_EOF) {
CommentGroup docs = f->lead_comment; CommentGroup docs = f->lead_comment;
u32 decl_flags = parse_field_prefixes(f); u32 flags = parse_field_prefixes(f);
if (decl_flags != 0) { auto names = parse_ident_list(f);
Array<AstNode *> names = parse_ident_list(f); if (names.count == 0) {
if (names.count == 0) {
syntax_error(f->curr_token, "Empty field declaration");
}
u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags);
total_decl_name_count += names.count;
expect_token_after(f, Token_Colon, "field list");
AstNode *type = parse_var_type(f, false, false);
array_add(&decls, ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment));
} else {
Array<AstNode *> names = parse_ident_list(f);
if (names.count == 0) {
break;
}
if (names.count > 1 || f->curr_token.kind == Token_Colon) {
u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, decl_flags);
total_decl_name_count += names.count;
expect_token_after(f, Token_Colon, "field list");
AstNode *type = parse_var_type(f, false, false);
array_add(&decls, ast_field(f, names, type, nullptr, set_flags, docs, f->line_comment));
} else {
AstNode *name = names[0];
Token open = expect_token(f, Token_OpenBrace);
isize decl_count = 0;
AstNode *list = parse_struct_field_list(f, &decl_count);
// AstNode *list = parse_record_fields(f, &decl_count, FieldFlag_using, str_lit("union"));
Token close = expect_token(f, Token_CloseBrace);
array_add(&variants, ast_union_field(f, name, list));
}
}
if (!parse_expect_struct_separator(f, nullptr)) {
break; break;
} }
u32 set_flags = check_field_prefixes(f, names.count, FieldFlag_using, flags);
if (names.count == 1 && f->curr_token.kind == Token_OpenBrace) {
if (set_flags != 0) {
error(names[0], "Variants cannot have field prefixes");
set_flags = 0;
}
AstNode *name = names[0];
Token open = expect_token(f, Token_OpenBrace);
isize decl_count = 0;
AstNode *list = parse_record_field_list(f, &decl_count);
Token close = expect_token(f, Token_CloseBrace);
array_add(&variants, ast_union_field(f, name, list));
expect_semicolon(f, nullptr);
} else {
AstNode *decl = parse_value_decl(f, names, docs);
if (decl->kind != AstNode_ValueDecl) {
error(decl, "Expected a field list, got %.*s", LIT(ast_node_strings[decl->kind]));
} else {
ast_node(vd, ValueDecl, decl);
if (vd->is_mutable) {
if (set_flags&FieldFlag_using) {
vd->flags |= VarDeclFlag_using;
}
if (vd->flags&VarDeclFlag_thread_local) {
vd->flags &= ~VarDeclFlag_thread_local;
error(decl, "Field values cannot be #thread_local");
}
array_add(&decls, decl);
total_decl_name_count += vd->names.count;
} else {
error(decl, "Only variable declarations are allowed at the moment");
}
}
}
} }
Token close = expect_token(f, Token_CloseBrace); Token close = expect_token(f, Token_CloseBrace);
return ast_union_type(f, token, decls, total_decl_name_count, variants); return ast_union_type(f, token, decls, total_decl_name_count, variants);
} break; } break;
@@ -3819,7 +3761,7 @@ AstNode *parse_type_or_ident(AstFile *f) {
Token open = expect_token_after(f, Token_OpenBrace, "raw_union"); Token open = expect_token_after(f, Token_OpenBrace, "raw_union");
isize decl_count = 0; isize decl_count = 0;
AstNode *fields = parse_struct_field_list(f, &decl_count); AstNode *fields = parse_record_field_list(f, &decl_count);
Token close = expect_token(f, Token_CloseBrace); Token close = expect_token(f, Token_CloseBrace);
Array<AstNode *> decls = {}; Array<AstNode *> decls = {};
@@ -4391,11 +4333,7 @@ AstNode *parse_stmt(AstFile *f) {
syntax_error(token, "`using` may only be applied to variable declarations"); syntax_error(token, "`using` may only be applied to variable declarations");
return decl; return decl;
} }
if (f->curr_proc == nullptr) { decl->ValueDecl.flags |= VarDeclFlag_using;
syntax_error(token, "`using` is not allowed at the file scope");
} else {
decl->ValueDecl.flags |= VarDeclFlag_using;
}
return decl; return decl;
} }