Commit 76ab1d2b6c
Changed files (8)
doc/langref.html.in
@@ -5958,10 +5958,12 @@ MultiplyOperator = "||" | "*" | "/" | "%" | "**" | "*%"
PrefixOpExpression = PrefixOp TypeExpr | SuffixOpExpression
-SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") SuffixOpExpression FnCallExpression) | PrimaryExpression option(FnCallExpression | ArrayAccessExpression | FieldAccessExpression | SliceExpression)
+SuffixOpExpression = ("async" option("<" SuffixOpExpression ">") 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 = "!" | "-" | "~" | "*" | ("&" 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");