From: Brendan Hansen Date: Mon, 15 Nov 2021 19:27:20 +0000 (-0600) Subject: enum values are no longer bad X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=773b171ec6244f5913884aac8506be4eb986e598;p=onyx.git enum values are no longer bad --- diff --git a/include/astnodes.h b/include/astnodes.h index 64a620dd..d3bded15 100644 --- a/include/astnodes.h +++ b/include/astnodes.h @@ -893,7 +893,7 @@ struct AstEnumType { b32 is_flags : 1; }; -struct AstEnumValue { AstTyped_base; AstNumLit* value; }; +struct AstEnumValue { AstTyped_base; AstTyped* value; }; struct AstTypeAlias { AstType_base; AstType* to; }; struct AstTypeRawAlias { AstType_base; Type* to; }; struct AstCompoundType { @@ -1263,6 +1263,7 @@ typedef enum EntityType { Entity_Type_String_Literal, Entity_Type_File_Contents, Entity_Type_Enum, + Entity_Type_Enum_Value, Entity_Type_Type_Alias, Entity_Type_Memory_Reservation_Type, Entity_Type_Use, @@ -1319,6 +1320,7 @@ typedef struct Entity { AstFileContents *file_contents; AstType *type_alias; AstEnumType *enum_type; + AstEnumValue *enum_value; AstMemRes *mem_res; AstPolyProc *poly_proc; AstPolyQuery *poly_query; diff --git a/src/astnodes.c b/src/astnodes.c index a7bd73e1..b7a2ab4e 100644 --- a/src/astnodes.c +++ b/src/astnodes.c @@ -391,13 +391,16 @@ void promote_numlit_to_larger(AstNumLit* num) { } // NOTE: Returns 1 if the conversion was successful. -b32 convert_numlit_to_type(AstNumLit* num, Type* type) { +b32 convert_numlit_to_type(AstNumLit* num, Type* to_type) { if (num->type == NULL) num->type = type_build_from_ast(context.ast_alloc, num->type_node); assert(num->type); - if (types_are_compatible(num->type, type)) return 1; - if (!type_is_numeric(type)) return 0; + if (types_are_compatible(num->type, to_type)) return 1; + if (!type_is_numeric(to_type)) return 0; + + Type *type = to_type; + if (type->kind == Type_Kind_Enum) type = type->Enum.backing; if (num->type->Basic.kind == Basic_Kind_Int_Unsized) { @@ -412,20 +415,20 @@ b32 convert_numlit_to_type(AstNumLit* num, Type* type) { if (type->Basic.flags & Basic_Flag_Unsigned) { u64 value = (u64) num->value.l; if (type->Basic.size == 8) { - num->type = type; + num->type = to_type; return 1; } switch (type->Basic.size) { case 1: if (value <= 255) { - num->type = type; + num->type = to_type; return 1; } case 2: if (value <= 65535) { - num->type = type; + num->type = to_type; return 1; } case 4: if (value <= 4294967295) { - num->type = type; + num->type = to_type; return 1; } } @@ -439,20 +442,20 @@ b32 convert_numlit_to_type(AstNumLit* num, Type* type) { switch (type->Basic.size) { case 1: if (-128ll <= value && value <= 127ll) { num->value.i = (i32) value; - num->type = type; + num->type = to_type; return 1; } break; case 2: if (-32768ll <= value && value <= 32767ll) { num->value.i = (i32) value; - num->type = type; + num->type = to_type; return 1; } break; case 4: if (-2147483648ll <= value && value <= 2147483647ll) { num->value.i = (i32) value; - num->type = type; + num->type = to_type; return 1; } break; - case 8: { num->type = type; + case 8: { num->type = to_type; return 1; } break; } @@ -471,7 +474,7 @@ b32 convert_numlit_to_type(AstNumLit* num, Type* type) { return 0; } - num->type = type; + num->type = to_type; num->value.f = (f32) num->value.l; return 1; } @@ -482,7 +485,7 @@ b32 convert_numlit_to_type(AstNumLit* num, Type* type) { return 0; } - num->type = type; + num->type = to_type; num->value.d = (f64) num->value.l; return 1; } @@ -496,7 +499,7 @@ b32 convert_numlit_to_type(AstNumLit* num, Type* type) { num->value.f = (f32) num->value.d; } - num->type = type; + num->type = to_type; return 1; } else if (num->type->Basic.kind == Basic_Kind_F32) { @@ -505,7 +508,7 @@ b32 convert_numlit_to_type(AstNumLit* num, Type* type) { if (type->Basic.kind == Basic_Kind_F64) { num->value.d = (f64) num->value.f; - num->type = type; + num->type = to_type; return 1; } } diff --git a/src/checker.c b/src/checker.c index e03fe86e..0a68c9a6 100644 --- a/src/checker.c +++ b/src/checker.c @@ -2684,6 +2684,10 @@ void check_entity(Entity* ent) { resolve_expression_type(ent->expr); break; + case Entity_Type_Enum_Value: + cs = check_expression(&ent->enum_value->value); + break; + case Entity_Type_Type_Alias: if (ent->type_alias->kind == Ast_Kind_Struct_Type) cs = check_struct((AstStructType *) ent->type_alias); diff --git a/src/entities.c b/src/entities.c index a3fe241d..f489b356 100644 --- a/src/entities.c +++ b/src/entities.c @@ -264,6 +264,14 @@ void add_entities_for_node(bh_arr(Entity *) *target_arr, AstNode* node, Scope* s break; } + case Ast_Kind_Enum_Value: { + ent.type = Entity_Type_Enum_Value; + ent.state = Entity_State_Check_Types; + ent.enum_value = (AstEnumValue *) node; + ENTITY_INSERT(ent); + break; + } + case Ast_Kind_Use: { if (((AstUse *) node)->expr->kind == Ast_Kind_Package) { ent.state = Entity_State_Resolve_Symbols; diff --git a/src/parser.c b/src/parser.c index d336d3ce..f7222b68 100644 --- a/src/parser.c +++ b/src/parser.c @@ -2601,9 +2601,7 @@ static AstEnumType* parse_enum_declaration(OnyxParser* parser) { if (consume_token_if_next(parser, ':')) { expect_token(parser, ':'); - - // TODO: Make this work for any expression. - evalue->value = parse_int_literal(parser); + evalue->value = parse_expression(parser, 0); } expect_token(parser, ';'); diff --git a/src/symres.c b/src/symres.c index 12ad701c..b8908ae4 100644 --- a/src/symres.c +++ b/src/symres.c @@ -300,6 +300,11 @@ static SymresStatus symres_field_access(AstFieldAccess** fa) { AstTyped* expr = (AstTyped *) strip_aliases((AstNode *) (*fa)->expr); + b32 force_a_lookup = 0; + if (expr->kind == Ast_Kind_Enum_Type) { + force_a_lookup = 1; + } + AstNode* resolution = try_symbol_resolve_from_node((AstNode *) expr, (*fa)->token); if (resolution) *((AstNode **) fa) = resolution; else if (expr->kind == Ast_Kind_Package) { @@ -313,6 +318,16 @@ static SymresStatus symres_field_access(AstFieldAccess** fa) { return Symres_Yield_Macro; } } + else if (force_a_lookup) { + if (context.cycle_detected) { + onyx_report_error((*fa)->token->pos, "'%b' does not exist here. This is a bad error message.", + (*fa)->token->text, + (*fa)->token->length); + return Symres_Error; + } + + return Symres_Yield_Macro; + } return Symres_Success; } @@ -1051,38 +1066,63 @@ static SymresStatus symres_enum(AstEnumType* enum_node) { if (enum_node->backing->kind == Ast_Kind_Symbol) SYMRES(symbol, (AstNode **) &enum_node->backing); if (enum_node->backing == NULL) return Symres_Error; - enum_node->backing_type = type_build_from_ast(context.ast_alloc, enum_node->backing); - enum_node->scope = scope_create(context.ast_alloc, NULL, enum_node->token->pos); + if (enum_node->scope == NULL) { + enum_node->backing_type = type_build_from_ast(context.ast_alloc, enum_node->backing); + enum_node->scope = scope_create(context.ast_alloc, curr_scope, enum_node->token->pos); - type_build_from_ast(context.ast_alloc, (AstType *) enum_node); + type_build_from_ast(context.ast_alloc, (AstType *) enum_node); + } + + scope_enter(enum_node->scope); u64 next_assign_value = enum_node->is_flags ? 1 : 0; bh_arr_each(AstEnumValue *, value, enum_node->values) { - symbol_introduce(enum_node->scope, (*value)->token, (AstNode *) *value); + if ((*value)->flags & Ast_Flag_Has_Been_Checked) continue; + (*value)->type = enum_node->etcache; + (*value)->flags |= Ast_Flag_Comptime; if ((*value)->value != NULL) { - // HACK - resolve_expression_type((AstTyped *) (*value)->value); - if (type_is_small_integer((*value)->value->type)) { - next_assign_value = (*value)->value->value.i; - } else if (type_is_integer((*value)->value->type)) { - next_assign_value = (*value)->value->value.l; + SYMRES(expression, &(*value)->value); + + if ((*value)->value->kind == Ast_Kind_NumLit) { + AstNumLit *n_value = (AstNumLit *) (*value)->value; + resolve_expression_type((AstTyped *) n_value); + + if (type_is_small_integer(n_value->type)) { + next_assign_value = n_value->value.i; + } else if (type_is_integer(n_value->type)) { + next_assign_value = n_value->value.l; + } else { + onyx_report_error((*value)->token->pos, "expected numeric integer literal for enum initialization, got '%s'", type_get_name(n_value->type)); + return Symres_Error; + } + + n_value->type = enum_node->etcache; + } else { - onyx_report_error((*value)->token->pos, "expected numeric integer literal for enum initialization"); - return Symres_Error; - } + if ((*value)->entity == NULL) { + add_entities_for_node(NULL, (AstNode *) (*value), enum_node->scope, NULL); + } + + if (context.cycle_detected) { + onyx_report_error((*value)->token->pos, "Expected compile time known value for enum initialization."); + return Symres_Error; + } - (*value)->value->type = enum_node->etcache; + return Symres_Yield_Macro; + } } else { AstNumLit* num = make_int_literal(context.ast_alloc, next_assign_value); num->type = enum_node->etcache; - (*value)->value = num; + (*value)->value = (AstTyped *) num; } - (*value)->flags |= Ast_Flag_Comptime; + symbol_introduce(enum_node->scope, (*value)->token, (AstNode *) (*value)); + + (*value)->flags |= Ast_Flag_Comptime | Ast_Flag_Has_Been_Checked; if (enum_node->is_flags) { next_assign_value <<= 1; @@ -1090,6 +1130,14 @@ static SymresStatus symres_enum(AstEnumType* enum_node) { next_assign_value++; } } + + scope_leave(); + + // HACK this ensure that you can only lookup symbols in an Enum that are actually defined in the enum. + // However, during the symbol resolution of the values in an enum, they need to be able to see the + // enclosing scope. + enum_node->scope->parent = NULL; + return Symres_Success; } diff --git a/src/types.c b/src/types.c index d0a18e47..c89fd320 100644 --- a/src/types.c +++ b/src/types.c @@ -1181,6 +1181,7 @@ b32 type_is_bool(Type* type) { b32 type_is_small_integer(Type* type) { if (type == NULL) return 0; + if (type->kind == Type_Kind_Enum) return type_is_small_integer(type->Enum.backing); if (type->kind != Type_Kind_Basic) return 0; return type->Basic.kind >= Basic_Kind_I8 && type->Basic.kind <= Basic_Kind_U32; @@ -1188,6 +1189,7 @@ b32 type_is_small_integer(Type* type) { b32 type_is_integer(Type* type) { if (type == NULL) return 0; + if (type->kind == Type_Kind_Enum) return type_is_integer(type->Enum.backing); if (type->kind != Type_Kind_Basic) return 0; return (type->Basic.kind >= Basic_Kind_I8 && type->Basic.kind <= Basic_Kind_U64) diff --git a/src/wasm_emit.c b/src/wasm_emit.c index 850050f0..eec3e854 100644 --- a/src/wasm_emit.c +++ b/src/wasm_emit.c @@ -2782,9 +2782,12 @@ EMIT_FUNC(expression, AstTyped* expr) { case Ast_Kind_Enum_Value: { AstEnumValue* ev = (AstEnumValue *) expr; + AstNumLit * num = (AstNumLit *) ev->value; + assert(num->kind == Ast_Kind_NumLit); + WasmType backing_type = onyx_type_to_wasm_type(ev->type); - if (backing_type == WASM_TYPE_INT32) WID(WI_I32_CONST, ev->value->value.i); - else if (backing_type == WASM_TYPE_INT64) WID(WI_I64_CONST, ev->value->value.l); + if (backing_type == WASM_TYPE_INT32) WID(WI_I32_CONST, num->value.i); + else if (backing_type == WASM_TYPE_INT64) WID(WI_I64_CONST, num->value.l); else onyx_report_error(ev->token->pos, "Invalid backing type for enum."); break; } diff --git a/src/wasm_type_table.c b/src/wasm_type_table.c index 96632740..f67f4823 100644 --- a/src/wasm_type_table.c +++ b/src/wasm_type_table.c @@ -146,7 +146,10 @@ u64 build_type_table(OnyxWasmModule* module) { PATCH; bh_buffer_write_u64(&table_buffer, name_loc); bh_buffer_write_u64(&table_buffer, (*value)->token->length); - bh_buffer_write_u64(&table_buffer, (*value)->value->value.l); + + assert((*value)->value->kind == Ast_Kind_NumLit); + AstNumLit *num = (AstNumLit *) (*value)->value; + bh_buffer_write_u64(&table_buffer, num->value.l); } u32 name_base = table_buffer.length; diff --git a/tests/complicated_polymorph.onyx b/tests/complicated_polymorph.onyx index f3d56874..364cfd7d 100644 --- a/tests/complicated_polymorph.onyx +++ b/tests/complicated_polymorph.onyx @@ -24,10 +24,10 @@ main :: (args: [] cstr) { compose(10.0f, dumb, (ABC) => ABC + 3) |> println(); - double :: (x) => x * 2; - convert :: (x: $T, $TO: type_expr) => cast(TO) x; - add :: (x: $T, y: T) => x + y; - map :: (x: $T, f: (T) -> $R) => f(x); + double :: macro (x) => x * 2; + convert :: macro (x: $T, $TO: type_expr) => cast(TO) x; + add :: macro (x: $T, y: T) => x + y; + map :: macro (x: $T, f: (T) -> $R) => f(x); 5 |> double() |> map((x) => x * 3)