Commit aa56f016f7

Andrew Kelley <superjoe30@gmail.com>
2015-12-16 04:08:53
support addressof operator and struct pointer field access
1 parent 5a8822c
example/structs/structs.zig
@@ -11,6 +11,13 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
 
     test_foo(foo);
 
+    modify_foo(&foo);
+
+    if foo.c != 100 {
+        print_str("BAD\n");
+    }
+
+    print_str("OK\n");
     return 0;
 }
 
@@ -21,7 +28,11 @@ struct Foo {
 }
 
 fn test_foo(foo : Foo) {
-    if foo.b {
-        print_str("OK\n" as string);
+    if !foo.b {
+        print_str("BAD\n");
     }
 }
+
+fn modify_foo(foo : &Foo) {
+    foo.c = 100;
+}
src/analyze.cpp
@@ -116,6 +116,9 @@ TypeTableEntry *get_pointer_to_type(CodeGen *g, TypeTableEntry *child_type, bool
         entry->align_in_bits = g->pointer_size_bytes * 8;
         entry->di_type = LLVMZigCreateDebugPointerType(g->dbuilder, child_type->di_type,
                 entry->size_in_bits, entry->align_in_bits, buf_ptr(&entry->name));
+        entry->data.pointer.child_type = child_type;
+        entry->data.pointer.is_const = is_const;
+
         g->type_table.put(&entry->name, entry);
         *parent_pointer = entry;
         return entry;
@@ -575,6 +578,10 @@ static bool num_lit_fits_in_other_type(CodeGen *g, TypeTableEntry *literal_type,
         case TypeTableEntryIdFloat:
             if (is_num_lit_float(num_lit)) {
                 return lit_size_in_bits <= other_type->size_in_bits;
+            } else if (other_type->size_in_bits == 32) {
+                return lit_size_in_bits < 24;
+            } else if (other_type->size_in_bits == 64) {
+                return lit_size_in_bits < 53;
             } else {
                 return false;
             }
@@ -810,14 +817,19 @@ static TypeTableEntry *analyze_field_access_expr(CodeGen *g, ImportTableEntry *i
 
     TypeTableEntry *return_type;
 
-    if (struct_type->id == TypeTableEntryIdStruct) {
+    if (struct_type->id == TypeTableEntryIdStruct || (struct_type->id == TypeTableEntryIdPointer &&
+         struct_type->data.pointer.child_type->id == TypeTableEntryIdStruct))
+    {
         assert(node->codegen_node);
         FieldAccessNode *codegen_field_access = &node->codegen_node->data.field_access_node;
         assert(codegen_field_access);
 
         Buf *field_name = &node->data.field_access_expr.field_name;
 
-        get_struct_field(struct_type, field_name,
+        TypeTableEntry *bare_struct_type = (struct_type->id == TypeTableEntryIdStruct) ?
+            struct_type : struct_type->data.pointer.child_type;
+
+        get_struct_field(bare_struct_type, field_name,
                 &codegen_field_access->type_struct_field,
                 &codegen_field_access->field_index);
         if (codegen_field_access->type_struct_field) {
src/analyze.hpp
@@ -20,8 +20,8 @@ struct VariableTableEntry;
 struct CastNode;
 
 struct TypeTableEntryPointer {
-    TypeTableEntry *pointer_child;
-    bool pointer_is_const;
+    TypeTableEntry *child_type;
+    bool is_const;
 };
 
 struct TypeTableEntryInt {
src/codegen.cpp
@@ -248,6 +248,8 @@ static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node) {
         TypeTableEntry *type_entry;
         LLVMValueRef ptr = gen_field_ptr(g, node, &type_entry);
         return LLVMBuildLoad(g->builder, ptr, "");
+    } else if (struct_type->id == TypeTableEntryIdPointer) {
+        zig_panic("TODO struct pointer access");
     } else {
         zig_panic("gen_field_access_expr bad struct type");
     }
src/parser.cpp
@@ -1153,12 +1153,13 @@ static PrefixOp tok_to_prefix_op(Token *token) {
         case TokenIdBang: return PrefixOpBoolNot;
         case TokenIdDash: return PrefixOpNegation;
         case TokenIdTilde: return PrefixOpBinNot;
+        case TokenIdAmpersand: return PrefixOpAddressOf;
         default: return PrefixOpInvalid;
     }
 }
 
 /*
-PrefixOp : token(Not) | token(Dash) | token(Tilde)
+PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const)))
 */
 static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool mandatory) {
     Token *token = &pc->tokens->at(*token_index);
@@ -1171,6 +1172,15 @@ static PrefixOp ast_parse_prefix_op(ParseContext *pc, int *token_index, bool man
         }
     }
     *token_index += 1;
+
+    if (result == PrefixOpAddressOf) {
+        Token *token = &pc->tokens->at(*token_index);
+        if (token->id == TokenIdKeywordConst) {
+            *token_index += 1;
+            result = PrefixOpConstAddressOf;
+        }
+    }
+
     return result;
 }
 
test/run_tests.cpp
@@ -569,6 +569,11 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
     foo.a += 1;
     foo.b = foo.a == 1;
     test_foo(foo);
+    test_mutation(&foo);
+    if foo.c != 100 {
+        print_str("BAD\n");
+    }
+    print_str("OK\n");
     return 0;
 }
 struct Foo {
@@ -577,9 +582,12 @@ struct Foo {
     c : f32,
 }
 fn test_foo(foo : Foo) {
-    if foo.b {
-        print_str("OK\n");
+    if !foo.b {
+        print_str("BAD\n");
     }
+}
+fn test_mutation(foo : &Foo) {
+    foo.c = 100;
 }
     )SOURCE", "OK\n");