diff options
| author | Ginger Bill <bill@gingerbill.org> | 2017-01-08 20:24:12 +0000 |
|---|---|---|
| committer | Ginger Bill <bill@gingerbill.org> | 2017-01-08 20:24:12 +0000 |
| commit | ff473e83425c74bae2cee4c9d68435c7b346533e (patch) | |
| tree | 746fbe47711e1d00ef09214136e53f2a140b9241 /src/check_expr.c | |
| parent | 659e5359b2399927ffdd44d441d41a8a6e96228a (diff) | |
"Old style" enums
name and value information
`count`, `min_value`, `max_value` constants
Diffstat (limited to 'src/check_expr.c')
| -rw-r--r-- | src/check_expr.c | 203 |
1 files changed, 150 insertions, 53 deletions
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); |