Implemented C variadic arguments
This commit is contained in:
@@ -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()
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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);
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
@@ -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,
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -468,9 +468,14 @@ parse_parameter_list(Arena *arena) {
|
||||
Array<Ast_Decl *> 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);
|
||||
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
|
||||
Reference in New Issue
Block a user