Add multi-pointer types [^]T

This commit is contained in:
gingerBill
2021-08-21 23:10:21 +01:00
parent 01a888fced
commit 6a77fc4cdd
10 changed files with 286 additions and 50 deletions
+67 -15
View File
@@ -592,10 +592,25 @@ i64 check_distance_between_types(CheckerContext *c, Operand *operand, Type *type
#if 1 #if 1
// TODO(bill): Should I allow this implicit conversion at all?!
// rawptr <- ^T // rawptr <- ^T
if (are_types_identical(type, t_rawptr) && is_type_pointer(src)) { if (are_types_identical(type, t_rawptr) && is_type_pointer(src)) {
return 5; return 5;
}
// rawptr <- [^]T
if (are_types_identical(type, t_rawptr) && is_type_multi_pointer(src)) {
return 5;
}
// ^T <- [^]T
if (is_type_pointer(dst) && is_type_multi_pointer(src)) {
if (are_types_identical(dst->Pointer.elem, src->MultiPointer.elem)) {
return 4;
}
}
// [^]T <- ^T
if (is_type_multi_pointer(dst) && is_type_pointer(src)) {
if (are_types_identical(dst->MultiPointer.elem, src->Pointer.elem)) {
return 4;
}
} }
#endif #endif
@@ -2392,6 +2407,15 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
if (is_type_pointer(src) && is_type_pointer(dst)) { if (is_type_pointer(src) && is_type_pointer(dst)) {
return true; return true;
} }
if (is_type_multi_pointer(src) && is_type_multi_pointer(dst)) {
return true;
}
if (is_type_multi_pointer(src) && is_type_pointer(dst)) {
return true;
}
if (is_type_pointer(src) && is_type_multi_pointer(dst)) {
return true;
}
// uintptr <-> pointer // uintptr <-> pointer
if (is_type_uintptr(src) && is_type_pointer(dst)) { if (is_type_uintptr(src) && is_type_pointer(dst)) {
@@ -2400,16 +2424,18 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
if (is_type_pointer(src) && is_type_uintptr(dst)) { if (is_type_pointer(src) && is_type_uintptr(dst)) {
return true; return true;
} }
if (is_type_uintptr(src) && is_type_multi_pointer(dst)) {
return true;
}
if (is_type_multi_pointer(src) && is_type_uintptr(dst)) {
return true;
}
// []byte/[]u8 <-> string (not cstring) // []byte/[]u8 <-> string (not cstring)
if (is_type_u8_slice(src) && (is_type_string(dst) && !is_type_cstring(dst))) { if (is_type_u8_slice(src) && (is_type_string(dst) && !is_type_cstring(dst))) {
return true; return true;
} }
if ((is_type_string(src) && !is_type_cstring(src)) && is_type_u8_slice(dst)) {
// if (is_type_typed(src)) {
// return true;
// }
}
// cstring -> string // cstring -> string
if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) { if (are_types_identical(src, t_cstring) && are_types_identical(dst, t_string)) {
if (operand->mode != Addressing_Constant) { if (operand->mode != Addressing_Constant) {
@@ -2421,6 +2447,10 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
if (are_types_identical(src, t_cstring) && is_type_u8_ptr(dst)) { if (are_types_identical(src, t_cstring) && is_type_u8_ptr(dst)) {
return !is_constant; return !is_constant;
} }
// cstring -> [^]u8
if (are_types_identical(src, t_cstring) && is_type_u8_multi_ptr(dst)) {
return !is_constant;
}
// cstring -> rawptr // cstring -> rawptr
if (are_types_identical(src, t_cstring) && is_type_rawptr(dst)) { if (are_types_identical(src, t_cstring) && is_type_rawptr(dst)) {
return !is_constant; return !is_constant;
@@ -2430,6 +2460,10 @@ bool check_is_castable_to(CheckerContext *c, Operand *operand, Type *y) {
if (is_type_u8_ptr(src) && are_types_identical(dst, t_cstring)) { if (is_type_u8_ptr(src) && are_types_identical(dst, t_cstring)) {
return !is_constant; return !is_constant;
} }
// [^]u8 -> cstring
if (is_type_u8_multi_ptr(src) && are_types_identical(dst, t_cstring)) {
return !is_constant;
}
// rawptr -> cstring // rawptr -> cstring
if (is_type_rawptr(src) && are_types_identical(dst, t_cstring)) { if (is_type_rawptr(src) && are_types_identical(dst, t_cstring)) {
return !is_constant; return !is_constant;
@@ -3328,7 +3362,7 @@ void convert_to_typed(CheckerContext *c, Operand *operand, Type *target_type) {
operand->type = target_type; operand->type = target_type;
} }
bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64 max_count, i64 *value, Type *type_hint=nullptr) { bool check_index_value(CheckerContext *c, Type *main_type, bool open_range, Ast *index_value, i64 max_count, i64 *value, Type *type_hint=nullptr) {
Operand operand = {Addressing_Invalid}; Operand operand = {Addressing_Invalid};
check_expr_with_type_hint(c, &operand, index_value, type_hint); check_expr_with_type_hint(c, &operand, index_value, type_hint);
if (operand.mode == Addressing_Invalid) { if (operand.mode == Addressing_Invalid) {
@@ -3367,7 +3401,7 @@ bool check_index_value(CheckerContext *c, bool open_range, Ast *index_value, i64
if (operand.mode == Addressing_Constant && if (operand.mode == Addressing_Constant &&
(c->state_flags & StateFlag_no_bounds_check) == 0) { (c->state_flags & StateFlag_no_bounds_check) == 0) {
BigInt i = exact_value_to_integer(operand.value).value_integer; BigInt i = exact_value_to_integer(operand.value).value_integer;
if (i.sign && !is_type_enum(index_type)) { if (i.sign && !is_type_enum(index_type) && !is_type_multi_pointer(main_type)) {
gbString expr_str = expr_to_string(operand.expr); gbString expr_str = expr_to_string(operand.expr);
error(operand.expr, "Index '%s' cannot be a negative value", expr_str); error(operand.expr, "Index '%s' cannot be a negative value", expr_str);
gb_string_free(expr_str); gb_string_free(expr_str);
@@ -6102,6 +6136,13 @@ bool check_set_index_data(Operand *o, Type *t, bool indirection, i64 *max_count,
} }
break; break;
case Type_MultiPointer:
o->type = t->MultiPointer.elem;
if (o->mode != Addressing_Constant) {
o->mode = Addressing_Variable;
}
return true;
case Type_Array: case Type_Array:
*max_count = t->Array.count; *max_count = t->Array.count;
if (indirection) { if (indirection) {
@@ -8133,13 +8174,9 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
} }
i64 index = 0; i64 index = 0;
bool ok = check_index_value(c, false, ie->index, max_count, &index, index_type_hint); bool ok = check_index_value(c, t, false, ie->index, max_count, &index, index_type_hint);
if (is_const) { if (is_const) {
if (index < 0) { if (index < 0) {
if (max_count < 0) {
}
gbString str = expr_to_string(o->expr); gbString str = expr_to_string(o->expr);
error(o->expr, "Cannot index a constant '%s'", str); error(o->expr, "Cannot index a constant '%s'", str);
error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n"); error_line("\tSuggestion: store the constant into a variable in order to index it with a variable index\n");
@@ -8206,6 +8243,11 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
o->type = alloc_type_slice(t->Array.elem); o->type = alloc_type_slice(t->Array.elem);
break; break;
case Type_MultiPointer:
valid = true;
o->type = type_deref(o->type);
break;
case Type_Slice: case Type_Slice:
valid = true; valid = true;
o->type = type_deref(o->type); o->type = type_deref(o->type);
@@ -8262,7 +8304,7 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
capacity = max_count; capacity = max_count;
} }
i64 j = 0; i64 j = 0;
if (check_index_value(c, true, nodes[i], capacity, &j)) { if (check_index_value(c, t, true, nodes[i], capacity, &j)) {
index = j; index = j;
} }
@@ -8291,6 +8333,16 @@ ExprKind check_expr_base_internal(CheckerContext *c, Operand *o, Ast *node, Type
} }
} }
if (t->kind == Type_MultiPointer && se->high != nullptr) {
/*
x[:] -> [^]T
x[i:] -> [^]T
x[:n] -> []T
x[i:n] -> []T
*/
o->type = alloc_type_slice(t->MultiPointer.elem);
}
o->mode = Addressing_Value; o->mode = Addressing_Value;
if (is_type_string(t) && max_count >= 0) { if (is_type_string(t) && max_count >= 0) {
+6
View File
@@ -2525,6 +2525,12 @@ bool check_type_internal(CheckerContext *ctx, Ast *e, Type **type, Type *named_t
return true; return true;
case_end; case_end;
case_ast_node(pt, MultiPointerType, e);
*type = alloc_type_multi_pointer(check_type(ctx, pt->type));
set_base_type(named_type, *type);
return true;
case_end;
case_ast_node(rt, RelativeType, e); case_ast_node(rt, RelativeType, e);
GB_ASSERT(rt->tag->kind == Ast_CallExpr); GB_ASSERT(rt->tag->kind == Ast_CallExpr);
ast_node(ce, CallExpr, rt->tag); ast_node(ce, CallExpr, rt->tag);
+11
View File
@@ -1545,6 +1545,10 @@ void add_type_info_type_internal(CheckerContext *c, Type *t) {
add_type_info_type_internal(c, bt->Pointer.elem); add_type_info_type_internal(c, bt->Pointer.elem);
break; break;
case Type_MultiPointer:
add_type_info_type_internal(c, bt->MultiPointer.elem);
break;
case Type_Array: case Type_Array:
add_type_info_type_internal(c, bt->Array.elem); add_type_info_type_internal(c, bt->Array.elem);
add_type_info_type_internal(c, alloc_type_pointer(bt->Array.elem)); add_type_info_type_internal(c, alloc_type_pointer(bt->Array.elem));
@@ -1754,6 +1758,10 @@ void add_min_dep_type_info(Checker *c, Type *t) {
add_min_dep_type_info(c, bt->Pointer.elem); add_min_dep_type_info(c, bt->Pointer.elem);
break; break;
case Type_MultiPointer:
add_min_dep_type_info(c, bt->MultiPointer.elem);
break;
case Type_Array: case Type_Array:
add_min_dep_type_info(c, bt->Array.elem); add_min_dep_type_info(c, bt->Array.elem);
add_min_dep_type_info(c, alloc_type_pointer(bt->Array.elem)); add_min_dep_type_info(c, alloc_type_pointer(bt->Array.elem));
@@ -1993,6 +2001,7 @@ void generate_minimum_dependency_set(Checker *c, Entity *start) {
str_lit("bounds_check_error"), str_lit("bounds_check_error"),
str_lit("slice_expr_error_hi"), str_lit("slice_expr_error_hi"),
str_lit("slice_expr_error_lo_hi"), str_lit("slice_expr_error_lo_hi"),
str_lit("multi_pointer_slice_expr_error"),
}; };
for (isize i = 0; i < gb_count_of(bounds_check_entities); i++) { for (isize i = 0; i < gb_count_of(bounds_check_entities); i++) {
force_add_dependency_entity(c, c->info.runtime_package->scope, bounds_check_entities[i]); force_add_dependency_entity(c, c->info.runtime_package->scope, bounds_check_entities[i]);
@@ -2400,6 +2409,7 @@ void init_core_type_info(Checker *c) {
t_type_info_any = find_core_type(c, str_lit("Type_Info_Any")); t_type_info_any = find_core_type(c, str_lit("Type_Info_Any"));
t_type_info_typeid = find_core_type(c, str_lit("Type_Info_Type_Id")); t_type_info_typeid = find_core_type(c, str_lit("Type_Info_Type_Id"));
t_type_info_pointer = find_core_type(c, str_lit("Type_Info_Pointer")); t_type_info_pointer = find_core_type(c, str_lit("Type_Info_Pointer"));
t_type_info_multi_pointer = find_core_type(c, str_lit("Type_Info_Multi_Pointer"));
t_type_info_procedure = find_core_type(c, str_lit("Type_Info_Procedure")); t_type_info_procedure = find_core_type(c, str_lit("Type_Info_Procedure"));
t_type_info_array = find_core_type(c, str_lit("Type_Info_Array")); t_type_info_array = find_core_type(c, str_lit("Type_Info_Array"));
t_type_info_enumerated_array = find_core_type(c, str_lit("Type_Info_Enumerated_Array")); t_type_info_enumerated_array = find_core_type(c, str_lit("Type_Info_Enumerated_Array"));
@@ -2426,6 +2436,7 @@ void init_core_type_info(Checker *c) {
t_type_info_any_ptr = alloc_type_pointer(t_type_info_any); t_type_info_any_ptr = alloc_type_pointer(t_type_info_any);
t_type_info_typeid_ptr = alloc_type_pointer(t_type_info_typeid); t_type_info_typeid_ptr = alloc_type_pointer(t_type_info_typeid);
t_type_info_pointer_ptr = alloc_type_pointer(t_type_info_pointer); t_type_info_pointer_ptr = alloc_type_pointer(t_type_info_pointer);
t_type_info_multi_pointer_ptr = alloc_type_pointer(t_type_info_multi_pointer);
t_type_info_procedure_ptr = alloc_type_pointer(t_type_info_procedure); t_type_info_procedure_ptr = alloc_type_pointer(t_type_info_procedure);
t_type_info_array_ptr = alloc_type_pointer(t_type_info_array); t_type_info_array_ptr = alloc_type_pointer(t_type_info_array);
t_type_info_enumerated_array_ptr = alloc_type_pointer(t_type_info_enumerated_array); t_type_info_enumerated_array_ptr = alloc_type_pointer(t_type_info_enumerated_array);
+55
View File
@@ -1274,6 +1274,25 @@ lbValue lb_emit_conv(lbProcedure *p, lbValue value, Type *t) {
res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), ""); res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), "");
return res; return res;
} }
if (is_type_multi_pointer(src) && is_type_pointer(dst)) {
lbValue res = {};
res.type = t;
res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), "");
return res;
}
if (is_type_pointer(src) && is_type_multi_pointer(dst)) {
lbValue res = {};
res.type = t;
res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), "");
return res;
}
if (is_type_multi_pointer(src) && is_type_multi_pointer(dst)) {
lbValue res = {};
res.type = t;
res.value = LLVMBuildPointerCast(p->builder, value.value, lb_type(m, t), "");
return res;
}
@@ -2838,6 +2857,21 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
return lb_addr(v); return lb_addr(v);
} }
case Type_MultiPointer: {
lbValue multi_ptr = {};
multi_ptr = lb_build_expr(p, ie->expr);
if (deref) {
multi_ptr = lb_emit_load(p, multi_ptr);
}
lbValue index = lb_build_expr(p, ie->index);
lbValue v = {};
LLVMValueRef indices[1] = {index.value};
v.value = LLVMBuildGEP(p->builder, multi_ptr.value, indices, 1, "");
v.type = t;
return lb_addr(v);
}
case Type_RelativeSlice: { case Type_RelativeSlice: {
lbAddr slice_addr = {}; lbAddr slice_addr = {};
if (deref) { if (deref) {
@@ -2952,6 +2986,27 @@ lbAddr lb_build_addr(lbProcedure *p, Ast *expr) {
return slice; return slice;
} }
case Type_MultiPointer: {
lbAddr res = lb_add_local_generated(p, type_of_expr(expr), false);
if (se->high == nullptr) {
lbValue offset = base;
LLVMValueRef indices[1] = {low.value};
offset.value = LLVMBuildGEP(p->builder, offset.value, indices, 1, "");
lb_addr_store(p, res, offset);
} else {
lb_emit_multi_pointer_slice_bounds_check(p, se->open, low, high);
LLVMValueRef indices[1] = {low.value};
LLVMValueRef ptr = LLVMBuildGEP(p->builder, base.value, indices, 1, "");
LLVMValueRef len = LLVMBuildSub(p->builder, high.value, low.value, "");
// TODO(bill): bounds_check for negative length
LLVMValueRef gep0 = lb_emit_struct_ep(p, res.addr, 0).value;
LLVMValueRef gep1 = lb_emit_struct_ep(p, res.addr, 1).value;
LLVMBuildStore(p->builder, ptr, gep0);
LLVMBuildStore(p->builder, len, gep1);
}
return res;
}
case Type_Array: { case Type_Array: {
Type *slice_type = alloc_type_slice(type->Array.elem); Type *slice_type = alloc_type_slice(type->Array.elem);
+35
View File
@@ -420,6 +420,31 @@ void lb_emit_bounds_check(lbProcedure *p, Token token, lbValue index, lbValue le
lb_emit_runtime_call(p, "bounds_check_error", args); lb_emit_runtime_call(p, "bounds_check_error", args);
} }
void lb_emit_multi_pointer_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValue high) {
if (build_context.no_bounds_check) {
return;
}
if ((p->state_flags & StateFlag_no_bounds_check) != 0) {
return;
}
low = lb_emit_conv(p, low, t_int);
high = lb_emit_conv(p, high, t_int);
lbValue file = lb_find_or_add_entity_string(p->module, get_file_path_string(token.pos.file_id));
lbValue line = lb_const_int(p->module, t_i32, token.pos.line);
lbValue column = lb_const_int(p->module, t_i32, token.pos.column);
auto args = array_make<lbValue>(permanent_allocator(), 5);
args[0] = file;
args[1] = line;
args[2] = column;
args[3] = low;
args[4] = high;
lb_emit_runtime_call(p, "multi_pointer_slice_expr_error", args);
}
void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValue high, lbValue len, bool lower_value_used) { void lb_emit_slice_bounds_check(lbProcedure *p, Token token, lbValue low, lbValue high, lbValue len, bool lower_value_used) {
if (build_context.no_bounds_check) { if (build_context.no_bounds_check) {
return; return;
@@ -810,6 +835,13 @@ LLVMTypeRef llvm_addr_type(lbValue addr_val) {
lbValue lb_emit_load(lbProcedure *p, lbValue value) { lbValue lb_emit_load(lbProcedure *p, lbValue value) {
GB_ASSERT(value.value != nullptr); GB_ASSERT(value.value != nullptr);
if (is_type_multi_pointer(value.type)) {
Type *vt = base_type(value.type);
GB_ASSERT(vt->kind == Type_MultiPointer);
Type *t = vt->MultiPointer.elem;
LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, "");
return lbValue{v, t};
}
GB_ASSERT(is_type_pointer(value.type)); GB_ASSERT(is_type_pointer(value.type));
Type *t = type_deref(value.type); Type *t = type_deref(value.type);
LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, ""); LLVMValueRef v = LLVMBuildLoad2(p->builder, llvm_addr_type(value), value.value, "");
@@ -1568,6 +1600,9 @@ LLVMTypeRef lb_type_internal(lbModule *m, Type *type) {
case Type_Pointer: case Type_Pointer:
return LLVMPointerType(lb_type(m, type->Pointer.elem), 0); return LLVMPointerType(lb_type(m, type->Pointer.elem), 0);
case Type_MultiPointer:
return LLVMPointerType(lb_type(m, type->Pointer.elem), 0);
case Type_Array: { case Type_Array: {
m->internal_type_level -= 1; m->internal_type_level -= 1;
LLVMTypeRef t = LLVMArrayType(lb_type(m, type->Array.elem), cast(unsigned)type->Array.count); LLVMTypeRef t = LLVMArrayType(lb_type(m, type->Array.elem), cast(unsigned)type->Array.count);
+15
View File
@@ -40,6 +40,7 @@ lbValue lb_typeid(lbModule *m, Type *type) {
if (flags & BasicFlag_Rune) kind = Typeid_Rune; if (flags & BasicFlag_Rune) kind = Typeid_Rune;
} break; } break;
case Type_Pointer: kind = Typeid_Pointer; break; case Type_Pointer: kind = Typeid_Pointer; break;
case Type_MultiPointer: kind = Typeid_Multi_Pointer; break;
case Type_Array: kind = Typeid_Array; break; case Type_Array: kind = Typeid_Array; break;
case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break; case Type_EnumeratedArray: kind = Typeid_Enumerated_Array; break;
case Type_Slice: kind = Typeid_Slice; break; case Type_Slice: kind = Typeid_Slice; break;
@@ -396,6 +397,20 @@ void lb_setup_type_info_data(lbProcedure *p) { // NOTE(bill): Setup type_info da
lb_emit_store(p, tag, res); lb_emit_store(p, tag, res);
break; break;
} }
case Type_MultiPointer: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_multi_pointer_ptr);
lbValue gep = lb_get_type_info_ptr(m, t->MultiPointer.elem);
LLVMValueRef vals[1] = {
gep.value,
};
lbValue res = {};
res.type = type_deref(tag.type);
res.value = llvm_const_named_struct(lb_type(m, res.type), vals, gb_count_of(vals));
lb_emit_store(p, tag, res);
break;
}
case Type_Array: { case Type_Array: {
tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_array_ptr); tag = lb_const_ptr_cast(m, variant_ptr, t_type_info_array_ptr);
i64 ez = type_size_of(t->Array.elem); i64 ez = type_size_of(t->Array.elem);
+14 -2
View File
@@ -337,6 +337,9 @@ Ast *clone_ast(Ast *node) {
case Ast_PointerType: case Ast_PointerType:
n->PointerType.type = clone_ast(n->PointerType.type); n->PointerType.type = clone_ast(n->PointerType.type);
break; break;
case Ast_MultiPointerType:
n->MultiPointerType.type = clone_ast(n->MultiPointerType.type);
break;
case Ast_ArrayType: case Ast_ArrayType:
n->ArrayType.count = clone_ast(n->ArrayType.count); n->ArrayType.count = clone_ast(n->ArrayType.count);
n->ArrayType.elem = clone_ast(n->ArrayType.elem); n->ArrayType.elem = clone_ast(n->ArrayType.elem);
@@ -985,7 +988,12 @@ Ast *ast_pointer_type(AstFile *f, Token token, Ast *type) {
result->PointerType.type = type; result->PointerType.type = type;
return result; return result;
} }
Ast *ast_multi_pointer_type(AstFile *f, Token token, Ast *type) {
Ast *result = alloc_ast_node(f, Ast_MultiPointerType);
result->MultiPointerType.token = token;
result->MultiPointerType.type = type;
return result;
}
Ast *ast_array_type(AstFile *f, Token token, Ast *count, Ast *elem) { Ast *ast_array_type(AstFile *f, Token token, Ast *count, Ast *elem) {
Ast *result = alloc_ast_node(f, Ast_ArrayType); Ast *result = alloc_ast_node(f, Ast_ArrayType);
result->ArrayType.token = token; result->ArrayType.token = token;
@@ -2317,7 +2325,11 @@ Ast *parse_operand(AstFile *f, bool lhs) {
case Token_OpenBracket: { case Token_OpenBracket: {
Token token = expect_token(f, Token_OpenBracket); Token token = expect_token(f, Token_OpenBracket);
Ast *count_expr = nullptr; Ast *count_expr = nullptr;
if (f->curr_token.kind == Token_Question) { if (f->curr_token.kind == Token_Pointer) {
expect_token(f, Token_Pointer);
expect_token(f, Token_CloseBracket);
return ast_multi_pointer_type(f, token, parse_type(f));
} else if (f->curr_token.kind == Token_Question) {
count_expr = ast_unary_expr(f, expect_token(f, Token_Question), nullptr); count_expr = ast_unary_expr(f, expect_token(f, Token_Question), nullptr);
} else if (allow_token(f, Token_dynamic)) { } else if (allow_token(f, Token_dynamic)) {
expect_token(f, Token_CloseBracket); expect_token(f, Token_CloseBracket);
+4
View File
@@ -604,6 +604,10 @@ AST_KIND(_TypeBegin, "", bool) \
Ast *tag; \ Ast *tag; \
Ast *type; \ Ast *type; \
}) \ }) \
AST_KIND(MultiPointerType, "multi pointer type", struct { \
Token token; \
Ast *type; \
}) \
AST_KIND(ArrayType, "array type", struct { \ AST_KIND(ArrayType, "array type", struct { \
Token token; \ Token token; \
Ast *count; \ Ast *count; \
+2
View File
@@ -95,6 +95,7 @@ Token ast_token(Ast *node) {
case Ast_ProcType: return node->ProcType.token; case Ast_ProcType: return node->ProcType.token;
case Ast_RelativeType: return ast_token(node->RelativeType.tag); case Ast_RelativeType: return ast_token(node->RelativeType.tag);
case Ast_PointerType: return node->PointerType.token; case Ast_PointerType: return node->PointerType.token;
case Ast_MultiPointerType: return node->MultiPointerType.token;
case Ast_ArrayType: return node->ArrayType.token; case Ast_ArrayType: return node->ArrayType.token;
case Ast_DynamicArrayType: return node->DynamicArrayType.token; case Ast_DynamicArrayType: return node->DynamicArrayType.token;
case Ast_StructType: return node->StructType.token; case Ast_StructType: return node->StructType.token;
@@ -312,6 +313,7 @@ Token ast_end_token(Ast *node) {
case Ast_RelativeType: case Ast_RelativeType:
return ast_end_token(node->RelativeType.type); return ast_end_token(node->RelativeType.type);
case Ast_PointerType: return ast_end_token(node->PointerType.type); case Ast_PointerType: return ast_end_token(node->PointerType.type);
case Ast_MultiPointerType: return ast_end_token(node->MultiPointerType.type);
case Ast_ArrayType: return ast_end_token(node->ArrayType.elem); case Ast_ArrayType: return ast_end_token(node->ArrayType.elem);
case Ast_DynamicArrayType: return ast_end_token(node->DynamicArrayType.elem); case Ast_DynamicArrayType: return ast_end_token(node->DynamicArrayType.elem);
case Ast_StructType: case Ast_StructType:
+77 -33
View File
@@ -192,47 +192,48 @@ struct TypeProc {
bool optional_ok; bool optional_ok;
}; };
#define TYPE_KINDS \ #define TYPE_KINDS \
TYPE_KIND(Basic, BasicType) \ TYPE_KIND(Basic, BasicType) \
TYPE_KIND(Named, struct { \ TYPE_KIND(Named, struct { \
String name; \ String name; \
Type * base; \ Type * base; \
Entity *type_name; /* Entity_TypeName */ \ Entity *type_name; /* Entity_TypeName */ \
}) \ }) \
TYPE_KIND(Generic, struct { \ TYPE_KIND(Generic, struct { \
i64 id; \ i64 id; \
String name; \ String name; \
Type * specialized; \ Type * specialized; \
Scope * scope; \ Scope * scope; \
Entity *entity; \ Entity *entity; \
}) \ }) \
TYPE_KIND(Pointer, struct { Type *elem; }) \ TYPE_KIND(Pointer, struct { Type *elem; }) \
TYPE_KIND(Array, struct { \ TYPE_KIND(MultiPointer, struct { Type *elem; }) \
TYPE_KIND(Array, struct { \
Type *elem; \ Type *elem; \
i64 count; \ i64 count; \
Type *generic_count; \ Type *generic_count; \
}) \ }) \
TYPE_KIND(EnumeratedArray, struct { \ TYPE_KIND(EnumeratedArray, struct { \
Type *elem; \ Type *elem; \
Type *index; \ Type *index; \
ExactValue min_value; \ ExactValue min_value; \
ExactValue max_value; \ ExactValue max_value; \
i64 count; \ i64 count; \
TokenKind op; \ TokenKind op; \
}) \ }) \
TYPE_KIND(Slice, struct { Type *elem; }) \ TYPE_KIND(Slice, struct { Type *elem; }) \
TYPE_KIND(DynamicArray, struct { Type *elem; }) \ TYPE_KIND(DynamicArray, struct { Type *elem; }) \
TYPE_KIND(Map, struct { \ TYPE_KIND(Map, struct { \
Type *key; \ Type *key; \
Type *value; \ Type *value; \
Type *entry_type; \ Type *entry_type; \
Type *generated_struct_type; \ Type *generated_struct_type; \
Type *internal_type; \ Type *internal_type; \
Type *lookup_result_type; \ Type *lookup_result_type; \
}) \ }) \
TYPE_KIND(Struct, TypeStruct) \ TYPE_KIND(Struct, TypeStruct) \
TYPE_KIND(Union, TypeUnion) \ TYPE_KIND(Union, TypeUnion) \
TYPE_KIND(Enum, struct { \ TYPE_KIND(Enum, struct { \
Array<Entity *> fields; \ Array<Entity *> fields; \
Ast *node; \ Ast *node; \
Scope * scope; \ Scope * scope; \
@@ -242,31 +243,31 @@ struct TypeProc {
ExactValue max_value; \ ExactValue max_value; \
isize min_value_index; \ isize min_value_index; \
isize max_value_index; \ isize max_value_index; \
}) \ }) \
TYPE_KIND(Tuple, struct { \ TYPE_KIND(Tuple, struct { \
Array<Entity *> variables; /* Entity_Variable */ \ Array<Entity *> variables; /* Entity_Variable */ \
Array<i64> offsets; \ Array<i64> offsets; \
bool are_offsets_being_processed; \ bool are_offsets_being_processed; \
bool are_offsets_set; \ bool are_offsets_set; \
bool is_packed; \ bool is_packed; \
}) \ }) \
TYPE_KIND(Proc, TypeProc) \ TYPE_KIND(Proc, TypeProc) \
TYPE_KIND(BitSet, struct { \ TYPE_KIND(BitSet, struct { \
Type *elem; \ Type *elem; \
Type *underlying; \ Type *underlying; \
i64 lower; \ i64 lower; \
i64 upper; \ i64 upper; \
Ast * node; \ Ast * node; \
}) \ }) \
TYPE_KIND(SimdVector, struct { \ TYPE_KIND(SimdVector, struct { \
i64 count; \ i64 count; \
Type *elem; \ Type *elem; \
}) \ }) \
TYPE_KIND(RelativePointer, struct { \ TYPE_KIND(RelativePointer, struct { \
Type *pointer_type; \ Type *pointer_type; \
Type *base_integer; \ Type *base_integer; \
}) \ }) \
TYPE_KIND(RelativeSlice, struct { \ TYPE_KIND(RelativeSlice, struct { \
Type *slice_type; \ Type *slice_type; \
Type *base_integer; \ Type *base_integer; \
}) })
@@ -325,6 +326,7 @@ enum Typeid_Kind : u8 {
Typeid_Any, Typeid_Any,
Typeid_Type_Id, Typeid_Type_Id,
Typeid_Pointer, Typeid_Pointer,
Typeid_Multi_Pointer,
Typeid_Procedure, Typeid_Procedure,
Typeid_Array, Typeid_Array,
Typeid_Enumerated_Array, Typeid_Enumerated_Array,
@@ -605,6 +607,7 @@ gb_global Type *t_type_info_typeid = nullptr;
gb_global Type *t_type_info_string = nullptr; gb_global Type *t_type_info_string = nullptr;
gb_global Type *t_type_info_boolean = nullptr; gb_global Type *t_type_info_boolean = nullptr;
gb_global Type *t_type_info_pointer = nullptr; gb_global Type *t_type_info_pointer = nullptr;
gb_global Type *t_type_info_multi_pointer = nullptr;
gb_global Type *t_type_info_procedure = nullptr; gb_global Type *t_type_info_procedure = nullptr;
gb_global Type *t_type_info_array = nullptr; gb_global Type *t_type_info_array = nullptr;
gb_global Type *t_type_info_enumerated_array = nullptr; gb_global Type *t_type_info_enumerated_array = nullptr;
@@ -631,6 +634,7 @@ gb_global Type *t_type_info_typeid_ptr = nullptr;
gb_global Type *t_type_info_string_ptr = nullptr; gb_global Type *t_type_info_string_ptr = nullptr;
gb_global Type *t_type_info_boolean_ptr = nullptr; gb_global Type *t_type_info_boolean_ptr = nullptr;
gb_global Type *t_type_info_pointer_ptr = nullptr; gb_global Type *t_type_info_pointer_ptr = nullptr;
gb_global Type *t_type_info_multi_pointer_ptr = nullptr;
gb_global Type *t_type_info_procedure_ptr = nullptr; gb_global Type *t_type_info_procedure_ptr = nullptr;
gb_global Type *t_type_info_array_ptr = nullptr; gb_global Type *t_type_info_array_ptr = nullptr;
gb_global Type *t_type_info_enumerated_array_ptr = nullptr; gb_global Type *t_type_info_enumerated_array_ptr = nullptr;
@@ -779,6 +783,12 @@ Type *alloc_type_pointer(Type *elem) {
return t; return t;
} }
Type *alloc_type_multi_pointer(Type *elem) {
Type *t = alloc_type(Type_MultiPointer);
t->MultiPointer.elem = elem;
return t;
}
Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = nullptr) { Type *alloc_type_array(Type *elem, i64 count, Type *generic_count = nullptr) {
if (generic_count != nullptr) { if (generic_count != nullptr) {
Type *t = alloc_type(Type_Array); Type *t = alloc_type(Type_Array);
@@ -948,10 +958,10 @@ Type *type_deref(Type *t) {
if (bt == nullptr) { if (bt == nullptr) {
return nullptr; return nullptr;
} }
if (bt != nullptr && bt->kind == Type_Pointer) { if (bt->kind == Type_Pointer) {
return bt->Pointer.elem; return bt->Pointer.elem;
} }
if (bt != nullptr && bt->kind == Type_RelativePointer) { if (bt->kind == Type_RelativePointer) {
return type_deref(bt->RelativePointer.pointer_type); return type_deref(bt->RelativePointer.pointer_type);
} }
} }
@@ -1084,6 +1094,8 @@ bool is_type_ordered(Type *t) {
return (t->Basic.flags & BasicFlag_Ordered) != 0; return (t->Basic.flags & BasicFlag_Ordered) != 0;
case Type_Pointer: case Type_Pointer:
return true; return true;
case Type_MultiPointer:
return true;
} }
return false; return false;
} }
@@ -1157,6 +1169,10 @@ bool is_type_pointer(Type *t) {
} }
return t->kind == Type_Pointer; return t->kind == Type_Pointer;
} }
bool is_type_multi_pointer(Type *t) {
t = base_type(t);
return t->kind == Type_MultiPointer;
}
bool is_type_tuple(Type *t) { bool is_type_tuple(Type *t) {
t = base_type(t); t = base_type(t);
return t->kind == Type_Tuple; return t->kind == Type_Tuple;
@@ -1259,6 +1275,13 @@ bool is_type_u8_ptr(Type *t) {
} }
return false; return false;
} }
bool is_type_u8_multi_ptr(Type *t) {
t = base_type(t);
if (t->kind == Type_MultiPointer) {
return is_type_u8(t->Slice.elem);
}
return false;
}
bool is_type_rune_array(Type *t) { bool is_type_rune_array(Type *t) {
t = base_type(t); t = base_type(t);
if (t->kind == Type_Array) { if (t->kind == Type_Array) {
@@ -1348,7 +1371,8 @@ bool is_type_union_maybe_pointer(Type *t) {
t = base_type(t); t = base_type(t);
if (t->kind == Type_Union && t->Union.maybe) { if (t->kind == Type_Union && t->Union.maybe) {
if (t->Union.variants.count == 1) { if (t->Union.variants.count == 1) {
return is_type_pointer(t->Union.variants[0]); Type *v = t->Union.variants[0];
return is_type_pointer(v) || is_type_multi_pointer(v);
} }
} }
return false; return false;
@@ -1360,7 +1384,7 @@ bool is_type_union_maybe_pointer_original_alignment(Type *t) {
if (t->kind == Type_Union && t->Union.maybe) { if (t->kind == Type_Union && t->Union.maybe) {
if (t->Union.variants.count == 1) { if (t->Union.variants.count == 1) {
Type *v = t->Union.variants[0]; Type *v = t->Union.variants[0];
if (is_type_pointer(v)) { if (is_type_pointer(v) || is_type_multi_pointer(v)) {
return type_align_of(v) == type_align_of(t); return type_align_of(v) == type_align_of(t);
} }
} }
@@ -1614,6 +1638,8 @@ bool is_type_indexable(Type *t) {
case Type_DynamicArray: case Type_DynamicArray:
case Type_Map: case Type_Map:
return true; return true;
case Type_MultiPointer:
return true;
case Type_EnumeratedArray: case Type_EnumeratedArray:
return true; return true;
case Type_RelativeSlice: case Type_RelativeSlice:
@@ -1836,6 +1862,7 @@ bool type_has_nil(Type *t) {
case Type_Slice: case Type_Slice:
case Type_Proc: case Type_Proc:
case Type_Pointer: case Type_Pointer:
case Type_MultiPointer:
case Type_DynamicArray: case Type_DynamicArray:
case Type_Map: case Type_Map:
return true; return true;
@@ -1890,6 +1917,8 @@ bool is_type_comparable(Type *t) {
return true; return true;
case Type_Pointer: case Type_Pointer:
return true; return true;
case Type_MultiPointer:
return true;
case Type_Enum: case Type_Enum:
return is_type_comparable(core_type(t)); return is_type_comparable(core_type(t));
case Type_EnumeratedArray: case Type_EnumeratedArray:
@@ -1955,6 +1984,7 @@ bool is_type_simple_compare(Type *t) {
return false; return false;
case Type_Pointer: case Type_Pointer:
case Type_MultiPointer:
case Type_Proc: case Type_Proc:
case Type_BitSet: case Type_BitSet:
return true; return true;
@@ -2157,6 +2187,12 @@ bool are_types_identical(Type *x, Type *y) {
} }
break; break;
case Type_MultiPointer:
if (y->kind == Type_MultiPointer) {
return are_types_identical(x->MultiPointer.elem, y->MultiPointer.elem);
}
break;
case Type_Named: case Type_Named:
if (y->kind == Type_Named) { if (y->kind == Type_Named) {
return x->Named.type_name == y->Named.type_name; return x->Named.type_name == y->Named.type_name;
@@ -3139,6 +3175,9 @@ i64 type_size_of_internal(Type *t, TypePath *path) {
case Type_Pointer: case Type_Pointer:
return build_context.word_size; return build_context.word_size;
case Type_MultiPointer:
return build_context.word_size;
case Type_Array: { case Type_Array: {
i64 count, align, size, alignment; i64 count, align, size, alignment;
count = t->Array.count; count = t->Array.count;
@@ -3509,6 +3548,11 @@ gbString write_type_to_string(gbString str, Type *type) {
str = write_type_to_string(str, type->Pointer.elem); str = write_type_to_string(str, type->Pointer.elem);
break; break;
case Type_MultiPointer:
str = gb_string_appendc(str, "[^]");
str = write_type_to_string(str, type->Pointer.elem);
break;
case Type_EnumeratedArray: case Type_EnumeratedArray:
str = gb_string_append_rune(str, '['); str = gb_string_append_rune(str, '[');
str = write_type_to_string(str, type->EnumeratedArray.index); str = write_type_to_string(str, type->EnumeratedArray.index);