added 'typeof'
authorBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 23 Aug 2021 00:00:47 +0000 (19:00 -0500)
committerBrendan Hansen <brendan.f.hansen@gmail.com>
Mon, 23 Aug 2021 00:00:47 +0000 (19:00 -0500)
12 files changed:
bin/onyx
include/onyxastnodes.h
include/onyxlex.h
misc/onyx.sublime-syntax
misc/onyx.vim
src/onyxastnodes.c
src/onyxchecker.c
src/onyxclone.c
src/onyxlex.c
src/onyxparser.c
src/onyxsymres.c
src/onyxtypes.c

index 61209641ef06439b7698939dd0dce9c6b7fb936a..dcc66d87ec88b434b61b2127f01e166884245602 100755 (executable)
Binary files a/bin/onyx and b/bin/onyx differ
index a632a0226ba3195fc18e1f88f19f096f1cdd4553..aa27da733d8b1806cad450412dfce63c765ea360 100644 (file)
@@ -66,6 +66,7 @@
     NODE(TypeAlias)            \
     NODE(TypeRawAlias)         \
     NODE(CompoundType)         \
+    NODE(TypeOf)               \
                                \
     NODE(Binding)              \
     NODE(Alias)                \
@@ -144,6 +145,7 @@ typedef enum AstKind {
     Ast_Kind_Type_Alias,
     Ast_Kind_Type_Raw_Alias,
     Ast_Kind_Type_Compound,
+    Ast_Kind_Typeof,
     Ast_Kind_Type_End,
 
     Ast_Kind_Struct_Member,
@@ -252,6 +254,9 @@ typedef enum AstFlags {
     Ast_Flag_Has_Been_Checked      = BH_BIT(27),
 
     Ast_Flag_Static_If_Resolved    = BH_BIT(28),
+
+    // :TEMPORARY
+    Ast_Flag_Params_Introduced     = BH_BIT(29),
 } AstFlags;
 
 typedef enum UnaryOp {
@@ -808,6 +813,12 @@ struct AstCompoundType {
 
     bh_arr(AstType *) types;
 };
+struct AstTypeOf {
+    AstType_base;
+
+    AstTyped* expr;
+    Type* resolved_type;
+};
 
 // Top level nodes
 struct AstBinding       { AstTyped_base; AstNode* node; };
index 7c4789aeadd8121e3d1fa218be04c6fae8f6ca4a..43fed6705474bc40a39230fc18ce4883fb2c3d10 100644 (file)
@@ -32,6 +32,7 @@ typedef enum TokenType {
     Token_Type_Keyword_Continue,
     Token_Type_Keyword_Sizeof,
     Token_Type_Keyword_Alignof,
+    Token_Type_Keyword_Typeof,
     Token_Type_Keyword_Defer,
     Token_Type_Keyword_Do,
     Token_Type_Keyword_Case,
index a5666d386eafd8ea6619698d89bea8553ca2c2e9..d07244e5ccb9e52d859587089df25b1560fe8387 100644 (file)
@@ -26,7 +26,7 @@ contexts:
     # strings in YAML. When using single quoted strings, only single quotes
     # need to be escaped: this is done by using two single quotes next to each
     # other.
-    - match: '\b(package|struct|use|global|enum|if|elseif|else|for|while|do|break|continue|fallthrough|return|as|cast|sizeof|alignof|defer|switch|case|macro)\b'
+    - match: '\b(package|struct|use|global|enum|if|elseif|else|for|while|do|break|continue|fallthrough|return|as|cast|sizeof|alignof|typeof|defer|switch|case|macro)\b'
       scope: keyword.control.onyx
 
     - match: '\b(bool|void|i8|u8|i16|u16|i32|u32|i64|u64|f32|f64|rawptr|str|cstr|range|type_expr|any)\b'
index a6a79a512eb897453dc84c7a6cd7c00a2bbd50f3..7f750f832855eb81962a0a2f12018b63116b8814 100644 (file)
@@ -15,7 +15,7 @@ syn keyword onyxKeyword if elseif else
 syn keyword onyxKeyword for while do
 syn keyword onyxKeyword switch case
 syn keyword onyxKeyword break continue return defer fallthrough
-syn keyword onyxKeyword as cast sizeof alignof
+syn keyword onyxKeyword as cast sizeof alignof typeof
 syn keyword onyxType bool void
 syn keyword onyxType i8 u8
 syn keyword onyxType i16 u16
index 86c30aa88d10b58ae1e2a8ca1d6c447ea3ee2bdc..409523f9fc18b1af7f6029dde1cc265a7693472e 100644 (file)
@@ -41,6 +41,7 @@ static const char* ast_node_names[] = {
     "TYPE_ALIAS",
     "TYPE RAW ALIAS",
     "COMPOUND TYPE",
+    "TYPE OF",
     "TYPE_END (BAD)",
 
     "STRUCT MEMBER",
index a8947f421ecd18cb42b85bdb616cfcb2dbcfa3ca..f17d73543b6ca27f34ab897b0485bd73df2c4941 100644 (file)
@@ -1607,6 +1607,10 @@ CheckStatus check_expression(AstTyped** pexpr) {
         // This is to ensure that the type will exist when compiling. For example, a poly-call type
         // would have to wait for the entity to pass through, which the code generation does not know
         // about.
+        if (expr->kind == Ast_Kind_Typeof) {
+            CHECK(type, (AstType *) expr);
+        }
+
         if (type_build_from_ast(context.ast_alloc, (AstType*) expr) == NULL) {
             return Check_Yield_Macro;
         }
@@ -1646,7 +1650,7 @@ CheckStatus check_expression(AstTyped** pexpr) {
 
         case Ast_Kind_Param:
             if (expr->type == NULL) {
-                onyx_report_error(expr->token->pos, "Parameter with unknown type. You should hopefully never see this.");
+                onyx_report_error(expr->token->pos, "Parameter with bad type.");
                 retval = Check_Error;
             }
             break;
@@ -1848,6 +1852,8 @@ CheckStatus check_statement(AstNode** pstmt) {
             AstTyped* typed_stmt = (AstTyped *) stmt;
             fill_in_type(typed_stmt);
             if (typed_stmt->type_node != NULL && typed_stmt->type == NULL) {
+                CHECK(type, typed_stmt->type_node);
+
                 if (!node_is_type((AstNode *) typed_stmt->type_node)) {
                     onyx_report_error(stmt->token->pos, "Local's type is not a type.");
                     return Check_Error;
@@ -2156,15 +2162,57 @@ CheckStatus check_type(AstType* type) {
     while (type->kind == Ast_Kind_Type_Alias)
         type = ((AstTypeAlias *) type)->to;
 
-    if (type->kind == Ast_Kind_Poly_Call_Type) {
-        AstPolyCallType* pc_node = (AstPolyCallType *) type;
+    switch (type->kind) {
+        case Ast_Kind_Poly_Call_Type: {
+            AstPolyCallType* pc_node = (AstPolyCallType *) type;
 
-        bh_arr_each(AstNode *, param, pc_node->params) {
-            if (!node_is_type(*param)) {
-                CHECK(expression, (AstTyped **) param);
-                resolve_expression_type((AstTyped *) *param);
+            bh_arr_each(AstNode *, param, pc_node->params) {
+                if (!node_is_type(*param)) {
+                    CHECK(expression, (AstTyped **) param);
+                    resolve_expression_type((AstTyped *) *param);
+                }
             }
+
+            break;
         }
+
+        case Ast_Kind_Typeof: {
+            AstTypeOf *type_of = (AstTypeOf *) type;
+            CHECK(expression, (AstTyped **) &type_of->expr);
+            resolve_expression_type(type_of->expr);
+
+            if (type_of->expr->type == NULL) {
+                return Check_Yield_Macro;
+            }
+
+            type_of->resolved_type = type_of->expr->type;
+            break;
+        }
+
+        case Ast_Kind_Pointer_Type: CHECK(type, ((AstPointerType *) type)->elem); break;
+        case Ast_Kind_Slice_Type:   CHECK(type, ((AstSliceType *) type)->elem); break;
+        case Ast_Kind_DynArr_Type:  CHECK(type, ((AstDynArrType *) type)->elem); break;
+        case Ast_Kind_VarArg_Type:  CHECK(type, ((AstVarArgType *) type)->elem); break;
+
+        case Ast_Kind_Function_Type: {
+            AstFunctionType* ftype = (AstFunctionType *) type;
+
+            CHECK(type, ftype->return_type);
+
+            if (ftype->param_count > 0) {
+                fori (i, 0, (i64) ftype->param_count) {
+                    CHECK(type, ftype->params[i]);
+                }
+            }
+            break;
+        }
+
+        case Ast_Kind_Type_Compound: {
+            AstCompoundType* ctype = (AstCompoundType *) type;
+
+            bh_arr_each(AstType *, type, ctype->types) CHECK(type, *type);
+            break;
+        }    
     }
 
     return Check_Success;
index 12ad53739460d05a3ffcecd12cff6a9d570ae5ae..4c08c4ba66735f6e8fcc33d93e7b73c5fb51092b 100644 (file)
@@ -57,6 +57,7 @@ static inline i32 ast_kind_to_size(AstNode* node) {
         case Ast_Kind_Type_Alias: return sizeof(AstTypeAlias);
         case Ast_Kind_Type_Raw_Alias: return sizeof(AstTypeRawAlias);
         case Ast_Kind_Type_Compound: return sizeof(AstCompoundType);
+        case Ast_Kind_Typeof: return sizeof(AstTypeOf);
         case Ast_Kind_Type_End: return 0;
         case Ast_Kind_Struct_Member: return sizeof(AstStructMember);
         case Ast_Kind_Enum_Value: return sizeof(AstEnumValue);
@@ -449,6 +450,12 @@ AstNode* ast_clone(bh_allocator a, void* n) {
                        ((AstDirectiveInsert *) nn)->code_expr = (AstTyped *) ast_clone(a, ((AstDirectiveInsert *) node)->code_expr);
                        break;
                }
+
+               case Ast_Kind_Typeof: {
+                       ((AstTypeOf *) nn)->expr = (AstTyped *) ast_clone(a, ((AstTypeOf *) node)->expr);
+                       ((AstTypeOf *) nn)->resolved_type = NULL;
+                       break;
+               }
        }
 
        clone_depth--;
index 433c3b9db9d1cde3473c50af0208059b8ea6db5d..eefcdd16bac625cdab4567b6fe4ecfd0f76f13af 100644 (file)
@@ -30,6 +30,7 @@ static const char* token_type_names[] = {
     "continue",
     "sizeof",
     "alignof",
+    "typeof",
     "defer",
     "do",
     "switch",
@@ -346,12 +347,13 @@ whitespace_skipped:
         LITERAL_TOKEN("return",      1, Token_Type_Keyword_Return);
         break;
     case 's':
-        LITERAL_TOKEN("sizeof",      1, Token_Type_Keyword_Sizeof);
         LITERAL_TOKEN("struct",      1, Token_Type_Keyword_Struct);
+        LITERAL_TOKEN("sizeof",      1, Token_Type_Keyword_Sizeof);
         LITERAL_TOKEN("switch",      1, Token_Type_Keyword_Switch);
         break;
     case 't':
         LITERAL_TOKEN("true",        1, Token_Type_Literal_True);
+        LITERAL_TOKEN("typeof",      1, Token_Type_Keyword_Typeof);
         break;
     case 'u':
         LITERAL_TOKEN("use",         1, Token_Type_Keyword_Use);
index de862194e9473e4a60ba3f10ca78257248c68e4c..fd52bb483f69ee1d137d7e8ab8baaa3e3d6c810e 100644 (file)
@@ -57,6 +57,7 @@ static AstNode*       parse_use_stmt(OnyxParser* parser);
 static AstBlock*      parse_block(OnyxParser* parser, b32 make_a_new_scope);
 static AstNode*       parse_statement(OnyxParser* parser);
 static AstType*       parse_type(OnyxParser* parser);
+static AstTypeOf*     parse_typeof(OnyxParser* parser);
 static AstStructType* parse_struct(OnyxParser* parser);
 static void           parse_function_params(OnyxParser* parser, AstFunction* func);
 static b32            parse_possible_directive(OnyxParser* parser, const char* dir);
@@ -421,6 +422,11 @@ static AstTyped* parse_factor(OnyxParser* parser) {
             break;
         }
 
+        case Token_Type_Keyword_Typeof: {
+            retval = (AstTyped *) parse_typeof(parser);
+            break;
+        }
+
         case Token_Type_Symbol: {
             OnyxToken* sym_token = expect_token(parser, Token_Type_Symbol);
             AstTyped* sym_node = make_node(AstTyped, Ast_Kind_Symbol);
@@ -1734,6 +1740,12 @@ static AstType* parse_type(OnyxParser* parser) {
                 break;
             }
 
+            case Token_Type_Keyword_Typeof: {
+                *next_insertion = (AstType *) parse_typeof(parser);
+                next_insertion = NULL;
+                break;
+            }
+
             default:
                 onyx_report_error(parser->curr->pos, "unexpected token '%b'.", parser->curr->text, parser->curr->length);
                 consume_token(parser);
@@ -1746,6 +1758,17 @@ static AstType* parse_type(OnyxParser* parser) {
     return root;
 }
 
+static AstTypeOf* parse_typeof(OnyxParser* parser) {
+    OnyxToken* token = expect_token(parser, Token_Type_Keyword_Typeof);
+
+    AstTypeOf* type_of = make_node(AstTypeOf, Ast_Kind_Typeof);
+    type_of->token = token;
+    type_of->expr = parse_expression(parser, 0);
+    type_of->resolved_type = NULL;
+
+    return type_of;
+}
+
 static AstStructType* parse_struct(OnyxParser* parser) {
     OnyxToken *s_token = expect_token(parser, Token_Type_Keyword_Struct);
 
index c571d28a0b7389e38b32cf263546156a7d1f5405..27a28f7176ab70ba9c60bb1fe6c93d2d859e605d 100644 (file)
@@ -229,6 +229,12 @@ static SymresStatus symres_type(AstType** type) {
             SYMRES(type, (AstType **) &alias->alias);
             break;
         }
+
+        case Ast_Kind_Typeof: {
+            AstTypeOf* type_of = (AstTypeOf *) *type;
+            SYMRES(expression, &type_of->expr);
+            break;
+        }
     }
 
     return Symres_Success;
@@ -842,6 +848,11 @@ static SymresStatus symres_block(AstBlock* block) {
 SymresStatus symres_function_header(AstFunction* func) {
     func->flags |= Ast_Flag_Comptime;
 
+    if (func->scope == NULL)
+        func->scope = scope_create(context.ast_alloc, curr_scope, func->token->pos);
+
+    scope_enter(func->scope);
+
     bh_arr_each(AstParam, param, func->params) {
         if (param->default_value != NULL) {
             SYMRES(expression, &param->default_value);
@@ -849,9 +860,12 @@ SymresStatus symres_function_header(AstFunction* func) {
         }
     }
 
-    SYMRES(type, &func->return_type);
-    if (!node_is_type((AstNode *) func->return_type)) {
-        onyx_report_error(func->token->pos, "Return type is not a type.");
+    if ((func->flags & Ast_Flag_Params_Introduced) == 0) {
+        bh_arr_each(AstParam, param, func->params) {
+            symbol_introduce(curr_scope, param->local->token, (AstNode *) param->local);
+        }
+
+        func->flags |= Ast_Flag_Params_Introduced;
     }
 
     bh_arr_each(AstParam, param, func->params) {
@@ -859,6 +873,14 @@ SymresStatus symres_function_header(AstFunction* func) {
             SYMRES(type, &param->local->type_node);
         }
     }
+
+    SYMRES(type, &func->return_type);
+    if (!node_is_type((AstNode *) func->return_type)) {
+        onyx_report_error(func->token->pos, "Return type is not a type.");
+    }
+
+    scope_leave();
+
     return Symres_Success;
 }
 
@@ -871,8 +893,6 @@ SymresStatus symres_function(AstFunction* func) {
 
     if ((func->flags & Ast_Flag_Has_Been_Symres) == 0) {
         bh_arr_each(AstParam, param, func->params) {
-            symbol_introduce(curr_scope, param->local->token, (AstNode *) param->local);
-
             // CLEANUP: Currently, in order to 'use' parameters, the type must be completely
             // resolved and built. This is excessive because all that should need to be known
             // is the names of the members, since all that happens is implicit field accesses
index 125461ab8df332ca584bd76d29cb6c91dbb0ea56..eaa931fad764d2f89661fc260dc633d30571c9d5 100644 (file)
@@ -359,7 +359,7 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
 
                 mem_alignment = type_alignment_of((*member)->type);
                 if (mem_alignment <= 0) {
-                    onyx_report_error((*member)->token->pos, "Invalid member type: %s", type_get_name((*member)->type)); 
+                    onyx_report_error((*member)->token->pos, "Invalid member type: %s. Has alignment %d", type_get_name((*member)->type), mem_alignment); 
                     return NULL;
                 }
 
@@ -576,6 +576,15 @@ Type* type_build_from_ast(bh_allocator alloc, AstType* type_node) {
             AstAlias* alias = (AstAlias *) type_node;
             return type_build_from_ast(alloc, (AstType *) alias->alias);
         }
+
+        case Ast_Kind_Typeof: {
+            AstTypeOf* type_of = (AstTypeOf *) type_node;
+            if (type_of->resolved_type != NULL) {
+                return type_of->resolved_type;
+            }
+            
+            return NULL;
+        }
     }
 
     return NULL;