Adding len() builtin and TYPE_SLICE
This commit is contained in:
@@ -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;
|
||||
|
||||
8
main.kl
8
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)
|
||||
|
||||
10
tests.cpp
10
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<Ast_Type*> 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<Ast_Type*> 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);
|
||||
|
||||
@@ -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));
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
7
types.h
7
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<Ast_Resolved_Member> 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 "<Unknown_Type>";
|
||||
@@ -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;}
|
||||
|
||||
Reference in New Issue
Block a user