mirror of
https://github.com/Ed94/Odin.git
synced 2026-07-10 05:11:37 -07:00
using Foo :: enum {A, B, C}; len(Foo)
This commit is contained in:
@@ -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, ", ");
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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();
|
||||
|
||||
@@ -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
@@ -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
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user