using Foo :: enum {A, B, C}; len(Foo)

This commit is contained in:
gingerBill
2018-07-29 10:50:15 +01:00
parent 49f2124df0
commit 6512a3e5f2
11 changed files with 60 additions and 73 deletions
-1
View File
@@ -290,7 +290,6 @@ write_type :: proc(buf: ^String_Buffer, ti: ^runtime.Type_Info) {
case runtime.Type_Info_Enum:
write_string(buf, "enum ");
write_type(buf, info.base);
if info.is_export do write_string(buf, " #export");
write_string(buf, " {");
for name, i in info.names {
if i > 0 do write_string(buf, ", ");
+1 -1
View File
@@ -88,7 +88,7 @@ Type_Info_Enum :: struct {
base: ^Type_Info,
names: []string,
values: []Type_Info_Enum_Value,
is_export: bool,
is_using: bool, // TODO(bill): Should this be in the `Type_Info`?
};
Type_Info_Map :: struct {
key: ^Type_Info,
+6 -5
View File
@@ -608,15 +608,16 @@ named_proc_return_parameters :: proc() {
}
enum_export :: proc() {
fmt.println("# enum #export");
using_enum :: proc() {
fmt.println("# using enum");
Foo :: enum #export {A, B, C};
using Foo :: enum {A, B, C};
f0 := A;
f1 := B;
f2 := C;
fmt.println(f0, f1, f2);
fmt.println(len(Foo));
}
explicit_procedure_overloading :: proc() {
@@ -656,7 +657,7 @@ explicit_procedure_overloading :: proc() {
complete_switch :: proc() {
fmt.println("# complete_switch");
{ // enum
Foo :: enum #export {
using Foo :: enum {
A,
B,
C,
@@ -723,7 +724,7 @@ main :: proc() {
threading_example();
array_programming();
named_proc_return_parameters();
enum_export();
using_enum();
explicit_procedure_overloading();
complete_switch();
cstring_example();
-1
View File
@@ -510,7 +510,6 @@ void big_int_add(BigInt *dst, BigInt const *x, BigInt const *y) {
u64 first_word = dst->d.word;
big_int_alloc(dst, 0, bigger->len);
GB_ASSERT(dst->len > 1);
dst->d.words[0] = first_word;
i32 i = 0;
+15 -1
View File
@@ -2788,6 +2788,7 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
case BuiltinProc_offset_of:
case BuiltinProc_type_info_of:
case BuiltinProc_typeid_of:
case BuiltinProc_len:
// NOTE(bill): The first arg may be a Type, this will be checked case by case
break;
default:
@@ -2860,9 +2861,17 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
}
case BuiltinProc_len:
case BuiltinProc_cap: {
check_expr_or_type(c, operand, ce->args[0]);
if (operand->mode == Addressing_Invalid) {
return false;
}
/* fallthrough */
case BuiltinProc_cap:
{
// len :: proc(Type) -> int
// cap :: proc(Type) -> int
Type *op_type = type_deref(operand->type);
Type *type = t_int;
AddressingMode mode = Addressing_Invalid;
@@ -2890,6 +2899,11 @@ bool check_builtin_procedure(CheckerContext *c, Operand *operand, Ast *call, i32
mode = Addressing_Value;
} else if (is_type_map(op_type)) {
mode = Addressing_Value;
} else if (operand->mode == Addressing_Type && is_type_enum(op_type) && id == BuiltinProc_len) {
Type *bt = base_type(op_type);
mode = Addressing_Constant;
value = exact_value_i64(bt->Enum.fields.count);
type = t_untyped_integer;
}
if (mode == Addressing_Invalid) {
+4 -19
View File
@@ -571,22 +571,10 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast
// NOTE(bill): Skip blank identifiers
if (is_blank_ident(name)) {
continue;
} else if (name == "count") {
error(field, "'count' is a reserved identifier for enumerations");
continue;
} else if (name == "min_value") {
error(field, "'min_value' is a reserved identifier for enumerations");
continue;
} else if (name == "max_value") {
error(field, "'max_value' is a reserved identifier for enumerations");
continue;
} else if (name == "names") {
error(field, "'names' is a reserved identifier for enumerations");
continue;
}/* else if (name == "base_type") {
error(field, "'base_type' is a reserved identifier for enumerations");
continue;
} */
}
if (compare_exact_values(Token_Gt, min_value, iota)) {
min_value = iota;
@@ -613,8 +601,9 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast
enum_type->Enum.fields = fields;
enum_type->Enum.is_export = et->is_export;
if (et->is_export) {
enum_type->Enum.is_using = et->is_using;
// TODO(bill): Should this be done elsewhere? e.g. delayed
if (et->is_using) {
Scope *parent = ctx->scope->parent;
if (parent->flags&ScopeFlag_File) {
// NOTE(bill): Use package scope
@@ -634,10 +623,6 @@ void check_enum_type(CheckerContext *ctx, Type *enum_type, Type *named_type, Ast
}
Scope *s = ctx->scope;
enum_type->Enum.count = alloc_entity_constant(s, make_token_ident(str_lit("count")), t_int, exact_value_i64(fields.count));
enum_type->Enum.min_value = alloc_entity_constant(s, make_token_ident(str_lit("min_value")), constant_type, min_value);
enum_type->Enum.max_value = alloc_entity_constant(s, make_token_ident(str_lit("max_value")), constant_type, max_value);
enum_type->Enum.names = make_names_field_for_struct(ctx, ctx->scope);
}
+8
View File
@@ -2121,6 +2121,14 @@ void check_collect_value_decl(CheckerContext *c, Ast *decl) {
}
e->identifier = name;
if (vd->is_using) {
if (e->kind == Entity_TypeName && init->kind == Ast_EnumType) {
init->EnumType.is_using = true;
} else {
error(name, "'using' is not allowed on this constant value declaration");
}
}
if (e->kind != Entity_Procedure) {
if (fl != nullptr || c->foreign_context.in_export) {
AstKind kind = init->kind;
+2 -2
View File
@@ -8163,8 +8163,8 @@ void ir_setup_type_info_data(irProcedure *proc) { // NOTE(bill): Setup type_info
irValue *base = ir_type_info(proc, t->Enum.base_type);
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 0), base);
// is_export
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), ir_const_bool(t->Enum.is_export));
// is_using
ir_emit_store(proc, ir_emit_struct_ep(proc, tag, 3), ir_const_bool(t->Enum.is_using));
if (t->Enum.fields.count > 0) {
auto fields = t->Enum.fields;
+21 -22
View File
@@ -920,11 +920,10 @@ Ast *ast_union_type(AstFile *f, Token token, Array<Ast *> variants, Ast *align)
}
Ast *ast_enum_type(AstFile *f, Token token, Ast *base_type, bool is_export, Array<Ast *> fields) {
Ast *ast_enum_type(AstFile *f, Token token, Ast *base_type, Array<Ast *> fields) {
Ast *result = alloc_ast_node(f, Ast_EnumType);
result->EnumType.token = token;
result->EnumType.base_type = base_type;
result->EnumType.is_export = is_export;
result->EnumType.fields = fields;
return result;
}
@@ -1903,34 +1902,34 @@ Ast *parse_operand(AstFile *f, bool lhs) {
} break;
case Token_enum: {
bool is_export = false;
// bool is_export = false;
Token token = expect_token(f, Token_enum);
Ast *base_type = nullptr;
if (f->curr_token.kind != Token_OpenBrace) {
if (f->curr_token.kind != Token_Hash) {
base_type = parse_type(f);
}
while (allow_token(f, Token_Hash)) {
Token tag = f->curr_token;
if (!allow_token(f, Token_Ident) && !allow_token(f, Token_export)) {
expect_token_after(f, Token_Ident, "#");
}
if (tag.string == "export") {
if (is_export) {
syntax_error(tag, "Duplicate enum tag '#%.*s'", LIT(tag.string));
}
is_export = true;
} else {
syntax_error(tag, "Invalid enum tag '#%.*s'", LIT(tag.string));
}
}
// while (allow_token(f, Token_Hash)) {
// Token tag = f->curr_token;
// if (!allow_token(f, Token_Ident) && !allow_token(f, Token_export)) {
// expect_token_after(f, Token_Ident, "#");
// }
// if (tag.string == "export") {
// if (is_export) {
// syntax_error(tag, "Duplicate enum tag '#%.*s'", LIT(tag.string));
// }
// is_export = true;
// } else {
// syntax_error(tag, "Invalid enum tag '#%.*s'", LIT(tag.string));
// }
// }
}
Token open = expect_token(f, Token_OpenBrace);
Array<Ast *> values = parse_element_list(f);
Token close = expect_token(f, Token_CloseBrace);
return ast_enum_type(f, token, base_type, is_export, values);
return ast_enum_type(f, token, base_type, values);
} break;
case Token_bit_field: {
@@ -3591,10 +3590,10 @@ Ast *parse_stmt(AstFile *f) {
decl = parse_value_decl(f, list, docs);
if (decl != nullptr && decl->kind == Ast_ValueDecl) {
if (!decl->ValueDecl.is_mutable) {
syntax_error(token, "'using' may only be applied to variable declarations");
return decl;
}
// if (!decl->ValueDecl.is_mutable) {
// syntax_error(token, "'using' may only be applied to variable declarations");
// return decl;
// }
decl->ValueDecl.is_using = true;
return decl;
}
+1 -1
View File
@@ -478,7 +478,7 @@ AST_KIND(_TypeBegin, "", bool) \
Token token; \
Ast * base_type; \
Array<Ast *> fields; /* FieldValue */ \
bool is_export; \
bool is_using; \
}) \
AST_KIND(BitFieldType, "bit field type", struct { \
Token token; \
+2 -20
View File
@@ -131,14 +131,11 @@ struct TypeStruct {
TYPE_KIND(Struct, TypeStruct) \
TYPE_KIND(Enum, struct { \
Array<Entity *> fields; \
Ast *node; \
Ast *node; \
Scope * scope; \
Entity * names; \
Type * base_type; \
bool is_export; \
Entity * count; \
Entity * min_value; \
Entity * max_value; \
bool is_using; \
}) \
TYPE_KIND(Union, struct { \
Array<Type *> variants; \
@@ -1657,21 +1654,6 @@ Selection lookup_field_with_selection(Type *type_, String field_name, bool is_ty
if (is_type_enum(type)) {
// NOTE(bill): These may not have been added yet, so check in case
if (type->Enum.count != nullptr) {
if (field_name == "count") {
sel.entity = type->Enum.count;
return sel;
}
if (field_name == "min_value") {
sel.entity = type->Enum.min_value;
return sel;
}
if (field_name == "max_value") {
sel.entity = type->Enum.max_value;
return sel;
}
}
for_array(i, type->Enum.fields) {
Entity *f = type->Enum.fields[i];
GB_ASSERT(f->kind == Entity_Constant);