aboutsummaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorGinger Bill <bill@gingerbill.org>2017-01-08 20:24:12 +0000
committerGinger Bill <bill@gingerbill.org>2017-01-08 20:24:12 +0000
commitff473e83425c74bae2cee4c9d68435c7b346533e (patch)
tree746fbe47711e1d00ef09214136e53f2a140b9241 /src
parent659e5359b2399927ffdd44d441d41a8a6e96228a (diff)
"Old style" enums
name and value information `count`, `min_value`, `max_value` constants
Diffstat (limited to 'src')
-rw-r--r--src/check_decl.c8
-rw-r--r--src/check_expr.c203
-rw-r--r--src/checker.c16
-rw-r--r--src/entity.c3
-rw-r--r--src/ir.c90
-rw-r--r--src/types.c37
6 files changed, 281 insertions, 76 deletions
diff --git a/src/check_decl.c b/src/check_decl.c
index 9f683cf29..1c5cc1b06 100644
--- a/src/check_decl.c
+++ b/src/check_decl.c
@@ -249,9 +249,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
}
e->flags |= EntityFlag_Visited;
- c->context.iota = e->Constant.value;
- e->Constant.value = (ExactValue){0};
-
if (type_expr) {
Type *t = check_type(c, type_expr);
if (!is_type_constant_type(t)) {
@@ -259,7 +256,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
error_node(type_expr, "Invalid constant type `%s`", str);
gb_string_free(str);
e->type = t_invalid;
- c->context.iota = (ExactValue){0};
return;
}
e->type = t;
@@ -270,9 +266,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
check_expr_or_type(c, &operand, init);
}
if (operand.mode == Addressing_Type) {
- c->context.iota = (ExactValue){0};
-
- e->Constant.value = (ExactValue){0};
e->kind = Entity_TypeName;
DeclInfo *d = c->context.decl;
@@ -282,7 +275,6 @@ void check_const_decl(Checker *c, Entity *e, AstNode *type_expr, AstNode *init,
}
check_init_constant(c, e, &operand);
- c->context.iota = (ExactValue){0};
if (operand.mode == Addressing_Invalid) {
error(e->token, "Illegal cyclic declaration");
diff --git a/src/check_expr.c b/src/check_expr.c
index 2c772d149..c52d463f2 100644
--- a/src/check_expr.c
+++ b/src/check_expr.c
@@ -263,11 +263,13 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
}
// ^T <- rawptr
+#if 0
// TODO(bill): Should C-style (not C++) pointer cast be allowed?
- // if (is_type_pointer(dst) && is_type_rawptr(src)) {
- // return true;
- // }
-
+ if (is_type_pointer(dst) && is_type_rawptr(src)) {
+ return true;
+ }
+#endif
+#if 1
// rawptr <- ^T
if (is_type_rawptr(dst) && is_type_pointer(src)) {
// TODO(bill): Handle this properly
@@ -276,8 +278,7 @@ bool check_is_assignable_to(Checker *c, Operand *operand, Type *type) {
}
return true;
}
-
-
+#endif
if (dst->kind == Type_Array && src->kind == Type_Array) {
if (are_types_identical(dst->Array.elem, src->Array.elem)) {
@@ -702,20 +703,21 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
map_entity_init_with_reserve(&entity_map, c->tmp_allocator, 2*(et->fields.count));
Entity **fields = gb_alloc_array(c->allocator, Entity *, et->fields.count);
- isize field_index = 0;
+ isize field_count = 0;
Type *constant_type = enum_type;
if (named_type != NULL) {
constant_type = named_type;
}
- AstNode *prev_expr = NULL;
-
- i64 iota = 0;
+ ExactValue iota = make_exact_value_integer(-1);
+ ExactValue min_value = make_exact_value_integer(0);
+ ExactValue max_value = make_exact_value_integer(0);
for_array(i, et->fields) {
AstNode *field = et->fields.e[i];
AstNode *ident = NULL;
+ AstNode *init = NULL;
if (field->kind == AstNode_FieldValue) {
ast_node(fv, FieldValue, field);
if (fv->field == NULL || fv->field->kind != AstNode_Ident) {
@@ -723,7 +725,7 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
continue;
}
ident = fv->field;
- prev_expr = fv->value;
+ init = fv->value;
} else if (field->kind == AstNode_Ident) {
ident = field;
} else {
@@ -732,48 +734,73 @@ void check_enum_type(Checker *c, Type *enum_type, Type *named_type, AstNode *nod
}
String name = ident->Ident.string;
- if (str_ne(name, str_lit("_"))) {
- ExactValue v = make_exact_value_integer(iota);
- Entity *e = make_entity_constant(c->allocator, c->context.scope, ident->Ident, constant_type, v);
- e->identifier = ident;
- e->flags |= EntityFlag_Visited;
-
-
- AstNode *init = prev_expr;
- if (init == NULL) {
- error_node(field, "Missing initial expression for enumeration, e.g. iota");
- continue;
+ if (init != NULL) {
+ Operand o = {0};
+ check_expr(c, &o, init);
+ if (o.mode != Addressing_Constant) {
+ error_node(init, "Enumeration value must be a constant");
+ o.mode = Addressing_Invalid;
+ }
+ if (o.mode != Addressing_Invalid) {
+ check_assignment(c, &o, constant_type, str_lit("enumeration"));
}
+ if (o.mode != Addressing_Invalid) {
+ iota = o.value;
+ } else {
+ iota = exact_binary_operator_value(Token_Add, iota, make_exact_value_integer(1));
+ }
+ } else {
+ iota = exact_binary_operator_value(Token_Add, iota, make_exact_value_integer(1));
+ }
+
- ExactValue context_iota = c->context.iota;
- c->context.iota = e->Constant.value;
- e->Constant.value = (ExactValue){0};
+ // NOTE(bill): Skip blank identifiers
+ if (str_eq(name, str_lit("_"))) {
+ continue;
+ } else if (str_eq(name, str_lit("count"))) {
+ error_node(field, "`count` is a reserved identifier for enumerations");
+ continue;
+ } else if (str_eq(name, str_lit("min_value"))) {
+ error_node(field, "`min_value` is a reserved identifier for enumerations");
+ continue;
+ } else if (str_eq(name, str_lit("max_value"))) {
+ error_node(field, "`max_value` is a reserved identifier for enumerations");
+ continue;
+ }
- Operand operand = {0};
- check_expr(c, &operand, init);
+ if (compare_exact_values(Token_Gt, min_value, iota)) {
+ min_value = iota;
+ }
+ if (compare_exact_values(Token_Lt, max_value, iota)) {
+ max_value = iota;
+ }
- check_init_constant(c, e, &operand);
- c->context.iota = context_iota;
+ Entity *e = make_entity_constant(c->allocator, c->context.scope, ident->Ident, constant_type, iota);
+ e->identifier = ident;
+ e->flags |= EntityFlag_Visited;
- if (operand.mode == Addressing_Constant) {
- HashKey key = hash_string(name);
- if (map_entity_get(&entity_map, key) != NULL) {
- error_node(ident, "`%.*s` is already declared in this enumeration", LIT(name));
- } else {
- map_entity_set(&entity_map, key, e);
- add_entity(c, c->context.scope, NULL, e);
- fields[field_index++] = e;
- add_entity_use(c, field, e);
- }
- }
+ HashKey key = hash_string(name);
+ if (map_entity_get(&entity_map, key) != NULL) {
+ error_node(ident, "`%.*s` is already declared in this enumeration", LIT(name));
+ } else {
+ map_entity_set(&entity_map, key, e);
+ add_entity(c, c->context.scope, NULL, e);
+ fields[field_count++] = e;
+ add_entity_use(c, field, e);
}
- iota++;
}
- GB_ASSERT(field_index <= et->fields.count);
+ GB_ASSERT(field_count <= et->fields.count);
enum_type->Record.fields = fields;
- enum_type->Record.field_count = field_index;
+ enum_type->Record.field_count = field_count;
+
+ enum_type->Record.enum_count = make_entity_constant(c->allocator, c->context.scope,
+ make_token_ident(str_lit("count")), t_int, make_exact_value_integer(field_count));
+ enum_type->Record.enum_min_value = make_entity_constant(c->allocator, c->context.scope,
+ make_token_ident(str_lit("min_value")), constant_type, min_value);
+ enum_type->Record.enum_max_value = make_entity_constant(c->allocator, c->context.scope,
+ make_token_ident(str_lit("max_value")), constant_type, max_value);
gb_temp_arena_memory_end(tmp);
}
@@ -926,15 +953,7 @@ void check_identifier(Checker *c, Operand *o, AstNode *n, Type *named_type) {
o->type = t_invalid;
return;
}
- if (e == e_iota) {
- if (c->context.iota.kind == ExactValue_Invalid) {
- error(e->token, "Use of `iota` outside a enumeration is not allowed");
- return;
- }
- o->value = c->context.iota;
- } else {
- o->value = e->Constant.value;
- }
+ o->value = e->Constant.value;
if (o->value.kind == ExactValue_Invalid) {
return;
}
@@ -4091,7 +4110,6 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
}
}
}
-
} break;
case Type_Slice:
@@ -4162,6 +4180,85 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
}
} break;
+ case Type_Basic: {
+ if (!is_type_any(t)) {
+ if (cl->elems.count != 0) {
+ error_node(node, "Illegal compound literal");
+ }
+ break;
+ }
+ if (cl->elems.count == 0) {
+ break; // NOTE(bill): No need to init
+ }
+ { // Checker values
+ Type *field_types[2] = {t_type_info_ptr, t_rawptr};
+ isize field_count = 2;
+ if (cl->elems.e[0]->kind == AstNode_FieldValue) {
+ bool fields_visited[2] = {0};
+
+ for_array(i, cl->elems) {
+ AstNode *elem = cl->elems.e[i];
+ if (elem->kind != AstNode_FieldValue) {
+ error_node(elem, "Mixture of `field = value` and value elements in a `any` literal is not allowed");
+ continue;
+ }
+ ast_node(fv, FieldValue, elem);
+ if (fv->field->kind != AstNode_Ident) {
+ gbString expr_str = expr_to_string(fv->field);
+ error_node(elem, "Invalid field name `%s` in `any` literal", expr_str);
+ gb_string_free(expr_str);
+ continue;
+ }
+ String name = fv->field->Ident.string;
+
+ Selection sel = lookup_field(c->allocator, type, name, o->mode == Addressing_Type);
+ if (sel.entity == NULL) {
+ error_node(elem, "Unknown field `%.*s` in `any` literal", LIT(name));
+ continue;
+ }
+
+ isize index = sel.index.e[0];
+
+ if (fields_visited[index]) {
+ error_node(elem, "Duplicate field `%.*s` in `any` literal", LIT(name));
+ continue;
+ }
+
+ fields_visited[index] = true;
+ check_expr(c, o, fv->value);
+
+ // NOTE(bill): `any` literals can never be constant
+ is_constant = false;
+
+ check_assignment(c, o, field_types[index], str_lit("`any` literal"));
+ }
+ } else {
+ for_array(index, cl->elems) {
+ AstNode *elem = cl->elems.e[index];
+ if (elem->kind == AstNode_FieldValue) {
+ error_node(elem, "Mixture of `field = value` and value elements in a `any` literal is not allowed");
+ continue;
+ }
+
+
+ check_expr(c, o, elem);
+ if (index >= field_count) {
+ error_node(o->expr, "Too many values in `any` literal, expected %td", field_count);
+ break;
+ }
+
+ // NOTE(bill): `any` literals can never be constant
+ is_constant = false;
+
+ check_assignment(c, o, field_types[index], str_lit("`any` literal"));
+ }
+ if (cl->elems.count < field_count) {
+ error(cl->close, "Too few values in `any` literal, expected %td, got %td", field_count, cl->elems.count);
+ }
+ }
+ }
+ } break;
+
default: {
gbString str = type_to_string(type);
error_node(node, "Invalid compound literal type `%s`", str);
diff --git a/src/checker.c b/src/checker.c
index 6685d56ab..15dfe76f4 100644
--- a/src/checker.c
+++ b/src/checker.c
@@ -210,7 +210,6 @@ typedef struct CheckerContext {
Scope * scope;
DeclInfo * decl;
u32 stmt_state_flags;
- ExactValue iota; // Value of `iota` in a constant declaration; Invalid otherwise
} CheckerContext;
#define MAP_TYPE TypeAndValue
@@ -549,7 +548,6 @@ void init_universal_scope(BuildContext *bc) {
// Constants
add_global_constant(a, str_lit("true"), t_untyped_bool, make_exact_value_bool(true));
add_global_constant(a, str_lit("false"), t_untyped_bool, make_exact_value_bool(false));
- add_global_constant(a, str_lit("iota"), t_untyped_integer, make_exact_value_integer(0));
add_global_entity(make_entity_nil(a, str_lit("nil"), t_untyped_nil));
@@ -570,9 +568,10 @@ void init_universal_scope(BuildContext *bc) {
}
- t_u8_ptr = make_type_pointer(a, t_u8);
+ t_u8_ptr = make_type_pointer(a, t_u8);
t_int_ptr = make_type_pointer(a, t_int);
- e_iota = scope_lookup_entity(universal_scope, str_lit("iota"));
+ t_i64_ptr = make_type_pointer(a, t_i64);
+ t_f64_ptr = make_type_pointer(a, t_f64);
}
@@ -1020,6 +1019,11 @@ void init_preload(Checker *c) {
compiler_error("Could not find type declaration for `Type_Info_Member`\n"
"Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
}
+ Entity *type_info_enum_value_entity = current_scope_lookup_entity(c->global_scope, str_lit("Type_Info_Enum_Value"));
+ if (type_info_entity == NULL) {
+ compiler_error("Could not find type declaration for `Type_Info_Enum_Value`\n"
+ "Is `runtime.odin` missing from the `core` directory relative to odin.exe?");
+ }
t_type_info = type_info_entity->type;
t_type_info_ptr = make_type_pointer(c->allocator, t_type_info);
GB_ASSERT(is_type_union(type_info_entity->type));
@@ -1028,6 +1032,10 @@ void init_preload(Checker *c) {
t_type_info_member = type_info_member_entity->type;
t_type_info_member_ptr = make_type_pointer(c->allocator, t_type_info_member);
+ t_type_info_enum_value = type_info_enum_value_entity->type;
+ t_type_info_enum_value_ptr = make_type_pointer(c->allocator, t_type_info_enum_value);
+
+
if (record->field_count != 18) {
compiler_error("Invalid `Type_Info` layout");
}
diff --git a/src/entity.c b/src/entity.c
index 17fb70e06..a35c68d08 100644
--- a/src/entity.c
+++ b/src/entity.c
@@ -85,9 +85,6 @@ struct Entity {
};
-Entity *e_iota = NULL;
-
-
Entity *alloc_entity(gbAllocator a, EntityKind kind, Scope *scope, Token token, Type *type) {
Entity *entity = gb_alloc_item(a, Entity);
entity->kind = kind;
diff --git a/src/ir.c b/src/ir.c
index 789c8eddd..69d8d989c 100644
--- a/src/ir.c
+++ b/src/ir.c
@@ -1051,6 +1051,12 @@ irValue *ir_make_const_i32(gbAllocator a, i64 i) {
irValue *ir_make_const_i64(gbAllocator a, i64 i) {
return ir_make_value_constant(a, t_i64, make_exact_value_integer(i));
}
+irValue *ir_make_const_f32(gbAllocator a, f32 f) {
+ return ir_make_value_constant(a, t_f32, make_exact_value_float(f));
+}
+irValue *ir_make_const_f64(gbAllocator a, f64 f) {
+ return ir_make_value_constant(a, t_f64, make_exact_value_float(f));
+}
irValue *ir_make_const_bool(gbAllocator a, bool b) {
return ir_make_value_constant(a, t_bool, make_exact_value_bool(b != 0));
}
@@ -3743,6 +3749,48 @@ irAddr ir_build_addr(irProcedure *proc, AstNode *expr) {
ir_emit_store(proc, gep2, ir_make_const_int(proc->module->allocator, slice->ConstantSlice.count));
}
} break;
+
+ case Type_Basic: {
+ GB_ASSERT(is_type_any(bt));
+ if (cl->elems.count > 0) {
+ ir_emit_store(proc, v, ir_add_module_constant(proc->module, type, make_exact_value_compound(expr)));
+ String field_names[2] = {
+ str_lit("type_info"),
+ str_lit("data"),
+ };
+ Type *field_types[2] = {
+ t_type_info_ptr,
+ t_rawptr,
+ };
+
+ for_array(field_index, cl->elems) {
+ AstNode *elem = cl->elems.e[field_index];
+
+ irValue *field_expr = NULL;
+ isize index = field_index;
+
+ if (elem->kind == AstNode_FieldValue) {
+ ast_node(fv, FieldValue, elem);
+ Selection sel = lookup_field(proc->module->allocator, bt, fv->field->Ident.string, false);
+ index = sel.index.e[0];
+ elem = fv->value;
+ } else {
+ TypeAndValue *tav = type_and_value_of_expression(proc->module->info, elem);
+ Selection sel = lookup_field(proc->module->allocator, bt, field_names[field_index], false);
+ index = sel.index.e[0];
+ }
+
+ field_expr = ir_build_expr(proc, elem);
+
+ GB_ASSERT(ir_type(field_expr)->kind != Type_Tuple);
+
+ Type *ft = field_types[index];
+ irValue *fv = ir_emit_conv(proc, field_expr, ft);
+ irValue *gep = ir_emit_struct_ep(proc, v, index);
+ ir_emit_store(proc, gep, fv);
+ }
+ }
+ }
}
return ir_make_addr(v, expr);
@@ -5682,6 +5730,7 @@ void ir_gen_tree(irGen *s) {
Entity **fields = t->Record.fields;
isize count = t->Record.field_count;
irValue *name_array = NULL;
+ irValue *value_array = NULL;
{
Token token = {Token_Ident};
@@ -5698,8 +5747,40 @@ void ir_gen_tree(irGen *s) {
map_ir_value_set(&m->members, hash_string(token.string), name_array);
}
+ {
+ Token token = {Token_Ident};
+ i32 id = cast(i32)entry_index;
+ char name_base[] = "__$enum_values";
+ isize name_len = gb_size_of(name_base) + 10;
+ token.string.text = gb_alloc_array(a, u8, name_len);
+ token.string.len = gb_snprintf(cast(char *)token.string.text, name_len,
+ "%s-%d", name_base, id)-1;
+ Entity *e = make_entity_variable(a, NULL, token, make_type_array(a, t_type_info_enum_value, count));
+ value_array = ir_make_value_global(a, e, NULL);
+ value_array->Global.is_private = true;
+ ir_module_add_value(m, e, value_array);
+ map_ir_value_set(&m->members, hash_string(token.string), value_array);
+ }
+
+ bool is_value_int = is_type_integer(t->Record.enum_base_type);
+
for (isize i = 0; i < count; i++) {
- irValue *name_ep = ir_emit_array_epi(proc, name_array, i);
+ irValue *name_ep = ir_emit_array_epi(proc, name_array, i);
+ irValue *value_ep = ir_emit_array_epi(proc, value_array, i);
+
+ ExactValue value = fields[i]->Constant.value;
+
+ if (is_value_int) {
+ i64 i = value.value_integer;
+ value_ep = ir_emit_conv(proc, value_ep, t_i64_ptr);
+ ir_emit_store(proc, value_ep, ir_make_const_i64(a, i));
+ } else {
+ GB_ASSERT(is_type_float(t->Record.enum_base_type));
+ f64 f = value.value_float;
+ value_ep = ir_emit_conv(proc, value_ep, t_f64_ptr);
+ ir_emit_store(proc, value_ep, ir_make_const_f64(a, f));
+ }
+
ir_emit_store(proc, name_ep, ir_make_const_string(a, fields[i]->token.string));
}
@@ -5711,6 +5792,13 @@ void ir_gen_tree(irGen *s) {
ir_emit_store(proc, ir_emit_struct_ep(proc, names, 0), name_array_elem);
ir_emit_store(proc, ir_emit_struct_ep(proc, names, 1), v_count);
ir_emit_store(proc, ir_emit_struct_ep(proc, names, 2), v_count);
+
+ irValue *values = ir_emit_struct_ep(proc, tag, 2);
+ irValue *value_array_elem = ir_array_elem(proc, value_array);
+
+ ir_emit_store(proc, ir_emit_struct_ep(proc, values, 0), value_array_elem);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, values, 1), v_count);
+ ir_emit_store(proc, ir_emit_struct_ep(proc, values, 2), v_count);
}
}
break;
diff --git a/src/types.c b/src/types.c
index 779924cd4..9e6f6bd23 100644
--- a/src/types.c
+++ b/src/types.c
@@ -84,7 +84,10 @@ typedef struct TypeRecord {
bool struct_is_ordered;
Entity **fields_in_src_order; // Entity_Variable
- Type * enum_base_type;
+ Type * enum_base_type;
+ Entity *enum_count;
+ Entity *enum_min_value;
+ Entity *enum_max_value;
} TypeRecord;
#define TYPE_KINDS \
@@ -253,11 +256,15 @@ gb_global Type *t_rune = &basic_type_aliases[1];
gb_global Type *t_u8_ptr = NULL;
gb_global Type *t_int_ptr = NULL;
+gb_global Type *t_i64_ptr = NULL;
+gb_global Type *t_f64_ptr = NULL;
-gb_global Type *t_type_info = NULL;
-gb_global Type *t_type_info_ptr = NULL;
-gb_global Type *t_type_info_member = NULL;
-gb_global Type *t_type_info_member_ptr = NULL;
+gb_global Type *t_type_info = NULL;
+gb_global Type *t_type_info_member = NULL;
+gb_global Type *t_type_info_enum_value = NULL;
+gb_global Type *t_type_info_ptr = NULL;
+gb_global Type *t_type_info_member_ptr = NULL;
+gb_global Type *t_type_info_enum_value_ptr = NULL;
gb_global Type *t_type_info_named = NULL;
gb_global Type *t_type_info_integer = NULL;
@@ -1043,11 +1050,27 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
if (str_eq(field_name, str)) {
sel.entity = f;
- selection_add_index(&sel, i);
+ // selection_add_index(&sel, i);
return sel;
}
}
} else if (is_type_enum(type)) {
+ // NOTE(bill): These may not have been added yet, so check in case
+ if (type->Record.enum_count != NULL) {
+ if (str_eq(field_name, str_lit("count"))) {
+ sel.entity = type->Record.enum_count;
+ return sel;
+ }
+ if (str_eq(field_name, str_lit("min_value"))) {
+ sel.entity = type->Record.enum_min_value;
+ return sel;
+ }
+ if (str_eq(field_name, str_lit("max_value"))) {
+ sel.entity = type->Record.enum_max_value;
+ return sel;
+ }
+ }
+
for (isize i = 0; i < type->Record.field_count; i++) {
Entity *f = type->Record.fields[i];
GB_ASSERT(f->kind == Entity_Constant);
@@ -1055,7 +1078,7 @@ Selection lookup_field_with_selection(gbAllocator a, Type *type_, String field_n
if (str_eq(field_name, str)) {
sel.entity = f;
- selection_add_index(&sel, i);
+ // selection_add_index(&sel, i);
return sel;
}
}