From dda2252ca29824db2d59d11501033e81c3ee9783 Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Tue, 27 Sep 2022 13:50:30 +0200 Subject: [PATCH] length_of align_of size_of are no longer operators but function calls --- core_codegen_c_language.cpp | 7 +- core_compiler.h | 12 +- core_parsing.cpp | 20 +-- core_typechecking.cpp | 241 ++++++++++++++++++++---------------- 4 files changed, 146 insertions(+), 134 deletions(-) diff --git a/core_codegen_c_language.cpp b/core_codegen_c_language.cpp index 8bc1ce1..f1e501f 100644 --- a/core_codegen_c_language.cpp +++ b/core_codegen_c_language.cpp @@ -362,9 +362,10 @@ gen_expr(Ast_Expr *ast, Ast_Type *type_of_var){ BREAK(); } - CASE(LENGTH_OF, Builtin){ - gen_expr(node->expr); - if(is_pointer(node->expr->resolved_type)) + CASE(LENGTH_OF, Call){ + Ast_Expr *expr = unpack_ast_call_expr_for_builtin(node); + gen_expr(expr); + if(is_pointer(expr->resolved_type)) gen("->len"); else gen(".len"); BREAK(); diff --git a/core_compiler.h b/core_compiler.h index f9b6311..b8ace23 100644 --- a/core_compiler.h +++ b/core_compiler.h @@ -169,11 +169,11 @@ Intern_String keyword_switch; Intern_String keyword_break; Intern_String keyword_elif; Intern_String keyword_assert; -Intern_String keyword_sizeof; -Intern_String keyword_alignof; -Intern_String keyword_lengthof; Intern_String keyword_enum; +Intern_String intern_sizeof; +Intern_String intern_alignof; +Intern_String intern_lengthof; Intern_String intern_void; Intern_String intern_foreign; Intern_String intern_it; @@ -226,9 +226,6 @@ lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){ keyword_struct= l->intern("struct"_s); keyword_union = l->intern("union"_s); - keyword_sizeof = l->intern("size_of"_s); - keyword_lengthof = l->intern("length_of"_s); - keyword_alignof = l->intern("align_of"_s); keyword_true = l->intern("true"_s); keyword_default = l->intern("default"_s); keyword_break = l->intern("break"_s); @@ -245,6 +242,9 @@ lex_init(Allocator *token_string_arena, Allocator *map_allocator, Lexer *l){ l->interns.first_keyword = keyword_struct.str; l->interns.last_keyword = keyword_enum.str; + intern_sizeof = l->intern("size_of"_s); + intern_lengthof = l->intern("length_of"_s); + intern_alignof = l->intern("align_of"_s); intern_foreign = intern_string(&l->interns, "foreign"_s); intern_strict = intern_string(&l->interns, "strict"_s); intern_void = intern_string(&l->interns, "void"_s); diff --git a/core_parsing.cpp b/core_parsing.cpp index f6c1879..f776c42 100644 --- a/core_parsing.cpp +++ b/core_parsing.cpp @@ -566,25 +566,7 @@ parse_expr(S64 min_bp){ left = ast_bool(token, 1); else if(token->intern_val == keyword_false) left = ast_bool(token, 0); - else if(token->intern_val == keyword_sizeof){ - token_expect(TK_OpenParen); - Ast_Expr *expr = parse_expr(); - token_expect(TK_CloseParen); - left = ast_sizeof(token, expr); - } - else if(token->intern_val == keyword_alignof){ - token_expect(TK_OpenParen); - Ast_Expr *expr = parse_expr(); - token_expect(TK_CloseParen); - left = ast_alignof(token, expr); - } - else if(token->intern_val == keyword_lengthof){ - token_expect(TK_OpenParen); - Ast_Expr *expr = parse_expr(); - token_expect(TK_CloseParen); - left = ast_len(token, expr); - } - else compiler_error(token, "Unexpected keyword: [%s], expected keyword [cast]", token->intern_val.str); + else compiler_error(token, "Unexpected keyword: [%s]", token->intern_val.str); }break; case TK_OpenParen: { diff --git a/core_typechecking.cpp b/core_typechecking.cpp index 7f8cad9..67fff2f 100644 --- a/core_typechecking.cpp +++ b/core_typechecking.cpp @@ -989,6 +989,26 @@ resolve_field_access(Ast_Expr *node, Ast_Scope *context){ return resolve_field_access(next, ((Ast_Decl *)type->ast)->scope); } +function Ast_Expr * +unpack_ast_call_expr_for_builtin(Ast_Call *call){ + if(call->exprs.len != 1) { + compiler_error(call->pos, "Expected exactly 1 argument inside a builtin function call got instead %d", (int)call->exprs.len); + } + return call->exprs[0]->item; +} + +function bool +expr_atom_is_equal_intern(Ast_Expr *expr, Intern_String intern){ + assert(expr->kind == AST_IDENT || expr->kind == AST_BINARY); + if(expr->kind == AST_IDENT){ + Ast_Atom *atom = (Ast_Atom *)expr; + if(atom->intern_val == intern) { + return true; + } + } + return false; +} + function Operand resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ if(!ast && is_flag_set(flags, AST_CAN_BE_NULL)) return {}; @@ -1202,127 +1222,136 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ BREAK(); } - CASE(ALIGN_OF, Builtin){ - Operand name = resolve_expr(node->expr, inherit_flag(flags, AST_CANT_BE_NULL)); - if(!name.is_const) compiler_error(node->pos, "align_of requires a constant value"); - Ast_Type *type = name.type == type_type ? name.type_val : name.type; - Value v = value_int(type->align); - rewrite_into_const(node, Ast_Builtin, v); - return operand_const_rvalue(v); - BREAK(); - } - - CASE(SIZE_OF, Builtin){ - Operand name = resolve_expr(node->expr, inherit_flag(flags, AST_CANT_BE_NULL)); - if(!name.is_const) compiler_error(node->pos, "size_of requires a constant value"); - Ast_Type *type = name.type == type_type ? name.type_val : name.type; - Value v = value_int(type->size); - rewrite_into_const(node, Ast_Builtin, v); - return operand_const_rvalue(v); - BREAK(); - } - - CASE(LENGTH_OF, Builtin){ - Operand name = resolve_expr(node->expr, inherit_flag(flags, AST_CANT_BE_NULL)); - node->resolved_type = type_s64; - if(is_array(name.type)){ - Value value = value_int(name.type->arr.size); - rewrite_into_const(node, Ast_Builtin, value); - return operand_const_rvalue(value); - } - else if(name.type->kind == TYPE_UNTYPED_STRING){ - Value value = value_int(name.intern_val.len); - rewrite_into_const(node, Ast_Builtin, value); - return operand_const_rvalue(value); - } - else if(is_array(name.type) || is_slice(name.type) || is_string(name.type)){ - return operand_rvalue(type_s64); - } - else compiler_error(node->pos, "Can't get length of type %Q", typestring(name.type)); - BREAK(); - } - CASE(CALL, Call){ - Operand name = resolve_expr(node->name, inherit_flag(flags, AST_CANT_BE_NULL)); - if(name.type->kind != TYPE_LAMBDA) - compiler_error(node->pos, "Calling %Q which is not a [Lambda]", typestring(name.type)); + if(expr_atom_is_equal_intern(node->name, intern_sizeof)){ + Ast_Expr *expr = unpack_ast_call_expr_for_builtin(node); - Scratch scratch; - Array items = {scratch}; - S64 was_name_indexed = false; - S64 default_iter = 0; - - Ast_Lambda *lambda = (Ast_Lambda *)name.type->ast; - For_Named(lambda->args, lambda_arg){ - assert(lambda_arg->type); - - Ast_Call_Item *item = 0; - For(node->exprs){ - assert(!is_flag_set(it->call_flags, CALL_INDEX)); - if(is_flag_set(it->call_flags, CALL_NAME)){ - Ast_Atom *name = it->name; - assert(name->kind == AST_IDENT); - was_name_indexed = true; - if(name->intern_val.str == lambda_arg->name.str) - item = it; - } - else if(node->exprs.get_index(&it) == default_iter){ - default_iter++; - item = it; - } - else if(node->exprs.get_index(&it) > default_iter){ - compiler_error(it->pos, "Positional argument after named argument"); - } - - if(item) break; + Operand name = resolve_expr(expr, inherit_flag(flags, AST_CANT_BE_NULL)); + if(!name.is_const){ + compiler_error(node->pos, "size_of requires a constant value"); } - if(item){ - set_flag(item->call_flags, CALL_INCLUDED); - Operand expr = resolve_expr(item->item, AST_CANT_BE_NULL, lambda_arg->type); - if(is_flag_set(lambda_arg->flags, AST_ANY_VARGS)){ - make_sure_value_is_compatible_with_type(item->pos, &expr, lambda_arg->type->base, TYPE_AND_EXPR_REQUIRED); - item->resolved_type = expr.type; + Ast_Type *type = name.type == type_type ? name.type_val : name.type; + Value v = value_int(type->size); + rewrite_into_const(node, Ast_Builtin, v); + return operand_const_rvalue(v); + } + + else if(expr_atom_is_equal_intern(node->name, intern_lengthof)){ + Ast_Expr *expr = unpack_ast_call_expr_for_builtin(node); + + Operand name = resolve_expr(expr, inherit_flag(flags, AST_CANT_BE_NULL)); + node->kind = AST_LENGTH_OF; + node->resolved_type = type_s64; + if(is_array(name.type)){ + Value value = value_int(name.type->arr.size); + rewrite_into_const(node, Ast_Builtin, value); + return operand_const_rvalue(value); + } + else if(name.type->kind == TYPE_UNTYPED_STRING){ + Value value = value_int(name.intern_val.len); + rewrite_into_const(node, Ast_Builtin, value); + return operand_const_rvalue(value); + } + else if(is_array(name.type) || is_slice(name.type) || is_string(name.type)){ + return operand_rvalue(type_s64); + } + else compiler_error(node->pos, "Can't get length of type %Q", typestring(name.type)); + } + + else if(expr_atom_is_equal_intern(node->name, intern_alignof)){ + Ast_Expr *expr = unpack_ast_call_expr_for_builtin(node); + Operand name = resolve_expr(expr, inherit_flag(flags, AST_CANT_BE_NULL)); + if(!name.is_const) compiler_error(node->pos, "align_of requires a constant value"); + Ast_Type *type = name.type == type_type ? name.type_val : name.type; + Value v = value_int(type->align); + rewrite_into_const(node, Ast_Builtin, v); + return operand_const_rvalue(v); + } + + else { + Operand name = resolve_expr(node->name, inherit_flag(flags, AST_CANT_BE_NULL)); + if(name.type->kind != TYPE_LAMBDA) + compiler_error(node->pos, "Calling %Q which is not a [Lambda]", typestring(name.type)); + + Scratch scratch; + Array items = {scratch}; + S64 was_name_indexed = false; + S64 default_iter = 0; + + Ast_Lambda *lambda = (Ast_Lambda *)name.type->ast; + For_Named(lambda->args, lambda_arg){ + assert(lambda_arg->type); + + Ast_Call_Item *item = 0; + For(node->exprs){ + assert(!is_flag_set(it->call_flags, CALL_INDEX)); + if(is_flag_set(it->call_flags, CALL_NAME)){ + Ast_Atom *name = it->name; + assert(name->kind == AST_IDENT); + was_name_indexed = true; + if(name->intern_val.str == lambda_arg->name.str) + item = it; + } + else if(node->exprs.get_index(&it) == default_iter){ + default_iter++; + item = it; + } + else if(node->exprs.get_index(&it) > default_iter){ + compiler_error(it->pos, "Positional argument after named argument"); + } + + if(item) break; + } + + if(item){ + set_flag(item->call_flags, CALL_INCLUDED); + Operand expr = resolve_expr(item->item, AST_CANT_BE_NULL, lambda_arg->type); + if(is_flag_set(lambda_arg->flags, AST_ANY_VARGS)){ + make_sure_value_is_compatible_with_type(item->pos, &expr, lambda_arg->type->base, TYPE_AND_EXPR_REQUIRED); + item->resolved_type = expr.type; + } + + else{ + make_sure_value_is_compatible_with_type(item->pos, &expr, lambda_arg->type, TYPE_AND_EXPR_REQUIRED); + item->resolved_type = lambda_arg->type; + } + + try_propagating_resolved_type_to_untyped_literals(item->item, item->resolved_type); + item->resolved_index = lambda->args.get_index(&lambda_arg); + items.add(item); } else{ - make_sure_value_is_compatible_with_type(item->pos, &expr, lambda_arg->type, TYPE_AND_EXPR_REQUIRED); - item->resolved_type = lambda_arg->type; + if(!lambda_arg->expr) + compiler_error(lambda_arg->pos, "Required value: %Q in lambda call was not passed", lambda_arg->name); + + // @note: default values are typechecked when they get resolved + Ast_Call_Item *call_item = ast_call_item(lambda_arg->expr->pos, 0, 0, lambda_arg->expr); + call_item->resolved_type = lambda_arg->expr->resolved_type; + call_item->resolved_index = lambda->args.get_index(&lambda_arg); + set_flag(call_item->call_flags, CALL_INCLUDED); + items.add(call_item); } - try_propagating_resolved_type_to_untyped_literals(item->item, item->resolved_type); - item->resolved_index = lambda->args.get_index(&lambda_arg); - items.add(item); } - else{ - if(!lambda_arg->expr) - compiler_error(lambda_arg->pos, "Required value: %Q in lambda call was not passed", lambda_arg->name); + node->exprs = items.tight_copy(pctx->perm); + node->resolved_type = name.type->func.ret; - // @note: default values are typechecked when they get resolved - Ast_Call_Item *call_item = ast_call_item(lambda_arg->expr->pos, 0, 0, lambda_arg->expr); - call_item->resolved_type = lambda_arg->expr->resolved_type; - call_item->resolved_index = lambda->args.get_index(&lambda_arg); - set_flag(call_item->call_flags, CALL_INCLUDED); - items.add(call_item); + // @note: check if all arguments are included and cleanup + For(node->exprs){ + if(!is_flag_set(it->call_flags, CALL_INCLUDED)) + compiler_error(it->pos, "Unknown argument to a function call, couldn't match it with any of the declared arguments"); + else unset_flag(it->call_flags, CALL_INCLUDED); } + + return operand_rvalue(name.type->func.ret); + // + // CALL End + // } - - node->exprs = items.tight_copy(pctx->perm); - node->resolved_type = name.type->func.ret; - - // @note: check if all arguments are included and cleanup - For(node->exprs){ - if(!is_flag_set(it->call_flags, CALL_INCLUDED)) - compiler_error(it->pos, "Unknown argument to a function call, couldn't match it with any of the declared arguments"); - else unset_flag(it->call_flags, CALL_INCLUDED); - } - - return operand_rvalue(name.type->func.ret); - // - // CALL End - // BREAK(); }