Added initial implementation of enums; bugfixes will be needed
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 26 Jul 2020 16:22:36 +0000 (11:22 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Sun, 26 Jul 2020 16:22:36 +0000 (11:22 -0500)
include/onyxastnodes.h
include/onyxtypes.h
onyx
progs/ez.onyx
src/onyx.c
src/onyxchecker.c
src/onyxparser.c
src/onyxsymres.c
src/onyxtypes.c
src/onyxutils.c
src/onyxwasm.c

index f2ac24e1820854b4767183914f199da0eae93a46..1beab6f640e78240e3bd6137e77399e413b88767 100644 (file)
@@ -38,6 +38,8 @@ typedef struct AstFunctionType AstFunctionType;
 typedef struct AstArrayType AstArrayType;
 typedef struct AstStructType AstStructType;
 typedef struct AstStructMember AstStructMember;
+typedef struct AstEnumType AstEnumType;
+typedef struct AstEnumValue AstEnumValue;
 
 typedef struct AstBinding AstBinding;
 typedef struct AstIncludeFile AstIncludeFile;
@@ -83,9 +85,11 @@ typedef enum AstKind {
     Ast_Kind_Function_Type,
     Ast_Kind_Array_Type,
     Ast_Kind_Struct_Type,
+    Ast_Kind_Enum_Type,
     Ast_Kind_Type_End,
 
     Ast_Kind_Struct_Member,
+    Ast_Kind_Enum_Value,
 
     Ast_Kind_NumLit,
     Ast_Kind_StrLit,
@@ -303,6 +307,19 @@ struct AstStructType {
     Type *stcache;
 };
 struct AstStructMember { AstTyped_base; u64 offset; };
+struct AstEnumType {
+    AstType_base;
+    Scope *scope;
+
+    AstType *backing;
+    Type    *backing_type;
+
+    bh_arr(AstEnumValue *) values;
+
+    // NOTE: Used to cache the actual type for the same reason as above.
+    Type *etcache;
+};
+struct AstEnumValue { AstTyped_base; AstNumLit* value; };
 
 // Top level nodes
 struct AstBinding       { AstTyped_base; AstNode* node; };
@@ -359,13 +376,13 @@ struct AstPackage {
     Package* package;
 };
 
-
 // NOTE: An Entity represents something will need to be
 // processed later down the pipeline.
 typedef enum EntityType {
     Entity_Type_Unknown,
     Entity_Type_Use_Package,
     Entity_Type_String_Literal,
+    Entity_Type_Enum,
     Entity_Type_Struct,
     Entity_Type_Function_Header,
     Entity_Type_Global_Header,
@@ -387,6 +404,7 @@ typedef struct Entity {
         AstTyped              *expr;
         AstStrLit             *strlit;
         AstStructType         *struct_type;
+        AstEnumType           *enum_type;
     };
 } Entity;
 
index f0cf4714efcca32437cf55ceba3d271d9a479ccb..b87f91e288d4924c38543d8fe6f7b0b92392961a 100644 (file)
@@ -52,21 +52,22 @@ typedef struct StructMember {
 } StructMember;
 
 #define TYPE_KINDS \
-    TYPE_KIND(Basic, TypeBasic)                                 \
-    TYPE_KIND(Pointer, struct { TypeBasic base; Type *elem; })  \
-    TYPE_KIND(Function, struct {                                \
-        Type *return_type;                                      \
-        u64 param_count;                                        \
-        Type* params[];                                         \
-    })                                                          \
-    TYPE_KIND(Struct, struct {                                  \
-        char* name;                                             \
-        u32 size;                                               \
-        u32 mem_count;                                          \
-        bh_table(StructMember) members;                         \
-        bh_arr(StructMember *) memarr;                          \
-    })                                                          \
-    TYPE_KIND(Array, struct { u32 size; u32 count; Type *elem; })
+    TYPE_KIND(Basic, TypeBasic)                                   \
+    TYPE_KIND(Pointer, struct { TypeBasic base; Type *elem; })    \
+    TYPE_KIND(Function, struct {                                  \
+        Type *return_type;                                        \
+        u64 param_count;                                          \
+        Type* params[];                                           \
+    })                                                            \
+    TYPE_KIND(Struct, struct {                                    \
+        char* name;                                               \
+        u32 size;                                                 \
+        u32 mem_count;                                            \
+        bh_table(StructMember) members;                           \
+        bh_arr(StructMember *) memarr;                            \
+    })                                                            \
+    TYPE_KIND(Array, struct { u32 size; u32 count; Type *elem; }) \
+    TYPE_KIND(Enum, struct { char* name; Type* backing; }) 
 
 typedef enum TypeKind {
     Type_Kind_Invalid,
diff --git a/onyx b/onyx
index 484c0693d9084abed638e27dd23e8a0bafae2f8c..a46eafd47af0b8a0a1c4b36ca32ac2aa77522e87 100755 (executable)
Binary files a/onyx and b/onyx differ
index 40df5fc8017ef7d4bc8b3098610264c1ee66255c..5df021ff5aa95de602f1ca928cfe179bbfff5583 100644 (file)
@@ -1,12 +1,12 @@
 use "progs/print_funcs"
 
-use package printing as p {
-    print_f32, PrintableArray
-}
+use package printing
 
 Foo :: struct {
     x : i32;
     y : i32;
+
+    st : SomeType;
 }
 
 foo_sum :: proc (foo: ^Foo) -> i32 {
@@ -14,21 +14,39 @@ foo_sum :: proc (foo: ^Foo) -> i32 {
 }
 
 asdf :: proc (pa: PrintableArray) {
-    for i: 0, pa.len p.print(pa.data[i] as i32);
+    for i: 0, pa.len print(pa.data[i] as i32);
+}
+
+SomeType :: enum (u16) {
+    Value1;
+    Value2;
+    Value3 = 80;
+    Value4;
+}
+
+print_st :: proc (st: SomeType) {
+    print(st as i32);
 }
 
 proc #export "main" {
+
+    st := SomeType.Value4;
+    print_st(st);
+
     foo := __heap_start as ^Foo;
     foo.x = 123;
     foo.y = 321;
-    p.print(foo.foo_sum());
+    foo.st = st;
+    print(sizeof Foo);
+    print(foo.foo_sum());
+    print_st(foo.st);
 
-    pa := (__heap_start as i32 + 8) as ^p.PrintableArray;
+    pa := (__heap_start as i32 + sizeof Foo) as ^PrintableArray;
     pa.data = __heap_start as ^u8;
     pa.len = 5;
     asdf(*pa);
 
-    p.print(1234);
+    print(1234);
 
     print_f32(123.0f);
 }
index 177d18b3c27a2bf1783e22c0c82096363cae527b..76d1a3bc7cbb509288c1dfea2b2039b32f630da2 100644 (file)
@@ -230,6 +230,13 @@ static void merge_parse_results(CompilerState* compiler_state, ParseResults* res
                 break;
             }
 
+            case Ast_Kind_Enum_Type: {
+                ent.type = Entity_Type_Enum;
+                ent.enum_type = (AstEnumType *) node;
+                bh_arr_push(compiler_state->prog_info.entities, ent);
+                break;
+            }
+
             case Ast_Kind_Use_Package: {
                 ent.type = Entity_Type_Use_Package;
                 ent.use_package = (AstUsePackage *) node;
index 174d9ce24259f53d2459c43daab850d92f8349f9..cf6960b1bd49f7108bdbfdc5729513edf9283564 100644 (file)
@@ -647,6 +647,7 @@ CHECK(expression, AstTyped** pexpr) {
         case Ast_Kind_StrLit: break;
         case Ast_Kind_Function: break;
         case Ast_Kind_Overloaded_Function: break;
+        case Ast_Kind_Enum_Value: break;
 
         default:
             retval = 1;
@@ -935,6 +936,8 @@ void onyx_type_check() {
                 if (check_struct(entity->struct_type)) return;
                 break;
 
+            case Entity_Type_Enum: break;
+
             case Entity_Type_String_Literal: break;
 
             case Entity_Type_Global_Header: break;
index fb6792e13ed44e6cbc55917d1885e1c1cf621344..608e3f2aed84835a83db700e888770b294e3721b 100644 (file)
@@ -29,6 +29,7 @@ static AstStructType* parse_struct(OnyxParser* parser);
 static AstLocal*      parse_function_params(OnyxParser* parser);
 static AstFunction*   parse_function_definition(OnyxParser* parser);
 static AstTyped*      parse_global_declaration(OnyxParser* parser);
+static AstEnumType*   parse_enum_declaration(OnyxParser* parser);
 static AstTyped*      parse_top_level_expression(OnyxParser* parser);
 static AstNode*       parse_top_level_statement(OnyxParser* parser);
 
@@ -1060,6 +1061,46 @@ static AstTyped* parse_global_declaration(OnyxParser* parser) {
     return (AstTyped *) global_node;
 }
 
+static AstEnumType* parse_enum_declaration(OnyxParser* parser) {
+    AstEnumType* enum_node = make_node(AstEnumType, Ast_Kind_Enum_Type);
+    enum_node->token = expect_token(parser, Token_Type_Keyword_Enum);
+
+    bh_arr_new(global_heap_allocator, enum_node->values, 4);
+
+    AstType* backing = (AstType *) &basic_type_u32;
+    if (parser->curr->type == '(') {
+        consume_token(parser);
+
+        AstNode* backing_sym = make_node(AstNode, Ast_Kind_Symbol);
+        backing_sym->token = expect_token(parser, Token_Type_Symbol);
+        backing = (AstType *) backing_sym;
+
+        expect_token(parser, ')');
+    }
+    enum_node->backing = backing;
+
+    expect_token(parser, '{');
+
+    while (parser->curr->type != '}') {
+        AstEnumValue* evalue = make_node(AstEnumValue, Ast_Kind_Enum_Value);
+        evalue->token = expect_token(parser, Token_Type_Symbol);
+        evalue->type_node = (AstType *) enum_node;
+
+        if (parser->curr->type == '=') {
+            consume_token(parser);
+            evalue->value = parse_numeric_literal(parser);
+        }
+
+        expect_token(parser, ';');
+
+        bh_arr_push(enum_node->values, evalue);
+    }
+
+    expect_token(parser, '}');
+
+    return enum_node;
+}
+
 // <proc>
 // <global>
 // <expr>
@@ -1078,8 +1119,7 @@ static AstTyped* parse_top_level_expression(OnyxParser* parser) {
         return (AstTyped *) parse_struct(parser);
     }
     else if (parser->curr->type == Token_Type_Keyword_Enum) {
-        consume_token(parser);
-        return (AstTyped *) &error_node;
+        return (AstTyped *) parse_enum_declaration(parser);
     }
     else {
         return parse_expression(parser);
@@ -1166,7 +1206,7 @@ static AstNode* parse_top_level_statement(OnyxParser* parser) {
             } else if (node->kind != Ast_Kind_Overloaded_Function
                     && node->kind != Ast_Kind_StrLit) {
 
-                if (node->kind == Ast_Kind_Struct_Type) {
+                if (node->kind == Ast_Kind_Struct_Type || node->kind == Ast_Kind_Enum_Type) {
                     ((AstStructType *)node)->name = bh_aprintf(global_heap_allocator,
                         "%b", symbol->text, symbol->length);
                 }
index 3fbf0ff9d1a5683f4449a0ad0bf6906ad2ea844e..a17ad421310135d3145c918f25919fcce57935c9 100644 (file)
@@ -61,6 +61,7 @@ static void symres_function(AstFunction* func);
 static void symres_global(AstGlobal* global);
 static void symres_overloaded_function(AstOverloadedFunction* ofunc);
 static void symres_use_package(AstUsePackage* package);
+static void symres_enum(AstEnumType* enum_node);
 
 static void scope_enter(Scope* new_scope) {
     if (new_scope->parent == NULL)
@@ -184,6 +185,17 @@ static void symres_field_access(AstFieldAccess** fa) {
         if (n) {
             // NOTE: not field access
             *fa = (AstFieldAccess *) n;
+            return;
+        }
+    }
+
+    if ((*fa)->expr->kind == Ast_Kind_Enum_Type) {
+        AstEnumType* etype = (AstEnumType *) (*fa)->expr;
+        AstNode* n = symbol_resolve(etype->scope, (*fa)->token);
+        if (n) {
+            // NOTE: not field access
+            *fa = (AstFieldAccess *) n;
+            return;
         }
     }
 }
@@ -393,6 +405,44 @@ static void symres_use_package(AstUsePackage* package) {
         scope_include(semstate.curr_package->include_scope, p->scope);
 }
 
+static void symres_enum(AstEnumType* enum_node) {
+    if (enum_node->backing->kind == Ast_Kind_Symbol) {
+        enum_node->backing = (AstType *) symbol_resolve(semstate.curr_scope, enum_node->backing->token);
+    }
+    if (enum_node->backing == NULL) return;
+
+    enum_node->backing_type = type_build_from_ast(semstate.allocator, enum_node->backing);
+    enum_node->scope = scope_create(semstate.node_allocator, NULL);
+
+    u64 next_assign_value = 0;
+    bh_arr_each(AstEnumValue *, value, enum_node->values) {
+        symbol_introduce(enum_node->scope, (*value)->token, (AstNode *) *value);
+
+        if ((*value)->value != NULL) {
+            // HACK
+            if ((*value)->value->type_node == (AstType *) &basic_type_i32) {
+                next_assign_value = (*value)->value->value.i;
+            } else if ((*value)->value->type_node == (AstType *) &basic_type_i64) {
+                next_assign_value = (*value)->value->value.l;
+            } else {
+                onyx_message_add(Msg_Type_Literal,
+                    (*value)->value->token->pos,
+                    "expected numeric integer literal for enum initialization");
+                return;
+            }
+
+        } else {
+            AstNumLit* num = onyx_ast_node_new(semstate.node_allocator, sizeof(AstNumLit), Ast_Kind_NumLit);
+            num->value.l = next_assign_value;
+            num->type_node = enum_node->backing;
+            num->type = enum_node->backing_type;
+            (*value)->value = num;
+        }
+
+        next_assign_value++;
+    }
+}
+
 void onyx_resolve_symbols() {
 
     semstate.curr_scope = semstate.program->global_scope;
@@ -415,6 +465,7 @@ void onyx_resolve_symbols() {
             case Entity_Type_Global:              symres_global(entity->global); break;
             case Entity_Type_Expression:          symres_expression(&entity->expr); break;
             case Entity_Type_Struct:              symres_type((AstType *) entity->struct_type); break;
+            case Entity_Type_Enum:                symres_enum(entity->enum_type); break;
 
             default: break;
         }
index bc3663693b5f090faa3f7093bc6c064e47a725dd..37271b48d1fabd7549ed9ee9d17a6e870a40afa7 100644 (file)
@@ -75,6 +75,11 @@ b32 types_are_surface_compatible(Type* t1, Type* t2) {
             return works;
         }
 
+        case Type_Kind_Enum: {
+            if (t2->kind != Type_Kind_Enum) return 0;
+            return t1 == t2;
+        }
+
         default:
             assert(("Invalid type", 0));
             break;
@@ -138,6 +143,11 @@ b32 types_are_compatible(Type* t1, Type* t2) {
             return works;
         }
 
+        case Type_Kind_Enum: {
+            if (t2->kind != Type_Kind_Enum) return 0;
+            return t1 == t2;
+        }
+
         default:
             assert(("Invalid type", 0));
             break;
@@ -155,6 +165,7 @@ u32 type_size_of(Type* type) {
         case Type_Kind_Function: return 0;
         case Type_Kind_Array:    return type->Array.size;
         case Type_Kind_Struct:   return type->Struct.size;
+        case Type_Kind_Enum:     return type_size_of(type->Enum.backing);
         default:                 return 0;
     }
 }
@@ -255,6 +266,20 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
             return s_type;
         }
 
+        case Ast_Kind_Enum_Type: {
+            AstEnumType* enum_node = (AstEnumType *) type_node;
+            if (enum_node->etcache) return enum_node->etcache;
+
+            Type* enum_type = bh_alloc(alloc, sizeof(Type));
+            enum_node->etcache = enum_type;
+
+            enum_type->kind = Type_Kind_Enum;
+            enum_type->Enum.backing = enum_node->backing_type;
+            enum_type->Enum.name = enum_node->name;
+
+            return enum_type;
+        }
+
         case Ast_Kind_Basic_Type:
             return ((AstBasicType *) type_node)->type;
 
@@ -318,6 +343,11 @@ const char* type_get_name(Type* type) {
                 return type->Struct.name;
             else
                 return "<anonymous struct>";
+        case Type_Kind_Enum:
+            if (type->Enum.name)
+                return type->Enum.name;
+            else
+                return "<anonymous enum>";
         default: return "unknown";
     }
 }
index ec1233f59965200e5362f0fe3fdee7f33ec0a43d..14e35c5a6760e991127d06c119482379f620c24d 100644 (file)
@@ -33,9 +33,11 @@ static const char* ast_node_names[] = {
     "FUNCTION_TYPE",
     "ARRAY TYPE",
     "STRUCT TYPE",
+    "ENUM TYPE"
     "TYPE_END (BAD)",
 
     "STRUCT MEMBER",
+    "ENUM VALUE",
 
     "NUMERIC LITERAL",
     "STRING LITERAL",
index 1dff1fda5710b12d31b124b92a8ce55860022c88..bc29901d320243fa8b8725448c1b01bd4109f821 100644 (file)
@@ -205,6 +205,10 @@ static WasmType onyx_type_to_wasm_type(Type* type) {
         DEBUG_HERE;
     }
 
+    if (type->kind == Type_Kind_Enum) {
+        return onyx_type_to_wasm_type(type->Enum.backing);
+    }
+
     if (type->kind == Type_Kind_Pointer) {
         return WASM_TYPE_INT32;
     }
@@ -390,8 +394,12 @@ COMPILE_FUNC(assignment, AstBinaryOp* assign) {
 COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset) {
     bh_arr(WasmInstruction) code = *pcode;
 
+    if (type->kind == Type_Kind_Enum) {
+        type = type->Enum.backing;
+    }
+
     i32 store_size = type_size_of(type);
-    i32 is_basic   = type->kind == Type_Kind_Basic || type->kind == Type_Kind_Pointer;
+    i32 is_basic    = type->kind == Type_Kind_Basic || type->kind == Type_Kind_Pointer;
     i32 is_pointer  = is_basic && (type->Basic.flags & Basic_Flag_Pointer);
     i32 is_integer  = is_basic && (type->Basic.flags & Basic_Flag_Integer);
     i32 is_float    = is_basic && type->Basic.flags & Basic_Flag_Float;
@@ -417,6 +425,10 @@ COMPILE_FUNC(store_instruction, Type* type, u32 alignment, u32 offset) {
 
 COMPILE_FUNC(load_instruction, Type* type, u32 offset) {
     bh_arr(WasmInstruction) code = *pcode;
+    
+    if (type->kind == Type_Kind_Enum) {
+        type = type->Enum.backing;
+    }
 
     i32 load_size   = type_size_of(type);
     i32 is_basic    = type->kind == Type_Kind_Basic || type->kind == Type_Kind_Pointer;
@@ -957,6 +969,23 @@ COMPILE_FUNC(expression, AstTyped* expr) {
             break;
         }
 
+        case Ast_Kind_Enum_Value: {
+            AstEnumValue* ev = (AstEnumValue *) expr;
+            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);
+            }
+            else {
+                onyx_message_add(Msg_Type_Literal,
+                    ev->token->pos,
+                    "invalid backing type for enum");
+            }
+            break;
+        }
+
         default:
             bh_printf("Unhandled case: %d\n", expr->kind);
             DEBUG_HERE;