diff --git a/ccodegen.cpp b/ccodegen.cpp index e9fe0a2..922fa73 100644 --- a/ccodegen.cpp +++ b/ccodegen.cpp @@ -60,7 +60,7 @@ gen_simple_decl_postfix(Ast_Type *ast, bool scope_names){ case TYPE_POINTER: gen_simple_decl_postfix(ast->base, scope_names); break; case TYPE_ARRAY: gen("["); - if(ast->arr.size != ARRAY_SIZE_INFERRED) + if(ast->arr.size != ARRAY_SIZE_SLICE) gen("%d", (int)ast->arr.size); gen("]"); gen_simple_decl_postfix(ast->arr.base, scope_names); break; diff --git a/main.kl b/main.kl index c94d8bf..1822c5f 100644 --- a/main.kl +++ b/main.kl @@ -1,8 +1,16 @@ #import "base.kl" +test_arrays :: () + array := [4]int{1,2,3,4} + item := array[0] + length := len(array) + slice: []int = array + slice_length := len(slice) + main :: (argc: int, argv: **char): int memory := reserve(size = 10000) handle := Windows.GetStdHandle(Windows.STD_OUTPUT_HANDLE) + string: *char = "hello world" Windows.WriteConsoleA(handle, string->*void, 11, 0, 0) diff --git a/tests.cpp b/tests.cpp index 817da83..8a4dc7e 100644 --- a/tests.cpp +++ b/tests.cpp @@ -5,9 +5,9 @@ test_types(){ parse_init(&ctx, scratch, scratch); pctx = &ctx; - Ast_Type *array_type1 = type_array(type_s64, 1, 32); - Ast_Type *array_type2 = type_array(type_s64, 1, 32); - Ast_Type *array_type3 = type_array(type_s64, 1, 48); + Ast_Type *array_type1 = type_array(type_s64, 32); + Ast_Type *array_type2 = type_array(type_s64, 32); + Ast_Type *array_type3 = type_array(type_s64, 48); assert(array_type1 == array_type2); assert(array_type2 != array_type3); Ast_Type *pointer_type1 = type_pointer(type_s64); @@ -19,14 +19,14 @@ test_types(){ assert(pointer_type3 == pointer_type4); Array types = {scratch}; - types.add(type_array(type_s64, 1, 32)); + types.add(type_array(type_s64, 32)); Ast_Type *func_type1 = type_lambda(0, types[0], types); Ast_Type *func_type2 = type_lambda(0, types[0], types); assert(func_type1 == func_type2); Array types2 = {scratch}; { - types2.add(type_array(type_s64, 1, 32)); + types2.add(type_array(type_s64, 32)); types2.add(type_s64); } types.add(type_s64); diff --git a/typechecking.cpp b/typechecking.cpp index e76799b..2ca04ca 100644 --- a/typechecking.cpp +++ b/typechecking.cpp @@ -288,8 +288,8 @@ make_sure_value_is_compatible_with_type(Token *pos, Operand *expr, Ast_Type *typ else if(is_untyped(expr->type)){ expr->value = convert_untyped_to_typed(pos, expr->value, type); } - else if(is_array(type) && type->arr.size == ARRAY_SIZE_INFERRED){ - if(type->arr.inferred_size_hash == expr->type->arr.inferred_size_hash) + else if(is_slice(type) && is_array(expr->type)){ + if(type->arr.slice_hash == expr->type->arr.slice_hash) expr->type = type; } @@ -322,8 +322,8 @@ _search_for_decl(Ast_Scope *scope, Intern_String name, S32 level){ For(scope->implicit_imports){ Ast_Decl *result = 0; - if(scope->kind == AST_MODULE && level > 1); - else result = _search_for_decl(it, name, level+1); + if(scope->kind != AST_MODULE || level < 2) + result = _search_for_decl(it, name, level+1); if(result) return result; } @@ -507,7 +507,6 @@ try_resolving_lambda_scope(Operand *op, Ast_Lambda *lambda, Ast_Type *lambda_typ *op = operand_lambda(lambda_type); } else if(is_flag_set(lambda->flags, AST_FOREIGN)){ - // @todo: Add foreign *op = operand_lambda(lambda_type); } } @@ -692,7 +691,7 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ } CASE(VALUE, Atom){ - // @todo: More propagation of typed values to untyped values + // @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; } @@ -705,8 +704,13 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ Operand type = resolve_expr(node->base, AST_CANT_BE_NULL); Operand expr = require_const_int(node->expr, AST_CAN_BE_NULL); if(type.type != type_type) compiler_error(node->pos, "Prefix array operator is only allowed on types"); + if(node->expr){ + node->type = type_array(type.type_val, bigint_as_unsigned(&expr.big_int_val)); + } else{ + node->type = type_slice(type.type_val); + } + - node->type = type_array(type.type_val, node->expr ? 1 : 0, bigint_as_unsigned(&expr.big_int_val)); return operand_type(node->type); BREAK(); } @@ -835,6 +839,23 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){ } CASE(CALL, Call){ + // Handle builtin calls + if(node->name->kind == AST_IDENT){ + auto ident = (Ast_Atom *)node->name; + if(ident->intern_val == pctx->intern("len"_s)){ + if(node->exprs.len > 1) compiler_error(node->pos, "Expected 1 argument"); + Ast_Call_Item *arg = node->exprs[0]; + if(arg->name || arg->index) compiler_error(node->pos, "No named or indexed arguments expected"); + Operand op = resolve_expr(arg->item, AST_CANT_BE_NULL); + if(is_array(op.type)){ + Value val = value_int(op.type->arr.size); + rewrite_into_const(node, Ast_Call, val); + return operand_const_rvalue(val); + } else compiler_error(node->pos, "Invalid argument"); + } + } + + // Handle calls Operand name = resolve_expr(node->name, AST_CANT_BE_NULL); if(name.type->kind != TYPE_LAMBDA) compiler_error(node->pos, "Calling %s which is not a [Lambda]", docname(name.type)); diff --git a/typechecking.h b/typechecking.h index 52aaf8d..ba91589 100644 --- a/typechecking.h +++ b/typechecking.h @@ -134,11 +134,25 @@ type_pointer(Ast_Type *base){ } function Ast_Type * -type_array(Ast_Type *base, B32 size_present, S64 size){ - if(!size_present){ - size = ARRAY_SIZE_INFERRED; +type_slice(Ast_Type *base){ + U64 hash_base = hash_ptr(base); + U64 hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE)); + Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash); + if(result){ + assert(result->kind == TYPE_ARRAY); + assert(result->arr.base == base); + return result; } + struct Slice{void *p; S64 len;}; + result = type_new(pctx->perm, TYPE_SLICE, sizeof(Slice), alignof(Slice)); + result->arr.base = base; + result->arr.slice_hash = hash; + return result; +} + +function Ast_Type * +type_array(Ast_Type *base, S64 size){ U64 hash_base = hash_ptr(base); U64 hash = hash_mix(hash_base, hash_u64(size)); Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash); @@ -152,7 +166,7 @@ type_array(Ast_Type *base, B32 size_present, S64 size){ result = type_new(pctx->perm, TYPE_ARRAY, pointer_size, pointer_align); result->arr.base = base; result->arr.size = size; - result->arr.inferred_size_hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_INFERRED)); + result->arr.slice_hash = hash_mix(hash_base, hash_u64(ARRAY_SIZE_SLICE)); map_insert(&pctx->type_map, hash, result); return result; } diff --git a/types.h b/types.h index 0557cfe..5461847 100644 --- a/types.h +++ b/types.h @@ -31,6 +31,7 @@ enum Ast_Type_Kind{ TYPE_UNION, TYPE_ENUM, TYPE_TYPE, + TYPE_SLICE, TYPE_UNTYPED_FIRST = TYPE_UNTYPED_BOOL, TYPE_UNTYPED_LAST = TYPE_UNTYPED_STRING, @@ -59,7 +60,7 @@ struct Ast_Resolved_Member{ B32 visited; }; -#define ARRAY_SIZE_INFERRED (-1) +#define ARRAY_SIZE_SLICE (-1) struct Ast_Type{ Ast_Type_Kind kind; SizeU size; @@ -76,7 +77,7 @@ struct Ast_Type{ // you still want to pass that array into // a function that expects an array of size "[]" // so we want also should check this - U64 inferred_size_hash; + U64 slice_hash; }arr; struct{ Array members; @@ -120,6 +121,7 @@ docname(Ast_Type *type){ case TYPE_UNION: return "[Union]"; case TYPE_ENUM: return "[Enum]"; case TYPE_TYPE: return "[Type]"; + case TYPE_SLICE: return "[Slice]"; invalid_default_case; } return ""; @@ -211,6 +213,7 @@ global Ast_Type *untyped_float = &type__untyped_float; force_inline B32 is_struct(Ast_Type *a){return a->kind == TYPE_STRUCT;} force_inline B32 is_lambda(Ast_Type *a){return a->kind == TYPE_LAMBDA;} force_inline B32 is_array(Ast_Type *a){return a->kind == TYPE_ARRAY;} +force_inline B32 is_slice(Ast_Type *a){return a->kind == TYPE_SLICE;} force_inline B32 is_enum(Ast_Type *a){return a->kind == TYPE_ENUM;} force_inline B32 is_pointer(Ast_Type *a){return a->kind == TYPE_POINTER;} force_inline B32 is_string(Ast_Type *a){return a->kind == TYPE_STRING || a->kind == TYPE_UNTYPED_STRING || a == type_pointer_to_char;}