From: Brendan Hansen Date: Sun, 26 Jul 2020 16:22:36 +0000 (-0500) Subject: Added initial implementation of enums; bugfixes will be needed X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=52e24fcf19ca03b54ade5bd0d169ba52e66310c3;p=onyx.git Added initial implementation of enums; bugfixes will be needed --- diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index f2ac24e1..1beab6f6 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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; diff --git a/include/onyxtypes.h b/include/onyxtypes.h index f0cf4714..b87f91e2 100644 --- a/include/onyxtypes.h +++ b/include/onyxtypes.h @@ -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 484c0693..a46eafd4 100755 Binary files a/onyx and b/onyx differ diff --git a/progs/ez.onyx b/progs/ez.onyx index 40df5fc8..5df021ff 100644 --- a/progs/ez.onyx +++ b/progs/ez.onyx @@ -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); } diff --git a/src/onyx.c b/src/onyx.c index 177d18b3..76d1a3bc 100644 --- a/src/onyx.c +++ b/src/onyx.c @@ -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; diff --git a/src/onyxchecker.c b/src/onyxchecker.c index 174d9ce2..cf6960b1 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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; diff --git a/src/onyxparser.c b/src/onyxparser.c index fb6792e1..608e3f2a 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -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; +} + // // // @@ -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); } diff --git a/src/onyxsymres.c b/src/onyxsymres.c index 3fbf0ff9..a17ad421 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -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; } diff --git a/src/onyxtypes.c b/src/onyxtypes.c index bc366369..37271b48 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -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 ""; + case Type_Kind_Enum: + if (type->Enum.name) + return type->Enum.name; + else + return ""; default: return "unknown"; } } diff --git a/src/onyxutils.c b/src/onyxutils.c index ec1233f5..14e35c5a 100644 --- a/src/onyxutils.c +++ b/src/onyxutils.c @@ -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", diff --git a/src/onyxwasm.c b/src/onyxwasm.c index 1dff1fda..bc29901d 100644 --- a/src/onyxwasm.c +++ b/src/onyxwasm.c @@ -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;