Commit 76ab1d2b6c

Andrew Kelley <superjoe30@gmail.com>
2018-04-30 20:20:56
support foo.* for ptr deref
See #770
1 parent e14db23
doc/langref.html.in
@@ -5958,10 +5958,12 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
 
 PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression
 
-SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
+SuffixOpExpression = ("async" option("&lt;" SuffixOpExpression "&gt;") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression | PtrDerefExpression)
 
 FieldAccessExpression = "." Symbol
 
+PtrDerefExpression = ".*"
+
 FnCallExpression = "(" list(Expression, ",") ")"
 
 ArrayAccessExpression = "[" Expression "]"
@@ -5974,7 +5976,7 @@ ContainerInitBody = list(StructLiteralField, ",") | list(Expression, ",")
 
 StructLiteralField = "." Symbol "=" Expression
 
-PrefixOp = "!" | "-" | "~" | "*" | ("&amp;" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
+PrefixOp = "!" | "-" | "~" | ("*" option("align" "(" Expression option(":" Integer ":" Integer) ")" ) option("const") option("volatile")) | "?" | "??" | "-%" | "try" | "await"
 
 PrimaryExpression = Integer | Float | String | CharLiteral | KeywordLiteral | GroupedExpression | BlockExpression(BlockOrExpression) | Symbol | ("@" Symbol FnCallExpression) | ArrayType | FnProto | AsmExpression | ContainerDecl | ("continue" option(":" Symbol)) | ErrorSetDecl | PromiseType
 
src/all_types.hpp
@@ -379,6 +379,7 @@ enum NodeType {
     NodeTypeArrayAccessExpr,
     NodeTypeSliceExpr,
     NodeTypeFieldAccessExpr,
+    NodeTypePtrDeref,
     NodeTypeUse,
     NodeTypeBoolLiteral,
     NodeTypeNullLiteral,
@@ -603,6 +604,10 @@ struct AstNodeFieldAccessExpr {
     Buf *field_name;
 };
 
+struct AstNodePtrDerefExpr {
+    AstNode *target;
+};
+
 enum PrefixOp {
     PrefixOpInvalid,
     PrefixOpBoolNot,
@@ -911,6 +916,7 @@ struct AstNode {
         AstNodeCompTime comptime_expr;
         AstNodeAsmExpr asm_expr;
         AstNodeFieldAccessExpr field_access_expr;
+        AstNodePtrDerefExpr ptr_deref_expr;
         AstNodeContainerDecl container_decl;
         AstNodeStructField struct_field;
         AstNodeStringLiteral string_literal;
src/analyze.cpp
@@ -3275,6 +3275,7 @@ void scan_decls(CodeGen *g, ScopeDecls *decls_scope, AstNode *node) {
         case NodeTypeUnreachable:
         case NodeTypeAsmExpr:
         case NodeTypeFieldAccessExpr:
+        case NodeTypePtrDeref:
         case NodeTypeStructField:
         case NodeTypeContainerInitExpr:
         case NodeTypeStructValueField:
src/ast_render.cpp
@@ -222,6 +222,8 @@ static const char *node_type_str(NodeType node_type) {
             return "AsmExpr";
         case NodeTypeFieldAccessExpr:
             return "FieldAccessExpr";
+        case NodeTypePtrDeref:
+            return "PtrDerefExpr";
         case NodeTypeContainerDecl:
             return "ContainerDecl";
         case NodeTypeStructField:
@@ -696,6 +698,13 @@ static void render_node_extra(AstRender *ar, AstNode *node, bool grouped) {
                 print_symbol(ar, rhs);
                 break;
             }
+        case NodeTypePtrDeref:
+            {
+                AstNode *lhs = node->data.ptr_deref_expr.target;
+                render_node_ungrouped(ar, lhs);
+                fprintf(ar->f, ".*");
+                break;
+            }
         case NodeTypeUndefinedLiteral:
             fprintf(ar->f, "undefined");
             break;
src/ir.cpp
@@ -4548,8 +4548,14 @@ static IrInstruction *ir_gen_if_bool_expr(IrBuilder *irb, Scope *scope, AstNode
 }
 
 static IrInstruction *ir_gen_prefix_op_id_lval(IrBuilder *irb, Scope *scope, AstNode *node, IrUnOp op_id, LVal lval) {
-    assert(node->type == NodeTypePrefixOpExpr);
-    AstNode *expr_node = node->data.prefix_op_expr.primary_expr;
+    AstNode *expr_node;
+    if (node->type == NodeTypePrefixOpExpr) {
+        expr_node = node->data.prefix_op_expr.primary_expr;
+    } else if (node->type == NodeTypePtrDeref) {
+        expr_node = node->data.ptr_deref_expr.target;
+    } else {
+        zig_unreachable();
+    }
 
     IrInstruction *value = ir_gen_node_extra(irb, expr_node, scope, lval);
     if (value == irb->codegen->invalid_instruction)
@@ -6527,6 +6533,8 @@ static IrInstruction *ir_gen_node_raw(IrBuilder *irb, AstNode *node, Scope *scop
 
                 return ir_build_load_ptr(irb, scope, node, ptr_instruction);
             }
+        case NodeTypePtrDeref:
+            return ir_gen_prefix_op_id_lval(irb, scope, node, IrUnOpDereference, lval);
         case NodeTypeThisLiteral:
             return ir_lval_wrap(irb, scope, ir_gen_this_literal(irb, scope, node), lval);
         case NodeTypeBoolLiteral:
src/parser.cpp
@@ -1046,11 +1046,12 @@ static AstNode *ast_parse_fn_proto_partial(ParseContext *pc, size_t *token_index
 }
 
 /*
-SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
+SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | PtrDerefExpression | SliceExpression)
 FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
 ArrayAccessExpression : token(LBracket) Expression token(RBracket)
 SliceExpression = "[" Expression ".." option(Expression) "]"
 FieldAccessExpression : token(Dot) token(Symbol)
+PtrDerefExpression = ".*"
 StructLiteralField : token(Dot) token(Symbol) token(Eq) Expression
 */
 static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index, bool mandatory) {
@@ -1131,13 +1132,27 @@ static AstNode *ast_parse_suffix_op_expr(ParseContext *pc, size_t *token_index,
         } else if (first_token->id == TokenIdDot) {
             *token_index += 1;
 
-            Token *name_token = ast_eat_token(pc, token_index, TokenIdSymbol);
+            Token *token = &pc->tokens->at(*token_index);
+
+            if (token->id == TokenIdSymbol) {
+                *token_index += 1;
 
-            AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
-            node->data.field_access_expr.struct_expr = primary_expr;
-            node->data.field_access_expr.field_name = token_buf(name_token);
+                AstNode *node = ast_create_node(pc, NodeTypeFieldAccessExpr, first_token);
+                node->data.field_access_expr.struct_expr = primary_expr;
+                node->data.field_access_expr.field_name = token_buf(token);
+
+                primary_expr = node;
+            } else if (token->id == TokenIdStar) {
+                *token_index += 1;
+
+                AstNode *node = ast_create_node(pc, NodeTypePtrDeref, first_token);
+                node->data.ptr_deref_expr.target = primary_expr;
+
+                primary_expr = node;
+            } else {
+                ast_invalid_token_error(pc, token);
+            }
 
-            primary_expr = node;
         } else {
             return primary_expr;
         }
@@ -3012,6 +3027,9 @@ void ast_visit_node_children(AstNode *node, void (*visit)(AstNode **, void *cont
         case NodeTypeFieldAccessExpr:
             visit_field(&node->data.field_access_expr.struct_expr, visit, context);
             break;
+        case NodeTypePtrDeref:
+            visit_field(&node->data.ptr_deref_expr.target, visit, context);
+            break;
         case NodeTypeUse:
             visit_field(&node->data.use.expr, visit, context);
             break;
test/cases/pointers.zig
@@ -0,0 +1,14 @@
+const std = @import("std");
+const assert = std.debug.assert;
+
+test "dereference pointer" {
+    comptime testDerefPtr();
+    testDerefPtr();
+}
+
+fn testDerefPtr() void {
+    var x: i32 = 1234;
+    var y = &x;
+    y.* += 1;
+    assert(x == 1235);
+}
test/behavior.zig
@@ -33,6 +33,7 @@ comptime {
     _ = @import("cases/misc.zig");
     _ = @import("cases/namespace_depends_on_compile_var/index.zig");
     _ = @import("cases/null.zig");
+    _ = @import("cases/pointers.zig");
     _ = @import("cases/pub_enum/index.zig");
     _ = @import("cases/ref_var_in_if_after_if_2nd_switch_prong.zig");
     _ = @import("cases/reflection.zig");