| author | |
| committer | |
| log | 50357dad453845a69efff53370438dc29585dd17 |
| tree | e1a4ade250908bdc8690635d8cfe58c613a2f741 |
| parent | 9ce36ba0ccd5d7de076e688423862d315ef4233f |
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) |
| 144 | 144 | ||
| 145 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const))) | 145 | PrefixOp : token(Not) | token(Dash) | token(Tilde) | (token(Ampersand) option(token(Const))) |
| 146 | 146 | ||
| 147 | PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | token(Symbol) | Goto | BlockExpression | 147 | PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | BlockExpression | token(Symbol) | StructValueExpression |
| 148 | |||
| 149 | StructValueExpression : token(Type) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace) | ||
| 150 | |||
| 151 | StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression | ||
| 148 | 152 | ||
| 149 | Goto: token(Goto) token(Symbol) | 153 | Goto: token(Goto) token(Symbol) |
| 150 | 154 |
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 { |
| 21 | 21 | ||
| 22 | test_byval_assign(); | 22 | test_byval_assign(); |
| 23 | 23 | ||
| 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"); } |
| 79 | 81 | ||
| 80 | } | 82 | } |
| 83 | |||
| 84 | fn 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 |
| 1060 | enum LValPurpose { | 1066 | enum LValPurpose { |
| 1061 | LValPurposeAssign, | 1067 | LValPurposeAssign, |
| 1062 | LValPurposeAddressOf, | 1068 | LValPurposeAddressOf, |
| 1069 | LValPurposeNotLVal, | ||
| 1063 | }; | 1070 | }; |
| 1064 | 1071 | ||
| 1065 | static TypeTableEntry *analyze_lvalue(CodeGen *g, ImportTableEntry *import, BlockContext *block_context, | 1072 | static 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 | } |
| 1271 | 1278 | ||
| 1279 | static 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 | |||
| 1291 | static 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 | |||
| 1272 | static TypeTableEntry * analyze_expression(CodeGen *g, ImportTableEntry *import, BlockContext *context, | 1335 | static 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; |
| 18 | struct TypeTableEntry; | 18 | struct TypeTableEntry; |
| 19 | struct VariableTableEntry; | 19 | struct VariableTableEntry; |
| 20 | struct CastNode; | 20 | struct CastNode; |
| 21 | struct StructValExprNode; | ||
| 21 | 22 | ||
| 22 | struct TypeTableEntryPointer { | 23 | struct 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 root | 224 | 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 | }; |
| 228 | 230 | ||
| ... | @@ -292,6 +294,16 @@ struct VarDeclNode { | ... | @@ -292,6 +294,16 @@ struct VarDeclNode { |
| 292 | TypeTableEntry *type; | 294 | TypeTableEntry *type; |
| 293 | }; | 295 | }; |
| 294 | 296 | ||
| 297 | struct StructValFieldNode { | ||
| 298 | int index; | ||
| 299 | }; | ||
| 300 | |||
| 301 | struct StructValExprNode { | ||
| 302 | TypeTableEntry *type_entry; | ||
| 303 | LLVMValueRef ptr; | ||
| 304 | AstNode *source_node; | ||
| 305 | }; | ||
| 306 | |||
| 295 | struct CodeGenNode { | 307 | struct CodeGenNode { |
| 296 | union { | 308 | union { |
| 297 | TypeNode type_node; // for NodeTypeType | 309 | TypeNode type_node; // for NodeTypeType |
| ... | @@ -305,6 +317,8 @@ struct CodeGenNode { | ... | @@ -305,6 +317,8 @@ struct CodeGenNode { |
| 305 | CastNode cast_node; // for NodeTypeCastExpr | 317 | CastNode cast_node; // for NodeTypeCastExpr |
| 306 | NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral | 318 | NumberLiteralNode num_lit_node; // for NodeTypeNumberLiteral |
| 307 | VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration | 319 | 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 nodes | 323 | 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 | } |
| 659 | 659 | ||
| 660 | static 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 | |||
| 660 | static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { | 682 | static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) { |
| 661 | assert(node->type == NodeTypeBinOpExpr); | 683 | assert(node->type == NodeTypeBinOpExpr); |
| 662 | 684 | ||
| ... | @@ -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); |
| 677 | 699 | ||
| 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 | } |
| 694 | 702 | ||
| 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 | } |
| 972 | 980 | ||
| 981 | static 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 | |||
| 973 | static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) { | 1009 | static 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 | } | ||
| 999 | 1040 | ||
| 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); |
| 1037 | 1078 | ||
| 1038 | // TODO this is kinda iffy. make sure josh is on board with this | 1079 | // 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; |
| 1040 | 1081 | ||
| 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 | } |
| 1362 | 1414 | ||
| 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 | } |
| 346 | 362 | ||
| ... | @@ -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 | } |
| 1036 | 1052 | ||
| 1037 | /* | 1053 | /* |
| 1038 | PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | token(Symbol) | Goto | BlockExpression | 1054 | StructValueExpression : token(Symbol) token(LBrace) list(StructValueExpressionField, token(Comma)) token(RBrace) |
| 1055 | StructValueExpressionField : token(Dot) token(Symbol) token(Eq) Expression | ||
| 1056 | */ | ||
| 1057 | static 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 | /* | ||
| 1098 | PrimaryExpression : token(Number) | token(String) | KeywordLiteral | GroupedExpression | Goto | BlockExpression | token(Symbol) | StructValueExpression | ||
| 1039 | */ | 1099 | */ |
| 1040 | static AstNode *ast_parse_primary_expr(ParseContext *pc, int *token_index, bool mandatory) { | 1100 | static 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 | }; |
| 54 | 56 | ||
| 55 | struct AstNodeRoot { | 57 | struct AstNodeRoot { |
| ... | @@ -296,6 +298,16 @@ struct AstNodeNumberLiteral { | ... | @@ -296,6 +298,16 @@ struct AstNodeNumberLiteral { |
| 296 | } data; | 298 | } data; |
| 297 | }; | 299 | }; |
| 298 | 300 | ||
| 301 | struct AstNodeStructValueField { | ||
| 302 | Buf name; | ||
| 303 | AstNode *expr; | ||
| 304 | }; | ||
| 305 | |||
| 306 | struct AstNodeStructValueExpr { | ||
| 307 | AstNode *type; | ||
| 308 | ZigList<AstNode *> fields; | ||
| 309 | }; | ||
| 310 | |||
| 299 | struct AstNode { | 311 | struct 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; |
| 625 | 626 | ||
| 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 | } | ||
| 629 | fn 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"); |
| 629 | 634 |