enum values are no longer bad
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 15 Nov 2021 19:27:20 +0000 (13:27 -0600)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 15 Nov 2021 19:27:20 +0000 (13:27 -0600)
include/astnodes.h
src/astnodes.c
src/checker.c
src/entities.c
src/parser.c
src/symres.c
src/types.c
src/wasm_emit.c
src/wasm_type_table.c
tests/complicated_polymorph.onyx

index 64a620dd8ec0f7d0946019815cb7de49d935a5d9..d3bded15a99a77e974ad2f286aecabd73377baea 100644 (file)
@@ -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;
index a7bd73e17ed6f638676a4a635b5af6ba00322591..b7a2ab4e9b1846bb13c062475818a35e6c4c86d8 100644 (file)
@@ -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;
         }
     }
index e03fe86e53c75637735d2df3fa19809ee46c17d2..0a68c9a6ed2ab30628fdf306a4a771f369b88cd2 100644 (file)
@@ -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);
index a3fe241d5aca4355e05c106a321f18ae709dad78..f489b356c7a6699fa7b17930f74e4f09739c1a01 100644 (file)
@@ -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;
index d336d3ce39076dcc75055e0ac398a51cdcd17281..f7222b68172331fc22e6deec554b8a9d79418465 100644 (file)
@@ -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, ';');
index 12ad701cf8cee185d14bb660d33c18e75ef7b1e3..b8908ae4c3d7985f961ec79525d7936f06457f17 100644 (file)
@@ -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;
 }
 
index d0a18e473c876edba04e16b7d0a49a68534011d7..c89fd32084c59c42a6dce2d4910972399a8c66f6 100644 (file)
@@ -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)
index 850050f08e44e8284e5f9a6b0c305afc02edd0c7..eec3e85487d87e741006be716c64543156aa9d31 100644 (file)
@@ -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;
         }
index 966327409d04a6f0b932e96456e638c175a7394e..f67f4823a2ba52f9ab04e54fa1d5318273f5eb7c 100644 (file)
@@ -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;
index f3d5687422a051bc45bfba86f7e3c562afb1ac8c..364cfd7d646502ba553b454dbdf071c30f36cf87 100644 (file)
@@ -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)