authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-24 00:00:23-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2015-12-24 00:00:23-07:00
log50357dad453845a69efff53370438dc29585dd17
treee1a4ade250908bdc8690635d8cfe58c613a2f741
parent9ce36ba0ccd5d7de076e688423862d315ef4233f

add struct value expression


8 files changed, 255 insertions(+), 24 deletions(-)

doc/langref.md+5-1
......@@ -144,7 +144,11 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket)
144144
145145PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const)))
146146
147PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | token(Symbol) | Goto | BlockExpression
147PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | BlockExpression | token(Symbol) | StructValueExpression
148
149StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
150
151StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression
148152
149153Goto: token(Goto) token(Symbol)
150154
example/structs/structs.zig+7
......@@ -21,6 +21,8 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
2121
2222 test_byval_assign();
2323
24 test_initializer();
25
2426 print_str("OK\n");
2527 return 0;
2628}
......@@ -78,3 +80,8 @@ fn test_byval_assign() {
7880 if foo2.a != 1234 { print_str("BAD - byval assignment failed\n"); }
7981
8082}
83
84fn test_initializer() {
85 const val = Val { .x = 42 };
86 if val.x != 42 { print_str("BAD\n"); }
87}
src/analyze.cpp+69
......@@ -52,6 +52,8 @@ static AstNode *first_executing_node(AstNode *node) {
5252 case NodeTypeFieldAccessExpr:
5353 case NodeTypeStructDecl:
5454 case NodeTypeStructField:
55 case NodeTypeStructValueExpr:
56 case NodeTypeStructValueField:
5557 return node;
5658 }
5759 zig_panic("unreachable");
......@@ -529,6 +531,8 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
529531 case NodeTypeAsmExpr:
530532 case NodeTypeFieldAccessExpr:
531533 case NodeTypeStructField:
534 case NodeTypeStructValueExpr:
535 case NodeTypeStructValueField:
532536 zig_unreachable();
533537 }
534538}
......@@ -594,6 +598,8 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
594598 case NodeTypeAsmExpr:
595599 case NodeTypeFieldAccessExpr:
596600 case NodeTypeStructField:
601 case NodeTypeStructValueExpr:
602 case NodeTypeStructValueField:
597603 zig_unreachable();
598604 }
599605}
......@@ -1060,6 +1066,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
10601066enum LValPurpose {
10611067 LValPurposeAssign,
10621068 LValPurposeAddressOf,
1069 LValPurposeNotLVal,
10631070};
10641071
10651072static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,
......@@ -1269,6 +1276,62 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
12691276 }
12701277}
12711278
1279static TypeStructField *find_struct_type_field(TypeTableEntry *type_entry, Buf *name, int *index) {
1280 assert(type_entry->id == TypeTableEntryIdStruct);
1281 for (int i = 0; i < type_entry->data.structure.field_count; i += 1) {
1282 TypeStructField *field = &type_entry->data.structure.fields[i];
1283 if (buf_eql_buf(field->name, name)) {
1284 *index = i;
1285 return field;
1286 }
1287 }
1288 return nullptr;
1289}
1290
1291static TypeTableEntry *analyze_struct_val_expr(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1292 TypeTableEntry *expected_type, AstNode *node)
1293{
1294 assert(node->type == NodeTypeStructValueExpr);
1295
1296 AstNodeStructValueExpr *struct_val_expr = &node->data.struct_val_expr;
1297
1298 TypeTableEntry *type_entry = resolve_type(g, struct_val_expr->type);
1299
1300 if (type_entry->id == TypeTableEntryIdInvalid) {
1301 return g->builtin_types.entry_invalid;
1302 } else if (type_entry->id != TypeTableEntryIdStruct) {
1303 add_node_error(g, node,
1304 buf_sprintf("type '%s' is not a struct", buf_ptr(&type_entry->name)));
1305 return g->builtin_types.entry_invalid;
1306 }
1307
1308 assert(node->codegen_node);
1309 node->codegen_node->data.struct_val_expr_node.type_entry = type_entry;
1310 node->codegen_node->data.struct_val_expr_node.source_node = node;
1311 context->struct_val_expr_alloca_list.append(&node->codegen_node->data.struct_val_expr_node);
1312
1313 for (int i = 0; i < struct_val_expr->fields.length; i += 1) {
1314 AstNode *val_field_node = struct_val_expr->fields.at(i);
1315 int field_index;
1316 TypeStructField *type_field = find_struct_type_field(type_entry,
1317 &val_field_node->data.struct_val_field.name, &field_index);
1318
1319 if (!type_field) {
1320 add_node_error(g, val_field_node,
1321 buf_sprintf("type '%s' is not a struct", buf_ptr(&type_entry->name)));
1322 continue;
1323 }
1324
1325 alloc_codegen_node(val_field_node);
1326 val_field_node->codegen_node->data.struct_val_field_node.index = field_index;
1327
1328 analyze_expression(g, import, context, type_field->type_entry,
1329 val_field_node->data.struct_val_field.expr);
1330 }
1331
1332 return type_entry;
1333}
1334
12721335static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
12731336 TypeTableEntry *expected_type, AstNode *node)
12741337{
......@@ -1545,6 +1608,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
15451608 }
15461609 break;
15471610 }
1611 case NodeTypeStructValueExpr:
1612 return_type = analyze_struct_val_expr(g, import, context, expected_type, node);
1613 break;
15481614 case NodeTypeDirective:
15491615 case NodeTypeFnDecl:
15501616 case NodeTypeFnProto:
......@@ -1558,6 +1624,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
15581624 case NodeTypeLabel:
15591625 case NodeTypeStructDecl:
15601626 case NodeTypeStructField:
1627 case NodeTypeStructValueField:
15611628 zig_unreachable();
15621629 }
15631630 assert(return_type);
......@@ -1690,6 +1757,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
16901757 case NodeTypeAsmExpr:
16911758 case NodeTypeFieldAccessExpr:
16921759 case NodeTypeStructField:
1760 case NodeTypeStructValueExpr:
1761 case NodeTypeStructValueField:
16931762 zig_unreachable();
16941763 }
16951764}
src/analyze.hpp+14
......@@ -18,6 +18,7 @@ struct BlockContext;
1818struct TypeTableEntry;
1919struct VariableTableEntry;
2020struct CastNode;
21struct StructValExprNode;
2122
2223struct TypeTableEntryPointer {
2324 TypeTableEntry *child_type;
......@@ -223,6 +224,7 @@ struct BlockContext {
223224 BlockContext *parent; // null when this is the root
224225 HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
225226 ZigList<CastNode *> cast_expr_alloca_list;
227 ZigList<StructValExprNode *> struct_val_expr_alloca_list;
226228 LLVMZigDIScope *di_scope;
227229};
228230
......@@ -292,6 +294,16 @@ struct VarDeclNode {
292294 TypeTableEntry *type;
293295};
294296
297struct StructValFieldNode {
298 int index;
299};
300
301struct StructValExprNode {
302 TypeTableEntry *type_entry;
303 LLVMValueRef ptr;
304 AstNode *source_node;
305};
306
295307struct CodeGenNode {
296308 union {
297309 TypeNode type_node; // for NodeTypeType
......@@ -305,6 +317,8 @@ struct CodeGenNode {
305317 CastNode cast_node; // for NodeTypeCastExpr
306318 NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral
307319 VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration
320 StructValFieldNode struct_val_field_node; // for NodeTypeStructValueField
321 StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr
308322 } data;
309323 ExprNode expr_node; // for all the expression nodes
310324};
src/codegen.cpp+70-18
......@@ -657,6 +657,28 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
657657 return phi;
658658}
659659
660static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValueRef src, LLVMValueRef dest,
661 TypeTableEntry *type_entry)
662{
663 assert(type_entry->id == TypeTableEntryIdStruct);
664
665 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
666
667 add_debug_source_node(g, source_node);
668 LLVMValueRef src_ptr = LLVMBuildBitCast(g->builder, src, ptr_u8, "");
669 LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, dest, ptr_u8, "");
670
671 LLVMValueRef params[] = {
672 dest_ptr, // dest pointer
673 src_ptr, // source pointer
674 LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8), type_entry->size_in_bits / 8, false), // byte count
675 LLVMConstInt(LLVMInt32Type(), type_entry->align_in_bits / 8, false), // align in bytes
676 LLVMConstNull(LLVMInt1Type()), // is volatile
677 };
678
679 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
680}
681
660682static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
661683 assert(node->type == NodeTypeBinOpExpr);
662684
......@@ -675,21 +697,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
675697 assert(op1_type == op2_type);
676698 assert(node->data.bin_op_expr.bin_op == BinOpTypeAssign);
677699
678 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
679
680 add_debug_source_node(g, node);
681 LLVMValueRef src_ptr = LLVMBuildBitCast(g->builder, value, ptr_u8, "");
682 LLVMValueRef dest_ptr = LLVMBuildBitCast(g->builder, target_ref, ptr_u8, "");
683
684 LLVMValueRef params[] = {
685 dest_ptr, // dest pointer
686 src_ptr, // source pointer
687 LLVMConstInt(LLVMIntType(g->pointer_size_bytes * 8), op1_type->size_in_bits / 8, false), // byte count
688 LLVMConstInt(LLVMInt32Type(), op1_type->align_in_bits / 8, false), // align in bits
689 LLVMConstNull(LLVMInt1Type()), // is volatile
690 };
691
692 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
700 return gen_struct_memcpy(g, node, value, target_ref, op1_type);
693701 }
694702
695703 if (node->data.bin_op_expr.bin_op != BinOpTypeAssign) {
......@@ -970,6 +978,34 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
970978 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
971979}
972980
981static LLVMValueRef gen_struct_val_expr(CodeGen *g, AstNode *node) {
982 assert(node->type == NodeTypeStructValueExpr);
983
984 TypeTableEntry *type_entry = get_expr_type(node);
985
986 assert(type_entry->id == TypeTableEntryIdStruct);
987
988 int field_count = type_entry->data.structure.field_count;
989 assert(field_count == node->data.struct_val_expr.fields.length);
990
991 StructValExprNode *struct_val_expr_node = &node->codegen_node->data.struct_val_expr_node;
992 LLVMValueRef tmp_struct_ptr = struct_val_expr_node->ptr;
993
994 for (int i = 0; i < field_count; i += 1) {
995 AstNode *field_node = node->data.struct_val_expr.fields.at(i);
996 int index = field_node->codegen_node->data.struct_val_field_node.index;
997 TypeStructField *type_struct_field = &type_entry->data.structure.fields[index];
998 assert(buf_eql_buf(type_struct_field->name, &field_node->data.struct_val_field.name));
999
1000 add_debug_source_node(g, field_node);
1001 LLVMValueRef field_ptr = LLVMBuildStructGEP(g->builder, tmp_struct_ptr, index, "");
1002 LLVMValueRef value = gen_expr(g, field_node->data.struct_val_field.expr);
1003 LLVMBuildStore(g->builder, value, field_ptr);
1004 }
1005
1006 return tmp_struct_ptr;
1007}
1008
9731009static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
9741010 switch (node->type) {
9751011 case NodeTypeBinOpExpr:
......@@ -994,8 +1030,13 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
9941030 if (variable->type->id == TypeTableEntryIdVoid) {
9951031 return nullptr;
9961032 } else {
997 add_debug_source_node(g, node);
998 LLVMValueRef store_instr = LLVMBuildStore(g->builder, value, variable->value_ref);
1033 LLVMValueRef store_instr;
1034 if (variable->type->id == TypeTableEntryIdStruct && node->data.variable_declaration.expr) {
1035 store_instr = gen_struct_memcpy(g, node, value, variable->value_ref, variable->type);
1036 } else {
1037 add_debug_source_node(g, node);
1038 store_instr = LLVMBuildStore(g->builder, value, variable->value_ref);
1039 }
9991040
10001041 LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(node->line + 1, node->column + 1,
10011042 g->cur_block_context->di_scope);
......@@ -1035,7 +1076,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
10351076 TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
10361077 assert(type_entry);
10371078
1038 // TODO this is kinda iffy. make sure josh is on board with this
1079 // override the expression type for number literals
10391080 node->codegen_node->expr_node.type_entry = type_entry;
10401081
10411082 if (type_entry->id == TypeTableEntryIdInt) {
......@@ -1104,6 +1145,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
11041145 LLVMPositionBuilderAtEnd(g->builder, basic_block);
11051146 return nullptr;
11061147 }
1148 case NodeTypeStructValueExpr:
1149 return gen_struct_val_expr(g, node);
11071150 case NodeTypeRoot:
11081151 case NodeTypeRootExportDecl:
11091152 case NodeTypeFnProto:
......@@ -1116,6 +1159,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
11161159 case NodeTypeUse:
11171160 case NodeTypeStructDecl:
11181161 case NodeTypeStructField:
1162 case NodeTypeStructValueField:
11191163 zig_unreachable();
11201164 }
11211165 zig_unreachable();
......@@ -1358,6 +1402,14 @@ static void do_code_gen(CodeGen *g) {
13581402 add_debug_source_node(g, cast_node->source_node);
13591403 cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->type->type_ref, "");
13601404 }
1405
1406 // allocate structs which are struct value expressions
1407 for (int alloca_i = 0; alloca_i < block_context->struct_val_expr_alloca_list.length; alloca_i += 1) {
1408 StructValExprNode *struct_val_expr_node = block_context->struct_val_expr_alloca_list.at(alloca_i);
1409 add_debug_source_node(g, struct_val_expr_node->source_node);
1410 struct_val_expr_node->ptr = LLVMBuildAlloca(g->builder,
1411 struct_val_expr_node->type_entry->type_ref, "");
1412 }
13611413 }
13621414
13631415 TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type;
src/parser.cpp+71-5
......@@ -128,6 +128,10 @@ const char *node_type_str(NodeType node_type) {
128128 return "StructDecl";
129129 case NodeTypeStructField:
130130 return "StructField";
131 case NodeTypeStructValueExpr:
132 return "StructValueExpr";
133 case NodeTypeStructValueField:
134 return "StructValueField";
131135 }
132136 zig_unreachable();
133137}
......@@ -341,6 +345,18 @@ void ast_print(AstNode *node, int indent) {
341345 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_field.name));
342346 ast_print(node->data.struct_field.type, indent + 2);
343347 break;
348 case NodeTypeStructValueExpr:
349 fprintf(stderr, "%s\n", node_type_str(node->type));
350 ast_print(node->data.struct_val_expr.type, indent + 2);
351 for (int i = 0; i < node->data.struct_val_expr.fields.length; i += 1) {
352 AstNode *child = node->data.struct_val_expr.fields.at(i);
353 ast_print(child, indent + 2);
354 }
355 break;
356 case NodeTypeStructValueField:
357 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_val_field.name));
358 ast_print(node->data.struct_val_field.expr, indent + 2);
359 break;
344360 }
345361}
346362
......@@ -1035,7 +1051,51 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool
10351051}
10361052
10371053/*
1038PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | token(Symbol) | Goto | BlockExpression
1054StructValueExpression : token(Symbol) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace)
1055StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression
1056*/
1057static AstNode *ast_parse_struct_val_expr(ParseContext *pc, int *token_index) {
1058 Token *first_token = &pc->tokens->at(*token_index);
1059 AstNode *node = ast_create_node(pc, NodeTypeStructValueExpr, first_token);
1060
1061 node->data.struct_val_expr.type = ast_parse_type(pc, token_index);
1062
1063 ast_eat_token(pc, token_index, TokenIdLBrace);
1064
1065 for (;;) {
1066 Token *token = &pc->tokens->at(*token_index);
1067 *token_index += 1;
1068
1069 if (token->id == TokenIdRBrace) {
1070 return node;
1071 } else if (token->id == TokenIdDot) {
1072 Token *field_name_tok = ast_eat_token(pc, token_index, TokenIdSymbol);
1073 ast_eat_token(pc, token_index, TokenIdEq);
1074
1075 AstNode *field_node = ast_create_node(pc, NodeTypeStructValueField, token);
1076
1077 ast_buf_from_token(pc, field_name_tok, &field_node->data.struct_val_field.name);
1078 field_node->data.struct_val_field.expr = ast_parse_expression(pc, token_index, true);
1079
1080 node->data.struct_val_expr.fields.append(field_node);
1081
1082 Token *comma_tok = &pc->tokens->at(*token_index);
1083 if (comma_tok->id == TokenIdComma) {
1084 *token_index += 1;
1085 } else if (comma_tok->id != TokenIdRBrace) {
1086 ast_invalid_token_error(pc, comma_tok);
1087 } else {
1088 *token_index += 1;
1089 return node;
1090 }
1091 } else {
1092 ast_invalid_token_error(pc, token);
1093 }
1094 }
1095}
1096
1097/*
1098PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | BlockExpression | token(Symbol) | StructValueExpression
10391099*/
10401100static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
10411101 Token *token = &pc->tokens->at(*token_index);
......@@ -1069,10 +1129,16 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
10691129 *token_index += 1;
10701130 return node;
10711131 } else if (token->id == TokenIdSymbol) {
1072 AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
1073 ast_buf_from_token(pc, token, &node->data.symbol);
1074 *token_index += 1;
1075 return node;
1132 Token *next_token = &pc->tokens->at(*token_index + 1);
1133
1134 if (next_token->id == TokenIdLBrace) {
1135 return ast_parse_struct_val_expr(pc, token_index);
1136 } else {
1137 *token_index += 1;
1138 AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);
1139 ast_buf_from_token(pc, token, &node->data.symbol);
1140 return node;
1141 }
10761142 } else if (token->id == TokenIdKeywordGoto) {
10771143 AstNode *node = ast_create_node(pc, NodeTypeGoto, token);
10781144 *token_index += 1;
src/parser.hpp+14
......@@ -50,6 +50,8 @@ enum NodeType {
5050 NodeTypeAsmExpr,
5151 NodeTypeStructDecl,
5252 NodeTypeStructField,
53 NodeTypeStructValueExpr,
54 NodeTypeStructValueField,
5355};
5456
5557struct AstNodeRoot {
......@@ -296,6 +298,16 @@ struct AstNodeNumberLiteral {
296298 } data;
297299};
298300
301struct AstNodeStructValueField {
302 Buf name;
303 AstNode *expr;
304};
305
306struct AstNodeStructValueExpr {
307 AstNode *type;
308 ZigList<AstNode *> fields;
309};
310
299311struct AstNode {
300312 enum NodeType type;
301313 int line;
......@@ -330,6 +342,8 @@ struct AstNode {
330342 AstNodeStructField struct_field;
331343 AstNodeStringLiteral string_literal;
332344 AstNodeNumberLiteral number_literal;
345 AstNodeStructValueExpr struct_val_expr;
346 AstNodeStructValueField struct_val_field;
333347 Buf symbol;
334348 bool bool_literal;
335349 } data;
test/run_tests.cpp+5
......@@ -575,6 +575,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
575575 }
576576 test_point_to_self();
577577 test_byval_assign();
578 test_initializer();
578579 print_str("OK\n");
579580 return 0;
580581}
......@@ -624,6 +625,10 @@ fn test_byval_assign() {
624625 foo2 = foo1;
625626
626627 if foo2.a != 1234 { print_str("BAD - byval assignment failed\n"); }
628}
629fn test_initializer() {
630 const val = Val { .x = 42 };
631 if val.x != 42 { print_str("BAD\n"); }
627632}
628633 )SOURCE", "OK\n");
629634