authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-04 19:10:52-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-04 19:11:36-07:00
loge0aa0736be47e5e1383d8fb25f744f95c5a830ba
tree0ae86d7782de9e73d21449fd70a9fc3383cdad0a
parent22c52f1eb67a46e60be876fda332ad7d2f338ee7

add pointer dereferencing operator


6 files changed, 77 insertions(+), 6 deletions(-)

doc/langref.md+2-2
......@@ -154,7 +154,7 @@ FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
154154
155155ArrayAccessExpression : token(LBracket) Expression token(RBracket)
156156
157PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const)))
157PrefixOp : token(Not) | token(Dash) | token(Tilde) | token(Star) | (token(Ampersand) option(token(Const)))
158158
159159PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType
160160
......@@ -173,7 +173,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)
173173
174174```
175175x() x[] x.y
176!x -x ~x &x &const x
176!x -x ~x *x &x &const x
177177as
178178* / %
179179+ -
src/analyze.cpp+38-2
......@@ -1271,31 +1271,51 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc
12711271 if (purpose == LValPurposeAssign && var->is_const) {
12721272 add_node_error(g, lhs_node,
12731273 buf_sprintf("cannot assign to constant"));
1274 expected_rhs_type = g->builtin_types.entry_invalid;
12741275 } else if (purpose == LValPurposeAddressOf && var->is_const && !is_ptr_const) {
12751276 add_node_error(g, lhs_node,
12761277 buf_sprintf("must use &const to get address of constant"));
1278 expected_rhs_type = g->builtin_types.entry_invalid;
12771279 } else {
12781280 expected_rhs_type = var->type;
12791281 }
12801282 } else {
12811283 add_node_error(g, lhs_node,
12821284 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
1285 expected_rhs_type = g->builtin_types.entry_invalid;
12831286 }
12841287 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
12851288 expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node);
12861289 } else if (lhs_node->type == NodeTypeFieldAccessExpr) {
12871290 alloc_codegen_node(lhs_node);
12881291 expected_rhs_type = analyze_field_access_expr(g, import, block_context, lhs_node);
1292 } else if (lhs_node->type == NodeTypePrefixOpExpr &&
1293 lhs_node->data.prefix_op_expr.prefix_op == PrefixOpDereference)
1294 {
1295 assert(purpose == LValPurposeAssign);
1296 AstNode *target_node = lhs_node->data.prefix_op_expr.primary_expr;
1297 TypeTableEntry *type_entry = analyze_expression(g, import, block_context, nullptr, target_node);
1298 if (type_entry->id == TypeTableEntryIdInvalid) {
1299 expected_rhs_type = type_entry;
1300 } else if (type_entry->id == TypeTableEntryIdPointer) {
1301 expected_rhs_type = type_entry->data.pointer.child_type;
1302 } else {
1303 add_node_error(g, target_node,
1304 buf_sprintf("indirection requires pointer operand ('%s' invalid)",
1305 buf_ptr(&type_entry->name)));
1306 expected_rhs_type = g->builtin_types.entry_invalid;
1307 }
12891308 } else {
12901309 if (purpose == LValPurposeAssign) {
12911310 add_node_error(g, lhs_node,
1292 buf_sprintf("assignment target must be variable, field, or array element"));
1311 buf_sprintf("invalid assignment target"));
12931312 } else if (purpose == LValPurposeAddressOf) {
12941313 add_node_error(g, lhs_node,
1295 buf_sprintf("addressof target must be variable, field, or array element"));
1314 buf_sprintf("invalid addressof target"));
12961315 }
12971316 expected_rhs_type = g->builtin_types.entry_invalid;
12981317 }
1318 assert(expected_rhs_type);
12991319 return expected_rhs_type;
13001320}
13011321
......@@ -1940,6 +1960,22 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
19401960 return_type = get_pointer_to_type(g, child_type, is_const);
19411961 break;
19421962 }
1963 case PrefixOpDereference:
1964 {
1965 TypeTableEntry *type_entry = analyze_expression(g, import, context, nullptr,
1966 node->data.prefix_op_expr.primary_expr);
1967 if (type_entry->id == TypeTableEntryIdInvalid) {
1968 return_type = type_entry;
1969 } else if (type_entry->id == TypeTableEntryIdPointer) {
1970 return_type = type_entry->data.pointer.child_type;
1971 } else {
1972 add_node_error(g, node->data.prefix_op_expr.primary_expr,
1973 buf_sprintf("indirection requires pointer operand ('%s' invalid)",
1974 buf_ptr(&type_entry->name)));
1975 return_type = g->builtin_types.entry_invalid;
1976 }
1977 break;
1978 }
19431979 }
19441980 break;
19451981 case NodeTypeIfBoolExpr:
src/codegen.cpp+13-1
......@@ -359,6 +359,13 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
359359 }
360360 } else if (node->type == NodeTypeFieldAccessExpr) {
361361 target_ref = gen_field_ptr(g, node, out_type_entry);
362 } else if (node->type == NodeTypePrefixOpExpr) {
363 assert(node->data.prefix_op_expr.prefix_op == PrefixOpDereference);
364 AstNode *target_expr = node->data.prefix_op_expr.primary_expr;
365 TypeTableEntry *type_entry = get_expr_type(target_expr);
366 assert(type_entry->id == TypeTableEntryIdPointer);
367 *out_type_entry = type_entry->data.pointer.child_type;
368 return gen_expr(g, target_expr);
362369 } else {
363370 zig_panic("bad assign target");
364371 }
......@@ -397,11 +404,16 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
397404 case PrefixOpAddressOf:
398405 case PrefixOpConstAddressOf:
399406 {
400 add_debug_source_node(g, node);
401407 TypeTableEntry *lvalue_type;
402408 return gen_lvalue(g, node, expr_node, &lvalue_type);
403409 }
404410
411 case PrefixOpDereference:
412 {
413 LLVMValueRef expr = gen_expr(g, expr_node);
414 add_debug_source_node(g, node);
415 return LLVMBuildLoad(g->builder, expr, "");
416 }
405417 }
406418 zig_unreachable();
407419}
src/parser.cpp+2
......@@ -60,6 +60,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
6060 case PrefixOpBinNot: return "~";
6161 case PrefixOpAddressOf: return "&";
6262 case PrefixOpConstAddressOf: return "&const";
63 case PrefixOpDereference: return "*";
6364 }
6465 zig_unreachable();
6566}
......@@ -1422,6 +1423,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
14221423 case TokenIdDash: return PrefixOpNegation;
14231424 case TokenIdTilde: return PrefixOpBinNot;
14241425 case TokenIdAmpersand: return PrefixOpAddressOf;
1426 case TokenIdStar: return PrefixOpDereference;
14251427 default: return PrefixOpInvalid;
14261428 }
14271429}
src/parser.hpp+1
......@@ -212,6 +212,7 @@ enum PrefixOp {
212212 PrefixOpNegation,
213213 PrefixOpAddressOf,
214214 PrefixOpConstAddressOf,
215 PrefixOpDereference,
215216};
216217
217218struct AstNodePrefixOpExpr {
test/run_tests.cpp+21-1
......@@ -755,6 +755,26 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
755755 }
756756 print_str("OK\n");
757757 return 0;
758}
759 )SOURCE", "OK\n");
760
761 add_simple_case("pointer dereferencing", R"SOURCE(
762use "std.zig";
763
764pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
765 var x = 3 as i32;
766 const y = &x;
767
768 *y += 1;
769
770 if (x != 4) {
771 print_str("BAD\n");
772 }
773 if (*y != 4) {
774 print_str("BAD\n");
775 }
776 print_str("OK\n");
777 return 0;
758778}
759779 )SOURCE", "OK\n");
760780}
......@@ -904,7 +924,7 @@ a_label:
904924fn f() {
905925 3 = 3;
906926}
907 )SOURCE", 1, ".tmp_source.zig:3:5: error: assignment target must be variable, field, or array element");
927 )SOURCE", 1, ".tmp_source.zig:3:5: error: invalid assignment target");
908928
909929 add_compile_fail_case("assign to constant variable", R"SOURCE(
910930fn f() {