mirror of
https://github.com/Ed94/Odin.git
synced 2026-06-13 01:21:38 -07:00
down_cast
This commit is contained in:
+21
-9
@@ -9,20 +9,32 @@ main :: proc() {
|
||||
name: string
|
||||
}
|
||||
|
||||
Frog :: type struct {
|
||||
Amp :: type struct {
|
||||
using entity: Entity
|
||||
jump_height: f32
|
||||
}
|
||||
|
||||
f := Frog{}
|
||||
f.name = "ribbit"
|
||||
|
||||
print_name :: proc(using e: Entity) {
|
||||
print_string(name); nl()
|
||||
Frog :: type struct {
|
||||
using amp: Amp
|
||||
volume: f64
|
||||
}
|
||||
|
||||
print_name(f.entity)
|
||||
print_name(f)
|
||||
f := Frog{};
|
||||
f.name = "ribbit";
|
||||
f.jump_height = 1337;
|
||||
|
||||
e := ^f.entity;
|
||||
parent := e down_cast ^Frog;
|
||||
|
||||
print_name :: proc(using e: Entity, v: Vec3) {
|
||||
print_string(name); nl()
|
||||
print_int(v.x as int); nl()
|
||||
}
|
||||
|
||||
print_f32(f.jump_height); nl()
|
||||
print_f32(parent.jump_height); nl()
|
||||
|
||||
print_name(f.entity, Vec3{1, 2, 3})
|
||||
print_name(parent.entity, Vec3{3, 2, 1})
|
||||
|
||||
|
||||
}
|
||||
|
||||
+17
-17
@@ -27,23 +27,23 @@ GL_TEXTURE_MIN_FILTER :: 0x2801
|
||||
GL_TEXTURE_WRAP_S :: 0x2802
|
||||
GL_TEXTURE_WRAP_T :: 0x2803
|
||||
|
||||
glClear :: proc(mask: u32) #foreign
|
||||
glClearColor :: proc(r, g, b, a: f32) #foreign
|
||||
glBegin :: proc(mode: i32) #foreign
|
||||
glEnd :: proc() #foreign
|
||||
glColor3f :: proc(r, g, b: f32) #foreign
|
||||
glColor4f :: proc(r, g, b, a: f32) #foreign
|
||||
glVertex2f :: proc(x, y: f32) #foreign
|
||||
glVertex3f :: proc(x, y, z: f32) #foreign
|
||||
glTexCoord2f :: proc(u, v: f32) #foreign
|
||||
glLoadIdentity :: proc() #foreign
|
||||
glClear :: proc(mask: u32) #foreign
|
||||
glClearColor :: proc(r, g, b, a: f32) #foreign
|
||||
glBegin :: proc(mode: i32) #foreign
|
||||
glEnd :: proc() #foreign
|
||||
glColor3f :: proc(r, g, b: f32) #foreign
|
||||
glColor4f :: proc(r, g, b, a: f32) #foreign
|
||||
glVertex2f :: proc(x, y: f32) #foreign
|
||||
glVertex3f :: proc(x, y, z: f32) #foreign
|
||||
glTexCoord2f :: proc(u, v: f32) #foreign
|
||||
glLoadIdentity :: proc() #foreign
|
||||
glOrtho :: proc(left, right, bottom, top, near, far: f64) #foreign
|
||||
glBlendFunc :: proc(sfactor, dfactor: i32) #foreign
|
||||
glEnable :: proc(cap: i32) #foreign
|
||||
glDisable :: proc(cap: i32) #foreign
|
||||
glGenTextures :: proc(count: i32, result: ^u32) #foreign
|
||||
glTexParameteri :: proc(target, pname, param: i32) #foreign
|
||||
glTexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign
|
||||
glBindTexture :: proc(target: i32, texture: u32) #foreign
|
||||
glBlendFunc :: proc(sfactor, dfactor: i32) #foreign
|
||||
glEnable :: proc(cap: i32) #foreign
|
||||
glDisable :: proc(cap: i32) #foreign
|
||||
glGenTextures :: proc(count: i32, result: ^u32) #foreign
|
||||
glTexParameteri :: proc(target, pname, param: i32) #foreign
|
||||
glTexParameterf :: proc(target: i32, pname: i32, param: f32) #foreign
|
||||
glBindTexture :: proc(target: i32, texture: u32) #foreign
|
||||
glTexImage2D :: proc(target, level, internal_format, width, height, border, format, _type: i32, pixels: rawptr) #foreign
|
||||
|
||||
|
||||
+96
-123
@@ -1240,6 +1240,35 @@ b32 check_castable_to(Checker *c, Operand *operand, Type *y) {
|
||||
return false;
|
||||
}
|
||||
|
||||
String check_down_cast_name(Type *dst_, Type *src_) {
|
||||
String result = {};
|
||||
Type *dst = type_deref(dst_);
|
||||
Type *src = type_deref(src_);
|
||||
Type *dst_s = get_base_type(dst);
|
||||
GB_ASSERT(dst_s->kind == Type_Struct || dst_s->kind == Type_Union);
|
||||
// HACK(bill): struct/union variable overlay from unsafe tagged union
|
||||
for (isize i = 0; i < dst_s->Struct.field_count; i++) {
|
||||
Entity *f = dst_s->Struct.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
|
||||
if (f->Variable.anonymous) {
|
||||
if (are_types_identical(f->type, src_)) {
|
||||
return f->token.string;
|
||||
}
|
||||
if (are_types_identical(type_deref(f->type), src_)) {
|
||||
return f->token.string;
|
||||
}
|
||||
|
||||
if (!is_type_pointer(f->type)) {
|
||||
result = check_down_cast_name(f->type, src_);
|
||||
if (result.len > 0)
|
||||
return result;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
GB_ASSERT(node->kind == AstNode_BinaryExpr);
|
||||
Operand y_ = {}, *y = &y_;
|
||||
@@ -1328,6 +1357,69 @@ void check_binary_expr(Checker *c, Operand *x, AstNode *node) {
|
||||
|
||||
x->type = type;
|
||||
|
||||
return;
|
||||
} else if (be->op.kind == Token_down_cast) {
|
||||
check_expr(c, x, be->left);
|
||||
Type *type = check_type(c, be->right);
|
||||
if (x->mode == Addressing_Invalid)
|
||||
return;
|
||||
|
||||
if (x->mode == Addressing_Constant) {
|
||||
gbString expr_str = expr_to_string(node);
|
||||
defer (gb_string_free(expr_str));
|
||||
error(&c->error_collector, ast_node_token(node), "Cannot `down_cast` a constant expression: `%s`", expr_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (is_type_untyped(x->type)) {
|
||||
gbString expr_str = expr_to_string(node);
|
||||
defer (gb_string_free(expr_str));
|
||||
error(&c->error_collector, ast_node_token(node), "Cannot `down_cast` an untyped expression: `%s`", expr_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(is_type_pointer(x->type) && is_type_pointer(type))) {
|
||||
gbString expr_str = expr_to_string(node);
|
||||
defer (gb_string_free(expr_str));
|
||||
error(&c->error_collector, ast_node_token(node), "Can only `down_cast` pointers: `%s`", expr_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
Type *src = type_deref(x->type);
|
||||
Type *dst = type_deref(type);
|
||||
Type *bsrc = get_base_type(src);
|
||||
Type *bdst = get_base_type(dst);
|
||||
|
||||
if (!(bsrc->kind == Type_Struct || bsrc->kind == Type_Union)) {
|
||||
gbString expr_str = expr_to_string(node);
|
||||
defer (gb_string_free(expr_str));
|
||||
error(&c->error_collector, ast_node_token(node), "Can only `down_cast` pointer from structs or unions: `%s`", expr_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
if (!(bdst->kind == Type_Struct || bdst->kind == Type_Union)) {
|
||||
gbString expr_str = expr_to_string(node);
|
||||
defer (gb_string_free(expr_str));
|
||||
error(&c->error_collector, ast_node_token(node), "Can only `down_cast` pointer to structs or unions: `%s`", expr_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
String param_name = check_down_cast_name(dst, src);
|
||||
if (param_name.len == 0) {
|
||||
gbString expr_str = expr_to_string(node);
|
||||
defer (gb_string_free(expr_str));
|
||||
error(&c->error_collector, ast_node_token(node), "Illegal `down_cast`: `%s`", expr_str);
|
||||
x->mode = Addressing_Invalid;
|
||||
return;
|
||||
}
|
||||
|
||||
x->mode = Addressing_Value;
|
||||
x->type = type;
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -1637,125 +1729,6 @@ b32 check_index_value(Checker *c, AstNode *index_value, i64 max_count, i64 *valu
|
||||
return true;
|
||||
}
|
||||
|
||||
struct Selection {
|
||||
Entity *entity;
|
||||
gbArray(isize) index;
|
||||
b32 indirect; // Set if there was a pointer deref anywhere down the line
|
||||
};
|
||||
Selection empty_selection = {};
|
||||
|
||||
Selection make_selection(Entity *entity, gbArray(isize) index, b32 indirect) {
|
||||
Selection s = {entity, index, indirect};
|
||||
return s;
|
||||
}
|
||||
|
||||
void selection_add_index(Selection *s, isize index) {
|
||||
if (s->index == NULL) {
|
||||
gb_array_init(s->index, gb_heap_allocator());
|
||||
}
|
||||
gb_array_append(s->index, index);
|
||||
}
|
||||
|
||||
Selection lookup_field(Type *type_, String field_name, AddressingMode mode, Selection sel = empty_selection) {
|
||||
GB_ASSERT(type_ != NULL);
|
||||
|
||||
if (are_strings_equal(field_name, make_string("_"))) {
|
||||
return empty_selection;
|
||||
}
|
||||
|
||||
Type *type = type_deref(type_);
|
||||
b32 is_ptr = type != type_;
|
||||
type = get_base_type(type);
|
||||
|
||||
switch (type->kind) {
|
||||
case Type_Struct:
|
||||
if (mode == Addressing_Type) {
|
||||
for (isize i = 0; i < type->Struct.other_field_count; i++) {
|
||||
Entity *f = type->Struct.other_fields[i];
|
||||
GB_ASSERT(f->kind != Entity_Variable);
|
||||
String str = f->token.string;
|
||||
if (are_strings_equal(field_name, str)) {
|
||||
selection_add_index(&sel, i);
|
||||
sel.entity = f;
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (isize i = 0; i < type->Struct.field_count; i++) {
|
||||
Entity *f = type->Struct.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
|
||||
String str = f->token.string;
|
||||
if (are_strings_equal(field_name, str)) {
|
||||
selection_add_index(&sel, i);
|
||||
sel.entity = f;
|
||||
return sel;
|
||||
}
|
||||
|
||||
if (f->Variable.anonymous) {
|
||||
isize prev_count = 0;
|
||||
if (sel.index != NULL) {
|
||||
prev_count = gb_array_count(sel.index);
|
||||
}
|
||||
selection_add_index(&sel, i); // HACK(bill): Leaky memory
|
||||
|
||||
sel = lookup_field(f->type, field_name, mode, sel);
|
||||
|
||||
if (sel.entity != NULL) {
|
||||
// gb_printf("%.*s, %.*s, %.*s\n", LIT(field_name), LIT(str), LIT(sel.entity->token.string));
|
||||
if (is_type_pointer(f->type))
|
||||
sel.indirect = true;
|
||||
return sel;
|
||||
}
|
||||
gb_array_count(sel.index) = prev_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Union:
|
||||
for (isize i = 0; i < type->Union.field_count; i++) {
|
||||
Entity *f = type->Union.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
|
||||
String str = f->token.string;
|
||||
if (are_strings_equal(field_name, str)) {
|
||||
selection_add_index(&sel, i);
|
||||
sel.entity = f;
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
for (isize i = 0; i < type->Union.field_count; i++) {
|
||||
Entity *f = type->Union.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
|
||||
String str = f->token.string;
|
||||
if (f->Variable.anonymous) {
|
||||
selection_add_index(&sel, i); // HACK(bill): Leaky memory
|
||||
sel = lookup_field(f->type, field_name, mode, sel);
|
||||
if (sel.entity != NULL && is_type_pointer(f->type)) {
|
||||
sel.indirect = true;
|
||||
}
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Enum:
|
||||
if (mode == Addressing_Type) {
|
||||
for (isize i = 0; i < type->Enum.field_count; i++) {
|
||||
Entity *f = type->Enum.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Constant);
|
||||
String str = f->token.string;
|
||||
if (are_strings_equal(field_name, str)) {
|
||||
// Enums are constant expression
|
||||
return make_selection(f, NULL, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return sel;
|
||||
}
|
||||
|
||||
Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
GB_ASSERT(node->kind == AstNode_SelectorExpr);
|
||||
|
||||
@@ -1763,7 +1736,7 @@ Entity *check_selector(Checker *c, Operand *operand, AstNode *node) {
|
||||
AstNode *op_expr = se->expr;
|
||||
AstNode *selector = se->selector;
|
||||
if (selector) {
|
||||
Entity *entity = lookup_field(operand->type, selector->Ident.token.string, operand->mode).entity;
|
||||
Entity *entity = lookup_field(operand->type, selector->Ident.token.string, operand->mode == Addressing_Type).entity;
|
||||
if (entity == NULL) {
|
||||
gbString op_str = expr_to_string(op_expr);
|
||||
gbString type_str = type_to_string(operand->type);
|
||||
@@ -1967,7 +1940,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
|
||||
ast_node(arg, Ident, field_arg);
|
||||
Selection sel = lookup_field(type, arg->token.string, operand->mode);
|
||||
Selection sel = lookup_field(type, arg->token.string, operand->mode == Addressing_Type);
|
||||
if (sel.entity == NULL) {
|
||||
gbString type_str = type_to_string(type);
|
||||
error(&c->error_collector, ast_node_token(ce->arg_list),
|
||||
@@ -2004,7 +1977,7 @@ b32 check_builtin_procedure(Checker *c, Operand *operand, AstNode *call, i32 id)
|
||||
|
||||
|
||||
ast_node(i, Ident, s->selector);
|
||||
Selection sel = lookup_field(type, i->token.string, operand->mode);
|
||||
Selection sel = lookup_field(type, i->token.string, operand->mode == Addressing_Type);
|
||||
if (sel.entity == NULL) {
|
||||
gbString type_str = type_to_string(type);
|
||||
error(&c->error_collector, ast_node_token(arg),
|
||||
@@ -2630,7 +2603,7 @@ ExprKind check__expr_base(Checker *c, Operand *o, AstNode *node, Type *type_hint
|
||||
}
|
||||
String name = kv->field->Ident.token.string;
|
||||
|
||||
Selection sel = lookup_field(type, kv->field->Ident.token.string, o->mode);
|
||||
Selection sel = lookup_field(type, kv->field->Ident.token.string, o->mode == Addressing_Type);
|
||||
if (sel.entity == NULL) {
|
||||
error(&c->error_collector, ast_node_token(elem),
|
||||
"Unknown field `%.*s` in structure literal", LIT(name));
|
||||
|
||||
+117
-1
@@ -247,6 +247,8 @@ Type *make_type_proc(gbAllocator a, Scope *scope, Type *params, isize param_coun
|
||||
Type *type_deref(Type *t) {
|
||||
if (t != NULL) {
|
||||
Type *bt = get_base_type(t);
|
||||
if (bt == NULL)
|
||||
return NULL;
|
||||
if (bt != NULL && bt->kind == Type_Pointer)
|
||||
return bt->Pointer.elem;
|
||||
}
|
||||
@@ -595,6 +597,102 @@ gb_global i64 basic_type_sizes[] = {
|
||||
|
||||
|
||||
|
||||
struct Selection {
|
||||
Entity *entity;
|
||||
gbArray(isize) index;
|
||||
b32 indirect; // Set if there was a pointer deref anywhere down the line
|
||||
};
|
||||
Selection empty_selection = {};
|
||||
|
||||
Selection make_selection(Entity *entity, gbArray(isize) index, b32 indirect) {
|
||||
Selection s = {entity, index, indirect};
|
||||
return s;
|
||||
}
|
||||
|
||||
void selection_add_index(Selection *s, isize index) {
|
||||
if (s->index == NULL) {
|
||||
gb_array_init(s->index, gb_heap_allocator());
|
||||
}
|
||||
gb_array_append(s->index, index);
|
||||
}
|
||||
|
||||
Selection lookup_field(Type *type_, String field_name, b32 is_type, Selection sel = empty_selection) {
|
||||
GB_ASSERT(type_ != NULL);
|
||||
|
||||
if (are_strings_equal(field_name, make_string("_"))) {
|
||||
return empty_selection;
|
||||
}
|
||||
|
||||
Type *type = type_deref(type_);
|
||||
b32 is_ptr = type != type_;
|
||||
type = get_base_type(type);
|
||||
|
||||
switch (type->kind) {
|
||||
// HACK(bill): struct/union variable overlay from unsafe tagged union
|
||||
case Type_Struct:
|
||||
case Type_Union:
|
||||
if (is_type) {
|
||||
for (isize i = 0; i < type->Struct.other_field_count; i++) {
|
||||
Entity *f = type->Struct.other_fields[i];
|
||||
GB_ASSERT(f->kind != Entity_Variable);
|
||||
String str = f->token.string;
|
||||
if (are_strings_equal(field_name, str)) {
|
||||
selection_add_index(&sel, i);
|
||||
sel.entity = f;
|
||||
return sel;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (isize i = 0; i < type->Struct.field_count; i++) {
|
||||
Entity *f = type->Struct.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Variable && f->Variable.is_field);
|
||||
String str = f->token.string;
|
||||
if (are_strings_equal(field_name, str)) {
|
||||
selection_add_index(&sel, i);
|
||||
sel.entity = f;
|
||||
return sel;
|
||||
}
|
||||
|
||||
if (f->Variable.anonymous) {
|
||||
isize prev_count = 0;
|
||||
if (sel.index != NULL) {
|
||||
prev_count = gb_array_count(sel.index);
|
||||
}
|
||||
selection_add_index(&sel, i); // HACK(bill): Leaky memory
|
||||
|
||||
sel = lookup_field(f->type, field_name, is_type, sel);
|
||||
|
||||
if (sel.entity != NULL) {
|
||||
if (is_type_pointer(f->type))
|
||||
sel.indirect = true;
|
||||
return sel;
|
||||
}
|
||||
gb_array_count(sel.index) = prev_count;
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case Type_Enum:
|
||||
if (is_type) {
|
||||
for (isize i = 0; i < type->Enum.field_count; i++) {
|
||||
Entity *f = type->Enum.fields[i];
|
||||
GB_ASSERT(f->kind == Entity_Constant);
|
||||
String str = f->token.string;
|
||||
if (are_strings_equal(field_name, str)) {
|
||||
// Enums are constant expression
|
||||
return make_selection(f, NULL, i);
|
||||
}
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return sel;
|
||||
}
|
||||
|
||||
|
||||
|
||||
i64 type_size_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
|
||||
i64 type_align_of(BaseTypeSizes s, gbAllocator allocator, Type *t);
|
||||
i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, i64 index);
|
||||
@@ -763,6 +861,24 @@ i64 type_offset_of(BaseTypeSizes s, gbAllocator allocator, Type *t, isize index)
|
||||
return 0;
|
||||
}
|
||||
|
||||
gbString type_to_string(Type *type, gbAllocator a = gb_heap_allocator());
|
||||
|
||||
i64 type_offset_of_from_selection(BaseTypeSizes s, gbAllocator allocator, Type *t, Selection sel) {
|
||||
i64 offset = 0;
|
||||
for (isize i = 0; i < gb_array_count(sel.index); i++) {
|
||||
isize index = sel.index[i];
|
||||
t = get_base_type(t);
|
||||
if (t->kind == Type_Struct) {
|
||||
type_set_offsets(s, allocator, t);
|
||||
GB_ASSERT(gb_is_between(index, 0, t->Struct.field_count-1));
|
||||
offset += t->Struct.offsets[index];
|
||||
t = t->Struct.fields[index]->type;
|
||||
}
|
||||
}
|
||||
return offset;
|
||||
}
|
||||
|
||||
|
||||
|
||||
gbString write_type_to_string(gbString str, Type *type) {
|
||||
if (type == NULL) {
|
||||
@@ -866,7 +982,7 @@ gbString write_type_to_string(gbString str, Type *type) {
|
||||
}
|
||||
|
||||
|
||||
gbString type_to_string(Type *type, gbAllocator a = gb_heap_allocator()) {
|
||||
gbString type_to_string(Type *type, gbAllocator a) {
|
||||
gbString str = gb_string_make(a, "");
|
||||
return write_type_to_string(str, type);
|
||||
}
|
||||
|
||||
+25
-4
@@ -1408,7 +1408,7 @@ ssaValue *ssa_emit_conv(ssaProcedure *proc, ssaValue *value, Type *t, b32 is_arg
|
||||
|
||||
if (field_name.len > 0) {
|
||||
// NOTE(bill): It can be casted
|
||||
Selection sel = lookup_field(sb, field_name, Addressing_Variable);
|
||||
Selection sel = lookup_field(sb, field_name, false);
|
||||
if (sel.entity != NULL) {
|
||||
if (src_is_ptr) {
|
||||
value = ssa_emit_load(proc, value);
|
||||
@@ -1517,6 +1517,24 @@ ssaValue *ssa_emit_transmute(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
ssaValue *ssa_emit_down_cast(ssaProcedure *proc, ssaValue *value, Type *t) {
|
||||
GB_ASSERT(is_type_pointer(ssa_type(value)));
|
||||
gbAllocator allocator = proc->module->allocator;
|
||||
|
||||
// String field_name = check_down_cast_name(t, ssa_type(value));
|
||||
String field_name = check_down_cast_name(t, type_deref(ssa_type(value)));
|
||||
GB_ASSERT(field_name.len > 0);
|
||||
Selection sel = lookup_field(t, field_name, false);
|
||||
Type *t_u8_ptr = make_type_pointer(allocator, t_u8);
|
||||
ssaValue *bytes = ssa_emit_conv(proc, value, t_u8_ptr);
|
||||
|
||||
// IMPORTANT TODO(bill): THIS ONLY DOES ONE LAY DEEP!!! FUCKING HELL THIS IS NOT WHAT I SIGNED UP FOR!
|
||||
|
||||
i64 offset_ = type_offset_of_from_selection(proc->module->sizes, allocator, type_deref(t), sel);
|
||||
ssaValue *offset = ssa_make_value_constant(allocator, t_int, make_exact_value_integer(-offset_));
|
||||
ssaValue *head = ssa_emit_ptr_offset(proc, bytes, offset);
|
||||
return ssa_emit_conv(proc, head, t);
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -1619,6 +1637,9 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
case Token_transmute:
|
||||
return ssa_emit_transmute(proc, ssa_build_expr(proc, be->left), tv->type);
|
||||
|
||||
case Token_down_cast:
|
||||
return ssa_emit_down_cast(proc, ssa_build_expr(proc, be->left), tv->type);
|
||||
|
||||
default:
|
||||
GB_PANIC("Invalid binary expression");
|
||||
break;
|
||||
@@ -1705,7 +1726,7 @@ ssaValue *ssa_build_single_expr(ssaProcedure *proc, AstNode *expr, TypeAndValue
|
||||
|
||||
if (elem->kind == AstNode_FieldValue) {
|
||||
ast_node(kv, FieldValue, elem);
|
||||
Selection sel = lookup_field(base_type, kv->field->Ident.token.string, Addressing_Value);
|
||||
Selection sel = lookup_field(base_type, kv->field->Ident.token.string, false);
|
||||
field_index = sel.index[0];
|
||||
field_expr = ssa_build_expr(proc, kv->value);
|
||||
} else {
|
||||
@@ -2115,7 +2136,7 @@ ssaValue *ssa_add_using_variable(ssaProcedure *proc, Entity *e) {
|
||||
p = ssa_add_using_variable(proc, parent);
|
||||
}
|
||||
|
||||
Selection sel = lookup_field(parent->type, name, Addressing_Variable);
|
||||
Selection sel = lookup_field(parent->type, name, false);
|
||||
GB_ASSERT(sel.entity != NULL);
|
||||
ssaValue **pv = map_get(&proc->module->values, hash_pointer(parent));
|
||||
ssaValue *v = NULL;
|
||||
@@ -2160,7 +2181,7 @@ ssaAddr ssa_build_addr(ssaProcedure *proc, AstNode *expr) {
|
||||
case_ast_node(se, SelectorExpr, expr);
|
||||
Type *type = get_base_type(type_of_expr(proc->module->info, se->expr));
|
||||
|
||||
Selection sel = lookup_field(type, unparen_expr(se->selector)->Ident.token.string, Addressing_Value);
|
||||
Selection sel = lookup_field(type, unparen_expr(se->selector)->Ident.token.string, false);
|
||||
GB_ASSERT(sel.entity != NULL);
|
||||
|
||||
ssaValue *e = ssa_build_addr(proc, se->expr).addr;
|
||||
|
||||
+10
-6
@@ -1452,24 +1452,28 @@ AstNode *parse_binary_expr(AstFile *f, b32 lhs, i32 prec_in) {
|
||||
lhs = false;
|
||||
}
|
||||
|
||||
|
||||
if (op.kind == Token_DoublePrime) {
|
||||
switch (op.kind) {
|
||||
case Token_DoublePrime: {
|
||||
AstNode *proc = parse_identifier(f);
|
||||
AstNode *right = parse_binary_expr(f, false, prec+1);
|
||||
expression->next = right;
|
||||
expression = make_call_expr(f, proc, expression, 2, op, ast_node_token(right));
|
||||
continue;
|
||||
}
|
||||
} break;
|
||||
|
||||
if (op.kind == Token_as || op.kind == Token_transmute) {
|
||||
case Token_as:
|
||||
case Token_transmute:
|
||||
case Token_down_cast:
|
||||
right = parse_type(f);
|
||||
} else {
|
||||
break;
|
||||
|
||||
default:
|
||||
right = parse_binary_expr(f, false, prec+1);
|
||||
if (!right) {
|
||||
ast_file_err(f, op, "Expected expression on the right hand side of the binary operator");
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
expression = make_binary_expr(f, op, expression, right);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -30,6 +30,7 @@ TOKEN_KIND(Token__OperatorBegin, "_OperatorBegin"), \
|
||||
\
|
||||
TOKEN_KIND(Token_as, "as"), \
|
||||
TOKEN_KIND(Token_transmute, "transmute"), \
|
||||
TOKEN_KIND(Token_down_cast, "down_cast"), \
|
||||
\
|
||||
TOKEN_KIND(Token_Prime, "'"), \
|
||||
TOKEN_KIND(Token_DoublePrime, "''"), \
|
||||
@@ -207,6 +208,7 @@ i32 token_precedence(Token t) {
|
||||
return 6;
|
||||
case Token_as:
|
||||
case Token_transmute:
|
||||
case Token_down_cast:
|
||||
return 7;
|
||||
}
|
||||
|
||||
@@ -629,6 +631,8 @@ Token tokenizer_get_token(Tokenizer *t) {
|
||||
token.kind = Token_as;
|
||||
} else if (are_strings_equal(token.string, token_strings[Token_transmute])) {
|
||||
token.kind = Token_transmute;
|
||||
} else if (are_strings_equal(token.string, token_strings[Token_down_cast])) {
|
||||
token.kind = Token_down_cast;
|
||||
} else {
|
||||
for (i32 k = Token__KeywordBegin+1; k < Token__KeywordEnd; k++) {
|
||||
if (are_strings_equal(token.string, token_strings[k])) {
|
||||
|
||||
Reference in New Issue
Block a user