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)...@@ -144,7 +144,11 @@ ArrayAccessExpression : token(LBracket) Expression token(RBracket)
144144
145PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const)))145PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const)))
146146
147PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | token(Symbol) | Goto | BlockExpression147PrimaryExpression : 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
149Goto: token(Goto) token(Symbol)153Goto: token(Goto) token(Symbol)
150154
example/structs/structs.zig+7
...@@ -21,6 +21,8 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -21,6 +21,8 @@ pub fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
2121
22 test_byval_assign();22 test_byval_assign();
2323
24 test_initializer();
25
24 print_str("OK\n");26 print_str("OK\n");
25 return 0;27 return 0;
26}28}
...@@ -78,3 +80,8 @@ fn test_byval_assign() {...@@ -78,3 +80,8 @@ fn test_byval_assign() {
78 if foo2.a != 1234 { print_str("BAD - byval assignment failed\n"); }80 if foo2.a != 1234 { print_str("BAD - byval assignment failed\n"); }
7981
80}82}
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) {...@@ -52,6 +52,8 @@ static AstNode *first_executing_node(AstNode *node) {
52 case NodeTypeFieldAccessExpr:52 case NodeTypeFieldAccessExpr:
53 case NodeTypeStructDecl:53 case NodeTypeStructDecl:
54 case NodeTypeStructField:54 case NodeTypeStructField:
55 case NodeTypeStructValueExpr:
56 case NodeTypeStructValueField:
55 return node;57 return node;
56 }58 }
57 zig_panic("unreachable");59 zig_panic("unreachable");
...@@ -529,6 +531,8 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,...@@ -529,6 +531,8 @@ static void preview_function_declarations(CodeGen *g, ImportTableEntry *import,
529 case NodeTypeAsmExpr:531 case NodeTypeAsmExpr:
530 case NodeTypeFieldAccessExpr:532 case NodeTypeFieldAccessExpr:
531 case NodeTypeStructField:533 case NodeTypeStructField:
534 case NodeTypeStructValueExpr:
535 case NodeTypeStructValueField:
532 zig_unreachable();536 zig_unreachable();
533 }537 }
534}538}
...@@ -594,6 +598,8 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {...@@ -594,6 +598,8 @@ static void preview_types(CodeGen *g, ImportTableEntry *import, AstNode *node) {
594 case NodeTypeAsmExpr:598 case NodeTypeAsmExpr:
595 case NodeTypeFieldAccessExpr:599 case NodeTypeFieldAccessExpr:
596 case NodeTypeStructField:600 case NodeTypeStructField:
601 case NodeTypeStructValueExpr:
602 case NodeTypeStructValueField:
597 zig_unreachable();603 zig_unreachable();
598 }604 }
599}605}
...@@ -1060,6 +1066,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B...@@ -1060,6 +1066,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
1060enum LValPurpose {1066enum LValPurpose {
1061 LValPurposeAssign,1067 LValPurposeAssign,
1062 LValPurposeAddressOf,1068 LValPurposeAddressOf,
1069 LValPurposeNotLVal,
1063};1070};
10641071
1065static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,1072static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, BlockContext *block_context,
...@@ -1269,6 +1276,62 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry...@@ -1269,6 +1276,62 @@ static TypeTableEntry *analyze_number_literal_expr(CodeGen *g, ImportTableEntry
1269 }1276 }
1270}1277}
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
1272static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,1335static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context,
1273 TypeTableEntry *expected_type, AstNode *node)1336 TypeTableEntry *expected_type, AstNode *node)
1274{1337{
...@@ -1545,6 +1608,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1545,6 +1608,9 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1545 }1608 }
1546 break;1609 break;
1547 }1610 }
1611 case NodeTypeStructValueExpr:
1612 return_type = analyze_struct_val_expr(g, import, context, expected_type, node);
1613 break;
1548 case NodeTypeDirective:1614 case NodeTypeDirective:
1549 case NodeTypeFnDecl:1615 case NodeTypeFnDecl:
1550 case NodeTypeFnProto:1616 case NodeTypeFnProto:
...@@ -1558,6 +1624,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,...@@ -1558,6 +1624,7 @@ static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import,
1558 case NodeTypeLabel:1624 case NodeTypeLabel:
1559 case NodeTypeStructDecl:1625 case NodeTypeStructDecl:
1560 case NodeTypeStructField:1626 case NodeTypeStructField:
1627 case NodeTypeStructValueField:
1561 zig_unreachable();1628 zig_unreachable();
1562 }1629 }
1563 assert(return_type);1630 assert(return_type);
...@@ -1690,6 +1757,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,...@@ -1690,6 +1757,8 @@ static void analyze_top_level_declaration(CodeGen *g, ImportTableEntry *import,
1690 case NodeTypeAsmExpr:1757 case NodeTypeAsmExpr:
1691 case NodeTypeFieldAccessExpr:1758 case NodeTypeFieldAccessExpr:
1692 case NodeTypeStructField:1759 case NodeTypeStructField:
1760 case NodeTypeStructValueExpr:
1761 case NodeTypeStructValueField:
1693 zig_unreachable();1762 zig_unreachable();
1694 }1763 }
1695}1764}
src/analyze.hpp+14
...@@ -18,6 +18,7 @@ struct BlockContext;...@@ -18,6 +18,7 @@ struct BlockContext;
18struct TypeTableEntry;18struct TypeTableEntry;
19struct VariableTableEntry;19struct VariableTableEntry;
20struct CastNode;20struct CastNode;
21struct StructValExprNode;
2122
22struct TypeTableEntryPointer {23struct TypeTableEntryPointer {
23 TypeTableEntry *child_type;24 TypeTableEntry *child_type;
...@@ -223,6 +224,7 @@ struct BlockContext {...@@ -223,6 +224,7 @@ struct BlockContext {
223 BlockContext *parent; // null when this is the root224 BlockContext *parent; // null when this is the root
224 HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;225 HashMap<Buf *, VariableTableEntry *, buf_hash, buf_eql_buf> variable_table;
225 ZigList<CastNode *> cast_expr_alloca_list;226 ZigList<CastNode *> cast_expr_alloca_list;
227 ZigList<StructValExprNode *> struct_val_expr_alloca_list;
226 LLVMZigDIScope *di_scope;228 LLVMZigDIScope *di_scope;
227};229};
228230
...@@ -292,6 +294,16 @@ struct VarDeclNode {...@@ -292,6 +294,16 @@ struct VarDeclNode {
292 TypeTableEntry *type;294 TypeTableEntry *type;
293};295};
294296
297struct StructValFieldNode {
298 int index;
299};
300
301struct StructValExprNode {
302 TypeTableEntry *type_entry;
303 LLVMValueRef ptr;
304 AstNode *source_node;
305};
306
295struct CodeGenNode {307struct CodeGenNode {
296 union {308 union {
297 TypeNode type_node; // for NodeTypeType309 TypeNode type_node; // for NodeTypeType
...@@ -305,6 +317,8 @@ struct CodeGenNode {...@@ -305,6 +317,8 @@ struct CodeGenNode {
305 CastNode cast_node; // for NodeTypeCastExpr317 CastNode cast_node; // for NodeTypeCastExpr
306 NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral318 NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral
307 VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration319 VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration
320 StructValFieldNode struct_val_field_node; // for NodeTypeStructValueField
321 StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr
308 } data;322 } data;
309 ExprNode expr_node; // for all the expression nodes323 ExprNode expr_node; // for all the expression nodes
310};324};
src/codegen.cpp+70-18
...@@ -657,6 +657,28 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {...@@ -657,6 +657,28 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
657 return phi;657 return phi;
658}658}
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
660static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {682static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
661 assert(node->type == NodeTypeBinOpExpr);683 assert(node->type == NodeTypeBinOpExpr);
662684
...@@ -675,21 +697,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {...@@ -675,21 +697,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
675 assert(op1_type == op2_type);697 assert(op1_type == op2_type);
676 assert(node->data.bin_op_expr.bin_op == BinOpTypeAssign);698 assert(node->data.bin_op_expr.bin_op == BinOpTypeAssign);
677699
678 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);700 return gen_struct_memcpy(g, node, value, target_ref, op1_type);
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, "");
693 }701 }
694702
695 if (node->data.bin_op_expr.bin_op != BinOpTypeAssign) {703 if (node->data.bin_op_expr.bin_op != BinOpTypeAssign) {
...@@ -970,6 +978,34 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {...@@ -970,6 +978,34 @@ static LLVMValueRef gen_asm_expr(CodeGen *g, AstNode *node) {
970 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");978 return LLVMBuildCall(g->builder, asm_fn, param_values, input_and_output_count, "");
971}979}
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
973static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {1009static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
974 switch (node->type) {1010 switch (node->type) {
975 case NodeTypeBinOpExpr:1011 case NodeTypeBinOpExpr:
...@@ -994,8 +1030,13 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -994,8 +1030,13 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
994 if (variable->type->id == TypeTableEntryIdVoid) {1030 if (variable->type->id == TypeTableEntryIdVoid) {
995 return nullptr;1031 return nullptr;
996 } else {1032 } else {
997 add_debug_source_node(g, node);1033 LLVMValueRef store_instr;
998 LLVMValueRef store_instr = LLVMBuildStore(g->builder, value, variable->value_ref);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
1000 LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(node->line + 1, node->column + 1,1041 LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(node->line + 1, node->column + 1,
1001 g->cur_block_context->di_scope);1042 g->cur_block_context->di_scope);
...@@ -1035,7 +1076,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1035,7 +1076,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1035 TypeTableEntry *type_entry = codegen_num_lit->resolved_type;1076 TypeTableEntry *type_entry = codegen_num_lit->resolved_type;
1036 assert(type_entry);1077 assert(type_entry);
10371078
1038 // TODO this is kinda iffy. make sure josh is on board with this1079 // override the expression type for number literals
1039 node->codegen_node->expr_node.type_entry = type_entry;1080 node->codegen_node->expr_node.type_entry = type_entry;
10401081
1041 if (type_entry->id == TypeTableEntryIdInt) {1082 if (type_entry->id == TypeTableEntryIdInt) {
...@@ -1104,6 +1145,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1104,6 +1145,8 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1104 LLVMPositionBuilderAtEnd(g->builder, basic_block);1145 LLVMPositionBuilderAtEnd(g->builder, basic_block);
1105 return nullptr;1146 return nullptr;
1106 }1147 }
1148 case NodeTypeStructValueExpr:
1149 return gen_struct_val_expr(g, node);
1107 case NodeTypeRoot:1150 case NodeTypeRoot:
1108 case NodeTypeRootExportDecl:1151 case NodeTypeRootExportDecl:
1109 case NodeTypeFnProto:1152 case NodeTypeFnProto:
...@@ -1116,6 +1159,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1116,6 +1159,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1116 case NodeTypeUse:1159 case NodeTypeUse:
1117 case NodeTypeStructDecl:1160 case NodeTypeStructDecl:
1118 case NodeTypeStructField:1161 case NodeTypeStructField:
1162 case NodeTypeStructValueField:
1119 zig_unreachable();1163 zig_unreachable();
1120 }1164 }
1121 zig_unreachable();1165 zig_unreachable();
...@@ -1358,6 +1402,14 @@ static void do_code_gen(CodeGen *g) {...@@ -1358,6 +1402,14 @@ static void do_code_gen(CodeGen *g) {
1358 add_debug_source_node(g, cast_node->source_node);1402 add_debug_source_node(g, cast_node->source_node);
1359 cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->type->type_ref, "");1403 cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->type->type_ref, "");
1360 }1404 }
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 }
1361 }1413 }
13621414
1363 TypeTableEntry *implicit_return_type = codegen_fn_def->implicit_return_type;1415 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) {...@@ -128,6 +128,10 @@ const char *node_type_str(NodeType node_type) {
128 return "StructDecl";128 return "StructDecl";
129 case NodeTypeStructField:129 case NodeTypeStructField:
130 return "StructField";130 return "StructField";
131 case NodeTypeStructValueExpr:
132 return "StructValueExpr";
133 case NodeTypeStructValueField:
134 return "StructValueField";
131 }135 }
132 zig_unreachable();136 zig_unreachable();
133}137}
...@@ -341,6 +345,18 @@ void ast_print(AstNode *node, int indent) {...@@ -341,6 +345,18 @@ void ast_print(AstNode *node, int indent) {
341 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_field.name));345 fprintf(stderr, "%s '%s'\n", node_type_str(node->type), buf_ptr(&node->data.struct_field.name));
342 ast_print(node->data.struct_field.type, indent + 2);346 ast_print(node->data.struct_field.type, indent + 2);
343 break;347 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;
344 }360 }
345}361}
346362
...@@ -1035,7 +1051,51 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool...@@ -1035,7 +1051,51 @@ static AstNode *ast_parse_grouped_expr(ParseContext *pc, int *token_index, bool
1035}1051}
10361052
1037/*1053/*
1038PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | token(Symbol) | Goto | BlockExpression1054StructValueExpression : 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
1039*/1099*/
1040static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {1100static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) {
1041 Token *token = &pc->tokens->at(*token_index);1101 Token *token = &pc->tokens->at(*token_index);
...@@ -1069,10 +1129,16 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool...@@ -1069,10 +1129,16 @@ static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool
1069 *token_index += 1;1129 *token_index += 1;
1070 return node;1130 return node;
1071 } else if (token->id == TokenIdSymbol) {1131 } else if (token->id == TokenIdSymbol) {
1072 AstNode *node = ast_create_node(pc, NodeTypeSymbol, token);1132 Token *next_token = &pc->tokens->at(*token_index + 1);
1073 ast_buf_from_token(pc, token, &node->data.symbol);1133
1074 *token_index += 1;1134 if (next_token->id == TokenIdLBrace) {
1075 return node;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 }
1076 } else if (token->id == TokenIdKeywordGoto) {1142 } else if (token->id == TokenIdKeywordGoto) {
1077 AstNode *node = ast_create_node(pc, NodeTypeGoto, token);1143 AstNode *node = ast_create_node(pc, NodeTypeGoto, token);
1078 *token_index += 1;1144 *token_index += 1;
src/parser.hpp+14
...@@ -50,6 +50,8 @@ enum NodeType {...@@ -50,6 +50,8 @@ enum NodeType {
50 NodeTypeAsmExpr,50 NodeTypeAsmExpr,
51 NodeTypeStructDecl,51 NodeTypeStructDecl,
52 NodeTypeStructField,52 NodeTypeStructField,
53 NodeTypeStructValueExpr,
54 NodeTypeStructValueField,
53};55};
5456
55struct AstNodeRoot {57struct AstNodeRoot {
...@@ -296,6 +298,16 @@ struct AstNodeNumberLiteral {...@@ -296,6 +298,16 @@ struct AstNodeNumberLiteral {
296 } data;298 } data;
297};299};
298300
301struct AstNodeStructValueField {
302 Buf name;
303 AstNode *expr;
304};
305
306struct AstNodeStructValueExpr {
307 AstNode *type;
308 ZigList<AstNode *> fields;
309};
310
299struct AstNode {311struct AstNode {
300 enum NodeType type;312 enum NodeType type;
301 int line;313 int line;
...@@ -330,6 +342,8 @@ struct AstNode {...@@ -330,6 +342,8 @@ struct AstNode {
330 AstNodeStructField struct_field;342 AstNodeStructField struct_field;
331 AstNodeStringLiteral string_literal;343 AstNodeStringLiteral string_literal;
332 AstNodeNumberLiteral number_literal;344 AstNodeNumberLiteral number_literal;
345 AstNodeStructValueExpr struct_val_expr;
346 AstNodeStructValueField struct_val_field;
333 Buf symbol;347 Buf symbol;
334 bool bool_literal;348 bool bool_literal;
335 } data;349 } data;
test/run_tests.cpp+5
...@@ -575,6 +575,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -575,6 +575,7 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
575 }575 }
576 test_point_to_self();576 test_point_to_self();
577 test_byval_assign();577 test_byval_assign();
578 test_initializer();
578 print_str("OK\n");579 print_str("OK\n");
579 return 0;580 return 0;
580}581}
...@@ -624,6 +625,10 @@ fn test_byval_assign() {...@@ -624,6 +625,10 @@ fn test_byval_assign() {
624 foo2 = foo1;625 foo2 = foo1;
625626
626 if foo2.a != 1234 { print_str("BAD - byval assignment failed\n"); }627 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"); }
627}632}
628 )SOURCE", "OK\n");633 )SOURCE", "OK\n");
629634