From 8c4975db356b68b6566523b004ea073931e2cdbe Mon Sep 17 00:00:00 2001 From: Krzosa Karol Date: Fri, 14 Apr 2023 22:22:34 +0200 Subject: [PATCH] Implemented C variadic arguments --- build/examples/game2d.core | 2 ++ core_codegen_c_language.cpp | 5 ++++ core_compiler.cpp | 3 ++ core_compiler.h | 3 ++ core_compiler_interface.hpp | 2 ++ core_lexing.cpp | 2 +- core_parsing.cpp | 11 +++++-- core_typechecking.cpp | 58 ++++++++++++++++++++++++++++++------- core_types.cpp | 3 ++ 9 files changed, 74 insertions(+), 15 deletions(-) diff --git a/build/examples/game2d.core b/build/examples/game2d.core index 3cf4e02..e79440f 100644 --- a/build/examples/game2d.core +++ b/build/examples/game2d.core @@ -68,6 +68,8 @@ main :: (): int guys: Array(Guy) Add(&guys, {pos = {100, 100}}) + Memes(32, 32, 32, 32.42, "ASD") + InitWindow(1280, 720, "Testing") SetTargetFPS(60) for !WindowShouldClose() diff --git a/core_codegen_c_language.cpp b/core_codegen_c_language.cpp index 94a5449..9d27c2c 100644 --- a/core_codegen_c_language.cpp +++ b/core_codegen_c_language.cpp @@ -339,6 +339,10 @@ gen_lambda(Intern_String name, Ast_Lambda *lambda, B32 generate_block = true) { gen("("); if (lambda->args.len == 0) gen("void"); For(lambda->args) { + if (it->name == pctx->intern("..."_s)) { + gen("..."); + continue; + } gen_var(it, DONT_EMIT_VALUE, true); if (&it != (lambda->args.end() - 1)) gen(", "); @@ -935,6 +939,7 @@ compile_to_c_code() { global_indent++; For2(pctx->all_types, t) { if (t->kind == TYPE_POLYMORPH) continue; + // if (t->kind == TYPE_VARGS) continue; genln("{/*%Q*/", typestring(t)); global_indent += 1; diff --git a/core_compiler.cpp b/core_compiler.cpp index d65ae68..4c0a0ee 100644 --- a/core_compiler.cpp +++ b/core_compiler.cpp @@ -156,6 +156,9 @@ for i in meta.token_simple_expr: pctx->untyped_int = &pctx->type__untyped_int; pctx->untyped_float = &pctx->type__untyped_float; + pctx->type__vargs = {TYPE_VARGS}; + pctx->type_vargs = &pctx->type__vargs; + pctx->type_pointer_to_char = type_pointer(pctx->type_char); pctx->type_pointer_to_void = type_pointer(pctx->type_void); diff --git a/core_compiler.h b/core_compiler.h index 867bfc1..8655509 100644 --- a/core_compiler.h +++ b/core_compiler.h @@ -185,6 +185,9 @@ print(f"Ast_Operator_Info op_info_table[{size}];") Ast_Type *untyped_int = &type__untyped_int; Ast_Type *untyped_float = &type__untyped_float; + Ast_Type type__vargs; + Ast_Type *type_vargs = &type__vargs; + Intern_String intern(String string) { assert(string.len > 0); return intern_string(&interns, string); diff --git a/core_compiler_interface.hpp b/core_compiler_interface.hpp index 0d9943f..3dcbe9f 100644 --- a/core_compiler_interface.hpp +++ b/core_compiler_interface.hpp @@ -212,6 +212,7 @@ enum Ast_Type_Kind { TYPE_COMPLETING, TYPE_INCOMPLETE, TYPE_POLYMORPH, + TYPE_VARGS, TYPE_UNTYPED_BOOL, // FIRST_TYPED_NUMERIC, FIRST_NUMERIC TYPE_UNTYPED_INT, @@ -321,6 +322,7 @@ enum Ast_Kind : uint32_t { AST_LENGTH_OF, AST_ALIGN_OF, AST_TYPE_OF, + AST_VARGS_LAMBDA_PARAM, AST_SWITCH, AST_SWITCH_CASE, diff --git a/core_lexing.cpp b/core_lexing.cpp index 4373646..cf28301 100644 --- a/core_lexing.cpp +++ b/core_lexing.cpp @@ -431,7 +431,7 @@ lex__stream(Core_Ctx *lexer) { case '.': { if (lexc(s) == '.') { lex_advance(s); - if (lexci(s, 1) == '.') { + if (lexc(s) == '.') { lex_advance(s); t.kind = TK_ThreeDots; } diff --git a/core_parsing.cpp b/core_parsing.cpp index 4e95e8e..5f8c146 100644 --- a/core_parsing.cpp +++ b/core_parsing.cpp @@ -468,9 +468,14 @@ parse_parameter_list(Arena *arena) { Array params = {arena}; if (!token_is(TK_CloseParen)) { for (;;) { - Token *name = token_get(); - if (name->kind == TK_Identifier || name->kind == TK_Polymorph) { - token_next(); + Token *name = token_next(); + if (name->kind == TK_ThreeDots) { + Ast_Decl *param = ast_new(Ast_Decl, AST_VARGS_LAMBDA_PARAM, name, AST_DECL); + param->name = pctx->intern("..."_s); + params.add(param); + break; + } + else if (name->kind == TK_Identifier || name->kind == TK_Polymorph) { token_expect(TK_Colon); Ast_Decl *param = ast_new(Ast_Decl, AST_VAR, name, AST_DECL); diff --git a/core_typechecking.cpp b/core_typechecking.cpp index 47f2d32..e0ff3fa 100644 --- a/core_typechecking.cpp +++ b/core_typechecking.cpp @@ -401,7 +401,7 @@ make_sure_value_is_compatible_with_type(Token *pos, Operand *expr, Ast_Type *typ return; } - if (!type) { + if (!type || type->kind == TYPE_VARGS) { assert(is_flag_set(debug_flag, TYPE_CAN_BE_NULL)); assert(expr->type); try_converting_untyped_to_default_type(expr); @@ -914,12 +914,21 @@ resolve_lambda_type(Ast_Lambda *lambda) { } For(lambda->args) { - Ast_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL); - Operand default_value = resolve_expr(it->expr, AST_CAN_BE_NULL, type, 0); - make_sure_value_is_compatible_with_type(it->pos, &default_value, type, EXPR_CAN_BE_NULL); + if (it->name == pctx->intern("..."_s)) { + it->type = pctx->type_vargs; - it->type = type; - try_propagating_resolved_type_to_untyped_literals(it->expr, it->type); + For2(lambda->args, arg) { + if (arg->expr != 0) compiler_error(arg->pos, "Default values in variadic functions are not allowed"); + } + } + else { + Ast_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL); + Operand default_value = resolve_expr(it->expr, AST_CAN_BE_NULL, type, 0); + make_sure_value_is_compatible_with_type(it->pos, &default_value, type, EXPR_CAN_BE_NULL); + + it->type = type; + try_propagating_resolved_type_to_untyped_literals(it->expr, it->type); + } args.add(it->type); } @@ -1639,6 +1648,12 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_and_const_str Need to be careful!!! */ + For(node->exprs) { + if (is_flag_set(it->call_flags, CALL_INDEX)) { + compiler_error(it->pos, "Index inside a call is not allowed!"); + } + } + Scoped_Arena scratch(pctx->scratch); Ast_Lambda *lambda = name.resolved_decl->lambda; struct Match { @@ -1661,6 +1676,21 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_and_const_str For2(lambda->args, lambda_arg) { // assert(lambda_arg->type); // @todo: maybe add this check at the end + // @todo: Change inside resolve lambda, no default arguments allowed!!!!!! + if (lambda_arg->kind == AST_VARGS_LAMBDA_PARAM) { + For(node->exprs) { + if (is_flag_set(it->call_flags, CALL_NAME)) { + compiler_error(it->pos, "Variadic function doesnt allow for named arguments!"); + } + + S64 idx = node->exprs.get_index(it); + if (idx >= default_iter) { + matches.add({lambda_arg, it}); + } + } + break; + } + Ast_Call_Item *item = 0; For(node->exprs) { S64 it_index = node->exprs.get_index(it); @@ -1737,11 +1767,17 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_and_const_str Ast_Call_Item *item = it.call_arg; Ast_Decl *lambda_arg = it.lambda_arg; if (lambda_arg->flags & AST_IDENT_POLYMORPH) continue; - Operand expr = resolve_expr(item->item, AST_CANT_BE_NULL, lambda_arg->type, field_access_scope); - - 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->kind == AST_VARGS_LAMBDA_PARAM) { + Operand expr = resolve_expr(item->item, AST_CANT_BE_NULL, lambda_arg->type, field_access_scope); + try_converting_untyped_to_default_type(&expr); + if (expr.type == pctx->type_string) expr.type = pctx->type_pointer_to_char; + item->resolved_type = expr.type; + } + else { + Operand expr = resolve_expr(item->item, AST_CANT_BE_NULL, lambda_arg->type, field_access_scope); + 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); items.add(item); } diff --git a/core_types.cpp b/core_types.cpp index e160fc9..4342243 100644 --- a/core_types.cpp +++ b/core_types.cpp @@ -346,6 +346,9 @@ typename_base(String_Builder *sb, Ast_Type *type) { sb->addf("%Q", name); break; } + case TYPE_VARGS: { + sb->addf("..."); + } break; case TYPE_UNTYPED_BOOL: sb->addf("Untyped_Bool"); break; case TYPE_UNTYPED_INT: sb->addf("Untyped_Int"); break; case TYPE_UNTYPED_FLOAT: sb->addf("Untyped_Float"); break;