From: Brendan Hansen Date: Mon, 23 Aug 2021 00:00:47 +0000 (-0500) Subject: added 'typeof' X-Git-Url: https://git.brendanfh.com/?a=commitdiff_plain;h=4c89a86ee6b423d76b03b25ba1eae226b3245fd4;p=onyx.git added 'typeof' --- diff --git a/bin/onyx b/bin/onyx index 61209641..dcc66d87 100755 Binary files a/bin/onyx and b/bin/onyx differ diff --git a/include/onyxastnodes.h b/include/onyxastnodes.h index a632a022..aa27da73 100644 --- a/include/onyxastnodes.h +++ b/include/onyxastnodes.h @@ -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; }; diff --git a/include/onyxlex.h b/include/onyxlex.h index 7c4789ae..43fed670 100644 --- a/include/onyxlex.h +++ b/include/onyxlex.h @@ -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, diff --git a/misc/onyx.sublime-syntax b/misc/onyx.sublime-syntax index a5666d38..d07244e5 100644 --- a/misc/onyx.sublime-syntax +++ b/misc/onyx.sublime-syntax @@ -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' diff --git a/misc/onyx.vim b/misc/onyx.vim index a6a79a51..7f750f83 100644 --- a/misc/onyx.vim +++ b/misc/onyx.vim @@ -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 diff --git a/src/onyxastnodes.c b/src/onyxastnodes.c index 86c30aa8..409523f9 100644 --- a/src/onyxastnodes.c +++ b/src/onyxastnodes.c @@ -41,6 +41,7 @@ static const char* ast_node_names[] = { "TYPE_ALIAS", "TYPE RAW ALIAS", "COMPOUND TYPE", + "TYPE OF", "TYPE_END (BAD)", "STRUCT MEMBER", diff --git a/src/onyxchecker.c b/src/onyxchecker.c index a8947f42..f17d7354 100644 --- a/src/onyxchecker.c +++ b/src/onyxchecker.c @@ -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; diff --git a/src/onyxclone.c b/src/onyxclone.c index 12ad5373..4c08c4ba 100644 --- a/src/onyxclone.c +++ b/src/onyxclone.c @@ -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--; diff --git a/src/onyxlex.c b/src/onyxlex.c index 433c3b9d..eefcdd16 100644 --- a/src/onyxlex.c +++ b/src/onyxlex.c @@ -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); diff --git a/src/onyxparser.c b/src/onyxparser.c index de862194..fd52bb48 100644 --- a/src/onyxparser.c +++ b/src/onyxparser.c @@ -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); diff --git a/src/onyxsymres.c b/src/onyxsymres.c index c571d28a..27a28f71 100644 --- a/src/onyxsymres.c +++ b/src/onyxsymres.c @@ -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, ¶m->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, ¶m->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 diff --git a/src/onyxtypes.c b/src/onyxtypes.c index 125461ab..eaa931fa 100644 --- a/src/onyxtypes.c +++ b/src/onyxtypes.c @@ -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;