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)...@@ -154,7 +154,7 @@ FnCallExpression : token(LParen) list(Expression, token(Comma)) token(RParen)
154154
155ArrayAccessExpression : token(LBracket) Expression token(RBracket)155ArrayAccessExpression : 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
159PrimaryExpression : token(Number) | token(String) | token(CharLiteral) | KeywordLiteral | GroupedExpression | Goto | token(Break) | token(Continue) | BlockExpression | token(Symbol) | StructValueExpression | CompilerFnType159PrimaryExpression : 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)...@@ -173,7 +173,7 @@ KeywordLiteral : token(Unreachable) | token(Void) | token(True) | token(False)
173173
174```174```
175x() x[] x.y175x() x[] x.y
176!x -x ~x &x &const x176!x -x ~x *x &x &const x
177as177as
178* / %178* / %
179+ -179+ -
src/analyze.cpp+38-2
...@@ -1271,31 +1271,51 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc...@@ -1271,31 +1271,51 @@ static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, Bloc
1271 if (purpose == LValPurposeAssign && var->is_const) {1271 if (purpose == LValPurposeAssign && var->is_const) {
1272 add_node_error(g, lhs_node,1272 add_node_error(g, lhs_node,
1273 buf_sprintf("cannot assign to constant"));1273 buf_sprintf("cannot assign to constant"));
1274 expected_rhs_type = g->builtin_types.entry_invalid;
1274 } else if (purpose == LValPurposeAddressOf && var->is_const && !is_ptr_const) {1275 } else if (purpose == LValPurposeAddressOf && var->is_const && !is_ptr_const) {
1275 add_node_error(g, lhs_node,1276 add_node_error(g, lhs_node,
1276 buf_sprintf("must use &const to get address of constant"));1277 buf_sprintf("must use &const to get address of constant"));
1278 expected_rhs_type = g->builtin_types.entry_invalid;
1277 } else {1279 } else {
1278 expected_rhs_type = var->type;1280 expected_rhs_type = var->type;
1279 }1281 }
1280 } else {1282 } else {
1281 add_node_error(g, lhs_node,1283 add_node_error(g, lhs_node,
1282 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));1284 buf_sprintf("use of undeclared identifier '%s'", buf_ptr(name)));
1285 expected_rhs_type = g->builtin_types.entry_invalid;
1283 }1286 }
1284 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {1287 } else if (lhs_node->type == NodeTypeArrayAccessExpr) {
1285 expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node);1288 expected_rhs_type = analyze_array_access_expr(g, import, block_context, lhs_node);
1286 } else if (lhs_node->type == NodeTypeFieldAccessExpr) {1289 } else if (lhs_node->type == NodeTypeFieldAccessExpr) {
1287 alloc_codegen_node(lhs_node);1290 alloc_codegen_node(lhs_node);
1288 expected_rhs_type = analyze_field_access_expr(g, import, block_context, lhs_node);1291 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 }
1289 } else {1308 } else {
1290 if (purpose == LValPurposeAssign) {1309 if (purpose == LValPurposeAssign) {
1291 add_node_error(g, lhs_node,1310 add_node_error(g, lhs_node,
1292 buf_sprintf("assignment target must be variable, field, or array element"));1311 buf_sprintf("invalid assignment target"));
1293 } else if (purpose == LValPurposeAddressOf) {1312 } else if (purpose == LValPurposeAddressOf) {
1294 add_node_error(g, lhs_node,1313 add_node_error(g, lhs_node,
1295 buf_sprintf("addressof target must be variable, field, or array element"));1314 buf_sprintf("invalid addressof target"));
1296 }1315 }
1297 expected_rhs_type = g->builtin_types.entry_invalid;1316 expected_rhs_type = g->builtin_types.entry_invalid;
1298 }1317 }
1318 assert(expected_rhs_type);
1299 return expected_rhs_type;1319 return expected_rhs_type;
1300}1320}
13011321
...@@ -1940,6 +1960,22 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1940,6 +1960,22 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1940 return_type = get_pointer_to_type(g, child_type, is_const);1960 return_type = get_pointer_to_type(g, child_type, is_const);
1941 break;1961 break;
1942 }1962 }
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 }
1943 }1979 }
1944 break;1980 break;
1945 case NodeTypeIfBoolExpr:1981 case NodeTypeIfBoolExpr:
src/codegen.cpp+13-1
...@@ -359,6 +359,13 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,...@@ -359,6 +359,13 @@ static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node,
359 }359 }
360 } else if (node->type == NodeTypeFieldAccessExpr) {360 } else if (node->type == NodeTypeFieldAccessExpr) {
361 target_ref = gen_field_ptr(g, node, out_type_entry);361 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);
362 } else {369 } else {
363 zig_panic("bad assign target");370 zig_panic("bad assign target");
364 }371 }
...@@ -397,11 +404,16 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {...@@ -397,11 +404,16 @@ static LLVMValueRef gen_prefix_op_expr(CodeGen *g, AstNode *node) {
397 case PrefixOpAddressOf:404 case PrefixOpAddressOf:
398 case PrefixOpConstAddressOf:405 case PrefixOpConstAddressOf:
399 {406 {
400 add_debug_source_node(g, node);
401 TypeTableEntry *lvalue_type;407 TypeTableEntry *lvalue_type;
402 return gen_lvalue(g, node, expr_node, &lvalue_type);408 return gen_lvalue(g, node, expr_node, &lvalue_type);
403 }409 }
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 }
405 }417 }
406 zig_unreachable();418 zig_unreachable();
407}419}
src/parser.cpp+2
...@@ -60,6 +60,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) {...@@ -60,6 +60,7 @@ static const char *prefix_op_str(PrefixOp prefix_op) {
60 case PrefixOpBinNot: return "~";60 case PrefixOpBinNot: return "~";
61 case PrefixOpAddressOf: return "&";61 case PrefixOpAddressOf: return "&";
62 case PrefixOpConstAddressOf: return "&const";62 case PrefixOpConstAddressOf: return "&const";
63 case PrefixOpDereference: return "*";
63 }64 }
64 zig_unreachable();65 zig_unreachable();
65}66}
...@@ -1422,6 +1423,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {...@@ -1422,6 +1423,7 @@ static PrefixOp tok_to_prefix_op(Token *token) {
1422 case TokenIdDash: return PrefixOpNegation;1423 case TokenIdDash: return PrefixOpNegation;
1423 case TokenIdTilde: return PrefixOpBinNot;1424 case TokenIdTilde: return PrefixOpBinNot;
1424 case TokenIdAmpersand: return PrefixOpAddressOf;1425 case TokenIdAmpersand: return PrefixOpAddressOf;
1426 case TokenIdStar: return PrefixOpDereference;
1425 default: return PrefixOpInvalid;1427 default: return PrefixOpInvalid;
1426 }1428 }
1427}1429}
src/parser.hpp+1
...@@ -212,6 +212,7 @@ enum PrefixOp {...@@ -212,6 +212,7 @@ enum PrefixOp {
212 PrefixOpNegation,212 PrefixOpNegation,
213 PrefixOpAddressOf,213 PrefixOpAddressOf,
214 PrefixOpConstAddressOf,214 PrefixOpConstAddressOf,
215 PrefixOpDereference,
215};216};
216217
217struct AstNodePrefixOpExpr {218struct AstNodePrefixOpExpr {
test/run_tests.cpp+21-1
...@@ -755,6 +755,26 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -755,6 +755,26 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
755 }755 }
756 print_str("OK\n");756 print_str("OK\n");
757 return 0;757 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;
758}778}
759 )SOURCE", "OK\n");779 )SOURCE", "OK\n");
760}780}
...@@ -904,7 +924,7 @@ a_label:...@@ -904,7 +924,7 @@ a_label:
904fn f() {924fn f() {
905 3 = 3;925 3 = 3;
906}926}
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
909 add_compile_fail_case("assign to constant variable", R"SOURCE(929 add_compile_fail_case("assign to constant variable", R"SOURCE(
910fn f() {930fn f() {