diff --git a/ccodegen.cpp b/ccodegen.cpp index a2113f0..c231e34 100644 --- a/ccodegen.cpp +++ b/ccodegen.cpp @@ -273,6 +273,13 @@ gen_expr(Ast_Expr *ast, Ast_Type *type_of_var){ } CASE(VALUE, Atom){ + if(is_any(type_of_var)){ + gen("(Any){&"); + gen("("); gen_simple_decl(node->type); gen("){"); gen_value(node->value); gen("}"); + gen(", %d}", node->type->type_id); + return true; + } + B32 written = gen_value(node->value); if(!written) { gen("%Q", node->value.intern_val); diff --git a/programs/any.kl b/programs/any.kl index 96607c2..86eabf3 100644 --- a/programs/any.kl +++ b/programs/any.kl @@ -1,9 +1,23 @@ main :: (argc: int, argv: **char): int - test_arrays() test_any() + test_arrays() test_type() +test_array_any :: (any: Any, array_of_any: ..) + for array_of_any + pass + +test_any :: () + some_int_value := 10 + thing: Any = some_int_value + other_any: Any = thing + imp_any := thing + assert(thing.type != Any) + any_array := []Any{some_int_value, thing} + for any_array + assert(it.type == S64) + test_arrays :: () array1 := []S64{1,2,3,4,5} array2: []S64 = {0,9,8} @@ -17,16 +31,7 @@ test_arrays :: () for array2;; *it = 0 for i := 0, i < length_of(array1), i+=1;; assert(0 == array1[i]) -test_any :: () - some_int_value := 10 - thing: Any = some_int_value - other_any: Any = thing - imp_any := thing - assert(thing.type != Any) - any_array := []Any{some_int_value, thing} - for any_array - assert(it.type == S64) - + test_array_any(10, 20, 30) Some_Struct :: struct thing: int diff --git a/typechecking.cpp b/typechecking.cpp index 2e297bf..6032fec 100644 --- a/typechecking.cpp +++ b/typechecking.cpp @@ -326,7 +326,7 @@ eval_unary(Token *pos, Token_Kind op, Operand *operand){ } function void -try_converting_untyped_to_typed(Operand *op){ +try_converting_untyped_to_typed(Value *op){ if(is_untyped(op->type)){ switch(op->type->kind){ case TYPE_UNTYPED_INT: op->type = type_s64; break; @@ -338,6 +338,11 @@ try_converting_untyped_to_typed(Operand *op){ } } +function void +try_converting_untyped_to_typed(Operand *op){ + try_converting_untyped_to_typed(&op->value); +} + FLAG32(Typecheck_Flag){ TYPE_AND_EXPR_REQUIRED = 0, TYPE_CAN_BE_NULL = 1, @@ -653,11 +658,24 @@ 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); - make_sure_value_is_compatible_with_type(it->pos, &default_value, type, EXPR_CAN_BE_NULL); - it->type = type; - args.add(type); + if(is_flag_set(it->flags, AST_ANY_VARGS)){ + if(it->expr) + compiler_error(it->pos, "Internal compiler error: Default value for .. multiple arguments should be null"); + if(it->typespec) + compiler_error(it->pos, "Internal compiler error: Typespec for .. multiple arguments should be null"); + + it->type = type_slice(type_any, it); + } + + + else { + Ast_Type *type = resolve_typespec(it->typespec, AST_CANT_BE_NULL); + Operand default_value = resolve_expr(it->expr, AST_CAN_BE_NULL, type); + make_sure_value_is_compatible_with_type(it->pos, &default_value, type, EXPR_CAN_BE_NULL); + it->type = type; + } + + args.add(it->type); } return type_lambda(lambda, ret, args); @@ -890,8 +908,13 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ CASE(VALUE, Atom){ // @todo: More propagation of const char to sub values - if(compound_context && is_string(node->value.type) && is_string(compound_context)){ - node->value.type = compound_context; + if(compound_context){ + if(is_string(node->value.type) && is_string(compound_context)){ + node->value.type = compound_context; + } + if(is_any(compound_context)){ + try_converting_untyped_to_typed(&node->value); + } } return operand_const_rvalue(node->value); BREAK(); @@ -1131,21 +1154,30 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ if(item){ set_flag(item->call_flags, CALL_INCLUDED); Operand expr = resolve_expr(item->item, AST_CANT_BE_NULL, lambda_arg->type); - make_sure_value_is_compatible_with_type(item->pos, &expr, lambda_arg->type, TYPE_AND_EXPR_REQUIRED); - item->resolved_type = 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; + } + 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); + // @note: default values are typechecked when they get resolved - if(lambda_arg->expr){ - 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); - } - else compiler_error(lambda_arg->pos, "Required value in lambda call was not passed"); + 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); } }