Skip to content

Commit aa56f01

Browse files
committed
support addressof operator and struct pointer field access
1 parent 5a8822c commit aa56f01

File tree

6 files changed

+52
-9
lines changed

6 files changed

+52
-9
lines changed

example/structs/structs.zig

+13-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,13 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
1111

1212
test_foo(foo);
1313

14+
modify_foo(&foo);
15+
16+
if foo.c != 100 {
17+
print_str("BAD\n");
18+
}
19+
20+
print_str("OK\n");
1421
return 0;
1522
}
1623

@@ -21,7 +28,11 @@ struct Foo {
2128
}
2229

2330
fn test_foo(foo : Foo) {
24-
if foo.b {
25-
print_str("OK\n" as string);
31+
if !foo.b {
32+
print_str("BAD\n");
2633
}
2734
}
35+
36+
fn modify_foo(foo : &Foo) {
37+
foo.c = 100;
38+
}

src/analyze.cpp

+14-2
Original file line numberDiff line numberDiff line change
@@ -116,6 +116,9 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
116116
entry->align_in_bits = g->pointer_size_bytes * 8;
117117
entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type,
118118
entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));
119+
entry->data.pointer.child_type = child_type;
120+
entry->data.pointer.is_const = is_const;
121+
119122
g->type_table.put(&entry->name, entry);
120123
*parent_pointer = entry;
121124
return entry;
@@ -575,6 +578,10 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type,
575578
case TypeTableEntryIdFloat:
576579
if (is_num_lit_float(num_lit)) {
577580
return lit_size_in_bits <= other_type->size_in_bits;
581+
} else if (other_type->size_in_bits == 32) {
582+
return lit_size_in_bits < 24;
583+
} else if (other_type->size_in_bits == 64) {
584+
return lit_size_in_bits < 53;
578585
} else {
579586
return false;
580587
}
@@ -810,14 +817,19 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
810817

811818
TypeTableEntry *return_type;
812819

813-
if (struct_type->id == TypeTableEntryIdStruct) {
820+
if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer &&
821+
struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct))
822+
{
814823
assert(node->codegen_node);
815824
FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
816825
assert(codegen_field_access);
817826

818827
Buf *field_name = &node->data.field_access_expr.field_name;
819828

820-
get_struct_field(struct_type, field_name,
829+
TypeTableEntry *bare_struct_type = (struct_type->id == TypeTableEntryIdStruct) ?
830+
struct_type : struct_type->data.pointer.child_type;
831+
832+
get_struct_field(bare_struct_type, field_name,
821833
&codegen_field_access->type_struct_field,
822834
&codegen_field_access->field_index);
823835
if (codegen_field_access->type_struct_field) {

src/analyze.hpp

+2-2
Original file line numberDiff line numberDiff line change
@@ -20,8 +20,8 @@ struct VariableTableEntry;
2020
struct CastNode;
2121

2222
struct TypeTableEntryPointer {
23-
TypeTableEntry *pointer_child;
24-
bool pointer_is_const;
23+
TypeTableEntry *child_type;
24+
bool is_const;
2525
};
2626

2727
struct TypeTableEntryInt {

src/codegen.cpp

+2
Original file line numberDiff line numberDiff line change
@@ -248,6 +248,8 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
248248
TypeTableEntry *type_entry;
249249
LLVMValueRef ptr = gen_field_ptr(g, node, &type_entry);
250250
return LLVMBuildLoad(g->builder, ptr, "");
251+
} else if (struct_type->id == TypeTableEntryIdPointer) {
252+
zig_panic("TODO struct pointer access");
251253
} else {
252254
zig_panic("gen_field_access_expr bad struct type");
253255
}

src/parser.cpp

+11-1
Original file line numberDiff line numberDiff line change
@@ -1153,12 +1153,13 @@ static PrefixOp tok_to_prefix_op(Token *token) {
11531153
case TokenIdBang: return PrefixOpBoolNot;
11541154
case TokenIdDash: return PrefixOpNegation;
11551155
case TokenIdTilde: return PrefixOpBinNot;
1156+
case TokenIdAmpersand: return PrefixOpAddressOf;
11561157
default: return PrefixOpInvalid;
11571158
}
11581159
}
11591160

11601161
/*
1161-
PrefixOp : token(Not) | token(Dash) | token(Tilde)
1162+
PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const)))
11621163
*/
11631164
static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool mandatory) {
11641165
Token *token = &pc->tokens->at(*token_index);
@@ -1171,6 +1172,15 @@ static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool man
11711172
}
11721173
}
11731174
*token_index += 1;
1175+
1176+
if (result == PrefixOpAddressOf) {
1177+
Token *token = &pc->tokens->at(*token_index);
1178+
if (token->id == TokenIdKeywordConst) {
1179+
*token_index += 1;
1180+
result = PrefixOpConstAddressOf;
1181+
}
1182+
}
1183+
11741184
return result;
11751185
}
11761186

test/run_tests.cpp

+10-2
Original file line numberDiff line numberDiff line change
@@ -569,6 +569,11 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
569569
foo.a += 1;
570570
foo.b = foo.a == 1;
571571
test_foo(foo);
572+
test_mutation(&foo);
573+
if foo.c != 100 {
574+
print_str("BAD\n");
575+
}
576+
print_str("OK\n");
572577
return 0;
573578
}
574579
struct Foo {
@@ -577,9 +582,12 @@ struct Foo {
577582
c : f32,
578583
}
579584
fn test_foo(foo : Foo) {
580-
if foo.b {
581-
print_str("OK\n");
585+
if !foo.b {
586+
print_str("BAD\n");
582587
}
588+
}
589+
fn test_mutation(foo : &Foo) {
590+
foo.c = 100;
583591
}
584592
)SOURCE", "OK\n");
585593

0 commit comments

Comments
 (0)