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_POINTER: gen_simple_decl_postfix(ast->base, scope_names); break;
|
||||||
case TYPE_ARRAY:
|
case TYPE_ARRAY:
|
||||||
gen("[");
|
gen("[");
|
||||||
if(ast->arr.size != ARRAY_SIZE_INFERRED)
|
if(ast->arr.size != ARRAY_SIZE_SLICE)
|
||||||
gen("%d", (int)ast->arr.size);
|
gen("%d", (int)ast->arr.size);
|
||||||
gen("]");
|
gen("]");
|
||||||
gen_simple_decl_postfix(ast->arr.base, scope_names); break;
|
gen_simple_decl_postfix(ast->arr.base, scope_names); break;
|
||||||
|
|||||||
8
main.kl
8
main.kl
@@ -1,8 +1,16 @@
|
|||||||
#import "base.kl"
|
#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
|
main :: (argc: int, argv: **char): int
|
||||||
memory := reserve(size = 10000)
|
memory := reserve(size = 10000)
|
||||||
handle := Windows.GetStdHandle(Windows.STD_OUTPUT_HANDLE)
|
handle := Windows.GetStdHandle(Windows.STD_OUTPUT_HANDLE)
|
||||||
|
|
||||||
|
|
||||||
string: *char = "hello world"
|
string: *char = "hello world"
|
||||||
Windows.WriteConsoleA(handle, string->*void, 11, 0, 0)
|
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);
|
parse_init(&ctx, scratch, scratch);
|
||||||
pctx = &ctx;
|
pctx = &ctx;
|
||||||
|
|
||||||
Ast_Type *array_type1 = type_array(type_s64, 1, 32);
|
Ast_Type *array_type1 = type_array(type_s64, 32);
|
||||||
Ast_Type *array_type2 = type_array(type_s64, 1, 32);
|
Ast_Type *array_type2 = type_array(type_s64, 32);
|
||||||
Ast_Type *array_type3 = type_array(type_s64, 1, 48);
|
Ast_Type *array_type3 = type_array(type_s64, 48);
|
||||||
assert(array_type1 == array_type2);
|
assert(array_type1 == array_type2);
|
||||||
assert(array_type2 != array_type3);
|
assert(array_type2 != array_type3);
|
||||||
Ast_Type *pointer_type1 = type_pointer(type_s64);
|
Ast_Type *pointer_type1 = type_pointer(type_s64);
|
||||||
@@ -19,14 +19,14 @@ test_types(){
|
|||||||
assert(pointer_type3 == pointer_type4);
|
assert(pointer_type3 == pointer_type4);
|
||||||
|
|
||||||
Array<Ast_Type*> types = {scratch};
|
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_type1 = type_lambda(0, types[0], types);
|
||||||
Ast_Type *func_type2 = type_lambda(0, types[0], types);
|
Ast_Type *func_type2 = type_lambda(0, types[0], types);
|
||||||
assert(func_type1 == func_type2);
|
assert(func_type1 == func_type2);
|
||||||
|
|
||||||
Array<Ast_Type*> types2 = {scratch};
|
Array<Ast_Type*> types2 = {scratch};
|
||||||
{
|
{
|
||||||
types2.add(type_array(type_s64, 1, 32));
|
types2.add(type_array(type_s64, 32));
|
||||||
types2.add(type_s64);
|
types2.add(type_s64);
|
||||||
}
|
}
|
||||||
types.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)){
|
else if(is_untyped(expr->type)){
|
||||||
expr->value = convert_untyped_to_typed(pos, expr->value, type);
|
expr->value = convert_untyped_to_typed(pos, expr->value, type);
|
||||||
}
|
}
|
||||||
else if(is_array(type) && type->arr.size == ARRAY_SIZE_INFERRED){
|
else if(is_slice(type) && is_array(expr->type)){
|
||||||
if(type->arr.inferred_size_hash == expr->type->arr.inferred_size_hash)
|
if(type->arr.slice_hash == expr->type->arr.slice_hash)
|
||||||
expr->type = type;
|
expr->type = type;
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -322,8 +322,8 @@ _search_for_decl(Ast_Scope *scope, Intern_String name, S32 level){
|
|||||||
|
|
||||||
For(scope->implicit_imports){
|
For(scope->implicit_imports){
|
||||||
Ast_Decl *result = 0;
|
Ast_Decl *result = 0;
|
||||||
if(scope->kind == AST_MODULE && level > 1);
|
if(scope->kind != AST_MODULE || level < 2)
|
||||||
else result = _search_for_decl(it, name, level+1);
|
result = _search_for_decl(it, name, level+1);
|
||||||
if(result) return result;
|
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);
|
*op = operand_lambda(lambda_type);
|
||||||
}
|
}
|
||||||
else if(is_flag_set(lambda->flags, AST_FOREIGN)){
|
else if(is_flag_set(lambda->flags, AST_FOREIGN)){
|
||||||
// @todo: Add foreign
|
|
||||||
*op = operand_lambda(lambda_type);
|
*op = operand_lambda(lambda_type);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -692,7 +691,7 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){
|
|||||||
}
|
}
|
||||||
|
|
||||||
CASE(VALUE, Atom){
|
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)){
|
if(compound_context && is_string(node->value.type) && is_string(compound_context)){
|
||||||
node->value.type = 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 type = resolve_expr(node->base, AST_CANT_BE_NULL);
|
||||||
Operand expr = require_const_int(node->expr, AST_CAN_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(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);
|
return operand_type(node->type);
|
||||||
BREAK();
|
BREAK();
|
||||||
}
|
}
|
||||||
@@ -835,6 +839,23 @@ resolve_expr(Ast_Expr *ast, Resolve_Flag flags, Ast_Type *compound_context){
|
|||||||
}
|
}
|
||||||
|
|
||||||
CASE(CALL, Call){
|
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);
|
Operand name = resolve_expr(node->name, AST_CANT_BE_NULL);
|
||||||
if(name.type->kind != TYPE_LAMBDA)
|
if(name.type->kind != TYPE_LAMBDA)
|
||||||
compiler_error(node->pos, "Calling %s which is not a [Lambda]", docname(name.type));
|
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 *
|
function Ast_Type *
|
||||||
type_array(Ast_Type *base, B32 size_present, S64 size){
|
type_slice(Ast_Type *base){
|
||||||
if(!size_present){
|
U64 hash_base = hash_ptr(base);
|
||||||
size = ARRAY_SIZE_INFERRED;
|
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_base = hash_ptr(base);
|
||||||
U64 hash = hash_mix(hash_base, hash_u64(size));
|
U64 hash = hash_mix(hash_base, hash_u64(size));
|
||||||
Ast_Type *result = (Ast_Type *)map_get(&pctx->type_map, hash);
|
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 = type_new(pctx->perm, TYPE_ARRAY, pointer_size, pointer_align);
|
||||||
result->arr.base = base;
|
result->arr.base = base;
|
||||||
result->arr.size = size;
|
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);
|
map_insert(&pctx->type_map, hash, result);
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|||||||
7
types.h
7
types.h
@@ -31,6 +31,7 @@ enum Ast_Type_Kind{
|
|||||||
TYPE_UNION,
|
TYPE_UNION,
|
||||||
TYPE_ENUM,
|
TYPE_ENUM,
|
||||||
TYPE_TYPE,
|
TYPE_TYPE,
|
||||||
|
TYPE_SLICE,
|
||||||
|
|
||||||
TYPE_UNTYPED_FIRST = TYPE_UNTYPED_BOOL,
|
TYPE_UNTYPED_FIRST = TYPE_UNTYPED_BOOL,
|
||||||
TYPE_UNTYPED_LAST = TYPE_UNTYPED_STRING,
|
TYPE_UNTYPED_LAST = TYPE_UNTYPED_STRING,
|
||||||
@@ -59,7 +60,7 @@ struct Ast_Resolved_Member{
|
|||||||
B32 visited;
|
B32 visited;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define ARRAY_SIZE_INFERRED (-1)
|
#define ARRAY_SIZE_SLICE (-1)
|
||||||
struct Ast_Type{
|
struct Ast_Type{
|
||||||
Ast_Type_Kind kind;
|
Ast_Type_Kind kind;
|
||||||
SizeU size;
|
SizeU size;
|
||||||
@@ -76,7 +77,7 @@ struct Ast_Type{
|
|||||||
// you still want to pass that array into
|
// you still want to pass that array into
|
||||||
// a function that expects an array of size "[]"
|
// a function that expects an array of size "[]"
|
||||||
// so we want also should check this
|
// so we want also should check this
|
||||||
U64 inferred_size_hash;
|
U64 slice_hash;
|
||||||
}arr;
|
}arr;
|
||||||
struct{
|
struct{
|
||||||
Array<Ast_Resolved_Member> members;
|
Array<Ast_Resolved_Member> members;
|
||||||
@@ -120,6 +121,7 @@ docname(Ast_Type *type){
|
|||||||
case TYPE_UNION: return "[Union]";
|
case TYPE_UNION: return "[Union]";
|
||||||
case TYPE_ENUM: return "[Enum]";
|
case TYPE_ENUM: return "[Enum]";
|
||||||
case TYPE_TYPE: return "[Type]";
|
case TYPE_TYPE: return "[Type]";
|
||||||
|
case TYPE_SLICE: return "[Slice]";
|
||||||
invalid_default_case;
|
invalid_default_case;
|
||||||
}
|
}
|
||||||
return "<Unknown_Type>";
|
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_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_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_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_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_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;}
|
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