authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-02 00:06:06-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2016-01-02 00:06:06-07:00
log9a8851515b8aeac1adcea38094a45e3260e7522c
treedc1671648ae9ce7ab065ca36e012c4625c2880b0
parentb3ac5c16ecc8dd9da661dcb9d15a6c36a8e4167b

basic maybe type working


6 files changed, 267 insertions(+), 100 deletions(-)

doc/vim/syntax/zig.vim+1-1
...@@ -19,7 +19,7 @@ syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128...@@ -19,7 +19,7 @@ syn keyword zigType bool i8 u8 i16 u16 i32 u32 i64 u64 isize usize f32 f64 f128
1919
20syn keyword zigBoolean true false20syn keyword zigBoolean true false
2121
22syn match zigOperator display "\%(+\|-\|/\|*\|=\|\^\|&\||\|!\|>\|<\|%\)=\?"22syn match zigOperator display "\%(+\|-\|/\|*\|=\|\^\|&\|?\||\|!\|>\|<\|%\)=\?"
23syn match zigOperator display "&&\|||"23syn match zigOperator display "&&\|||"
24syn match zigArrowCharacter display "->"24syn match zigArrowCharacter display "->"
2525
example/maybe_type/main.zig+1-1
...@@ -2,7 +2,7 @@ export executable "maybe_type";...@@ -2,7 +2,7 @@ export executable "maybe_type";
22
3use "std.zig";3use "std.zig";
44
5fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {5pub fn main(argc: isize, argv: &&u8, env: &&u8) -> i32 {
6 const x : ?bool = true;6 const x : ?bool = true;
77
8 if (const y ?= x) {8 if (const y ?= x) {
src/analyze.cpp+61-7
...@@ -137,13 +137,44 @@ static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {...@@ -137,13 +137,44 @@ static TypeTableEntry *get_maybe_type(CodeGen *g, TypeTableEntry *child_type) {
137 return child_type->maybe_parent;137 return child_type->maybe_parent;
138 } else {138 } else {
139 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);139 TypeTableEntry *entry = new_type_table_entry(TypeTableEntryIdMaybe);
140 // TODO entry->type_ref140 // create a struct with a boolean whether this is the null value
141 assert(child_type->type_ref);
142 LLVMTypeRef elem_types[] = {
143 child_type->type_ref,
144 LLVMInt1Type(),
145 };
146 entry->type_ref = LLVMStructType(elem_types, 2, false);
141 buf_resize(&entry->name, 0);147 buf_resize(&entry->name, 0);
142 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));148 buf_appendf(&entry->name, "?%s", buf_ptr(&child_type->name));
143 // TODO entry->size_in_bits149 entry->size_in_bits = child_type->size_in_bits + 8;
144 // TODO entry->align_in_bits150 entry->align_in_bits = child_type->align_in_bits;
145 assert(child_type->di_type);151 assert(child_type->di_type);
146 // TODO entry->di_type152
153
154 LLVMZigDIScope *compile_unit_scope = LLVMZigCompileUnitToScope(g->compile_unit);
155 LLVMZigDIFile *di_file = nullptr;
156 unsigned line = 0;
157 entry->di_type = LLVMZigCreateReplaceableCompositeType(g->dbuilder,
158 LLVMZigTag_DW_structure_type(), buf_ptr(&entry->name),
159 compile_unit_scope, di_file, line);
160
161 LLVMZigDIType *di_element_types[] = {
162 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
163 "val", di_file, line, child_type->size_in_bits, child_type->align_in_bits, 0, 0,
164 child_type->di_type),
165 LLVMZigCreateDebugMemberType(g->dbuilder, LLVMZigTypeToScope(entry->di_type),
166 "maybe", di_file, line, 8, 8, 8, 0,
167 child_type->di_type),
168 };
169 LLVMZigDIType *replacement_di_type = LLVMZigCreateDebugStructType(g->dbuilder,
170 compile_unit_scope,
171 buf_ptr(&entry->name),
172 di_file, line, entry->size_in_bits, entry->align_in_bits, 0,
173 nullptr, di_element_types, 2, 0, nullptr, "");
174
175 LLVMZigReplaceTemporary(g->dbuilder, entry->di_type, replacement_di_type);
176 entry->di_type = replacement_di_type;
177
147 entry->data.maybe.child_type = child_type;178 entry->data.maybe.child_type = child_type;
148179
149 g->type_table.put(&entry->name, entry);180 g->type_table.put(&entry->name, entry);
...@@ -814,13 +845,35 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont...@@ -814,13 +845,35 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
814 return expected_type;845 return expected_type;
815 }846 }
816847
848 if (expected_type->id == TypeTableEntryIdMaybe &&
849 actual_type->id == TypeTableEntryIdMaybe)
850 {
851 TypeTableEntry *expected_child = expected_type->data.maybe.child_type;
852 TypeTableEntry *actual_child = actual_type->data.maybe.child_type;
853 return resolve_type_compatibility(g, context, node, expected_child, actual_child);
854 }
855
856 // implicit conversion from non maybe type to maybe type
857 if (expected_type->id == TypeTableEntryIdMaybe) {
858 TypeTableEntry *resolved_type = resolve_type_compatibility(g, context, node,
859 expected_type->data.maybe.child_type, actual_type);
860 if (resolved_type->id == TypeTableEntryIdInvalid) {
861 return resolved_type;
862 }
863 node->codegen_node->expr_node.implicit_maybe_cast.op = CastOpMaybeWrap;
864 node->codegen_node->expr_node.implicit_maybe_cast.after_type = expected_type;
865 node->codegen_node->expr_node.implicit_maybe_cast.source_node = node;
866 context->cast_expr_alloca_list.append(&node->codegen_node->expr_node.implicit_maybe_cast);
867 return expected_type;
868 }
869
817 // implicit widening conversion870 // implicit widening conversion
818 if (expected_type->id == TypeTableEntryIdInt &&871 if (expected_type->id == TypeTableEntryIdInt &&
819 actual_type->id == TypeTableEntryIdInt &&872 actual_type->id == TypeTableEntryIdInt &&
820 expected_type->data.integral.is_signed == actual_type->data.integral.is_signed &&873 expected_type->data.integral.is_signed == actual_type->data.integral.is_signed &&
821 expected_type->size_in_bits > actual_type->size_in_bits)874 expected_type->size_in_bits > actual_type->size_in_bits)
822 {875 {
823 node->codegen_node->expr_node.implicit_cast.type = expected_type;876 node->codegen_node->expr_node.implicit_cast.after_type = expected_type;
824 node->codegen_node->expr_node.implicit_cast.op = CastOpIntWidenOrShorten;877 node->codegen_node->expr_node.implicit_cast.op = CastOpIntWidenOrShorten;
825 node->codegen_node->expr_node.implicit_cast.source_node = node;878 node->codegen_node->expr_node.implicit_cast.source_node = node;
826 return expected_type;879 return expected_type;
...@@ -831,7 +884,7 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont...@@ -831,7 +884,7 @@ static TypeTableEntry *resolve_type_compatibility(CodeGen *g, BlockContext *cont
831 actual_type->id == TypeTableEntryIdArray &&884 actual_type->id == TypeTableEntryIdArray &&
832 actual_type->data.array.child_type == g->builtin_types.entry_u8)885 actual_type->data.array.child_type == g->builtin_types.entry_u8)
833 {886 {
834 node->codegen_node->expr_node.implicit_cast.type = expected_type;887 node->codegen_node->expr_node.implicit_cast.after_type = expected_type;
835 node->codegen_node->expr_node.implicit_cast.op = CastOpArrayToString;888 node->codegen_node->expr_node.implicit_cast.op = CastOpArrayToString;
836 node->codegen_node->expr_node.implicit_cast.source_node = node;889 node->codegen_node->expr_node.implicit_cast.source_node = node;
837 context->cast_expr_alloca_list.append(&node->codegen_node->expr_node.implicit_cast);890 context->cast_expr_alloca_list.append(&node->codegen_node->expr_node.implicit_cast);
...@@ -1077,7 +1130,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B...@@ -1077,7 +1130,7 @@ static TypeTableEntry *analyze_cast_expr(CodeGen *g, ImportTableEntry *import, B
10771130
1078 CastNode *cast_node = &node->codegen_node->data.cast_node;1131 CastNode *cast_node = &node->codegen_node->data.cast_node;
1079 cast_node->source_node = node;1132 cast_node->source_node = node;
1080 cast_node->type = wanted_type;1133 cast_node->after_type = wanted_type;
10811134
1082 // special casing this for now, TODO think about casting and do a general solution1135 // special casing this for now, TODO think about casting and do a general solution
1083 if (wanted_type == g->builtin_types.entry_isize &&1136 if (wanted_type == g->builtin_types.entry_isize &&
...@@ -1489,6 +1542,7 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,...@@ -1489,6 +1542,7 @@ static TypeTableEntry *analyze_if_var_expr(CodeGen *g, ImportTableEntry *import,
1489 assert(node->type == NodeTypeIfVarExpr);1542 assert(node->type == NodeTypeIfVarExpr);
14901543
1491 BlockContext *child_context = new_block_context(node, context);1544 BlockContext *child_context = new_block_context(node, context);
1545 node->codegen_node->data.if_var_node.block_context = child_context;
14921546
1493 analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true);1547 analyze_variable_declaration_raw(g, import, child_context, node, &node->data.if_var_expr.var_decl, true);
14941548
src/analyze.hpp+10-3
...@@ -272,10 +272,11 @@ struct FieldAccessNode {...@@ -272,10 +272,11 @@ struct FieldAccessNode {
272};272};
273273
274enum CastOp {274enum CastOp {
275 CastOpNothing,
275 CastOpPtrToInt,276 CastOpPtrToInt,
276 CastOpIntWidenOrShorten,277 CastOpIntWidenOrShorten,
277 CastOpArrayToString,278 CastOpArrayToString,
278 CastOpNothing,279 CastOpMaybeWrap,
279};280};
280281
281struct CastNode {282struct CastNode {
...@@ -283,7 +284,7 @@ struct CastNode {...@@ -283,7 +284,7 @@ struct CastNode {
283 // if op is CastOpArrayToString, this will be a pointer to284 // if op is CastOpArrayToString, this will be a pointer to
284 // the string struct on the stack285 // the string struct on the stack
285 LLVMValueRef ptr;286 LLVMValueRef ptr;
286 TypeTableEntry *type;287 TypeTableEntry *after_type;
287 AstNode *source_node;288 AstNode *source_node;
288};289};
289290
...@@ -294,7 +295,8 @@ struct ExprNode {...@@ -294,7 +295,8 @@ struct ExprNode {
294 BlockContext *block_context;295 BlockContext *block_context;
295296
296 // may be null for no cast297 // may be null for no cast
297 CastNode implicit_cast;298 CastNode implicit_cast; // happens first
299 CastNode implicit_maybe_cast; // happens second
298};300};
299301
300struct NumberLiteralNode {302struct NumberLiteralNode {
...@@ -315,6 +317,10 @@ struct StructValExprNode {...@@ -315,6 +317,10 @@ struct StructValExprNode {
315 AstNode *source_node;317 AstNode *source_node;
316};318};
317319
320struct IfVarNode {
321 BlockContext *block_context;
322};
323
318struct CodeGenNode {324struct CodeGenNode {
319 union {325 union {
320 TypeNode type_node; // for NodeTypeType326 TypeNode type_node; // for NodeTypeType
...@@ -330,6 +336,7 @@ struct CodeGenNode {...@@ -330,6 +336,7 @@ struct CodeGenNode {
330 VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration336 VarDeclNode var_decl_node; // for NodeTypeVariableDeclaration
331 StructValFieldNode struct_val_field_node; // for NodeTypeStructValueField337 StructValFieldNode struct_val_field_node; // for NodeTypeStructValueField
332 StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr338 StructValExprNode struct_val_expr_node; // for NodeTypeStructValueExpr
339 IfVarNode if_var_node; // for NodeTypeStructValueExpr
333 } data;340 } data;
334 ExprNode expr_node; // for all the expression nodes341 ExprNode expr_node; // for all the expression nodes
335};342};
src/codegen.cpp+176-88
...@@ -65,6 +65,11 @@ void codegen_set_libc_path(CodeGen *g, Buf *libc_path) {...@@ -65,6 +65,11 @@ void codegen_set_libc_path(CodeGen *g, Buf *libc_path) {
65static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);65static LLVMValueRef gen_expr(CodeGen *g, AstNode *expr_node);
66static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry);66static LLVMValueRef gen_lvalue(CodeGen *g, AstNode *expr_node, AstNode *node, TypeTableEntry **out_type_entry);
67static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue);67static LLVMValueRef gen_field_access_expr(CodeGen *g, AstNode *node, bool is_lvalue);
68static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
69 BlockContext *block_context, bool unwrap_maybe, LLVMValueRef *init_val);
70static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
71 LLVMValueRef target_ref, LLVMValueRef value,
72 TypeTableEntry *op1_type, TypeTableEntry *op2_type);
68 73
6974
70static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {75static TypeTableEntry *get_type_for_type_node(CodeGen *g, AstNode *type_node) {
...@@ -132,7 +137,7 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {...@@ -132,7 +137,7 @@ static LLVMValueRef find_or_create_string(CodeGen *g, Buf *str, bool c) {
132}137}
133138
134static TypeTableEntry *get_expr_type(AstNode *node) {139static TypeTableEntry *get_expr_type(AstNode *node) {
135 TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.type;140 TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.after_type;
136 return cast_type ? cast_type : node->codegen_node->expr_node.type_entry;141 return cast_type ? cast_type : node->codegen_node->expr_node.type_entry;
137}142}
138143
...@@ -367,6 +372,22 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v...@@ -367,6 +372,22 @@ static LLVMValueRef gen_bare_cast(CodeGen *g, AstNode *node, LLVMValueRef expr_v
367 switch (cast_node->op) {372 switch (cast_node->op) {
368 case CastOpNothing:373 case CastOpNothing:
369 return expr_val;374 return expr_val;
375 case CastOpMaybeWrap:
376 {
377 assert(cast_node->ptr);
378 assert(wanted_type->id == TypeTableEntryIdMaybe);
379
380 add_debug_source_node(g, node);
381 LLVMValueRef val_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 0, "");
382 gen_assign_raw(g, node, BinOpTypeAssign,
383 val_ptr, expr_val, wanted_type->data.maybe.child_type, actual_type);
384
385 add_debug_source_node(g, node);
386 LLVMValueRef maybe_ptr = LLVMBuildStructGEP(g->builder, cast_node->ptr, 1, "");
387 LLVMBuildStore(g->builder, LLVMConstAllOnes(LLVMInt1Type()), maybe_ptr);
388
389 return cast_node->ptr;
390 }
370 case CastOpPtrToInt:391 case CastOpPtrToInt:
371 return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");392 return LLVMBuildPtrToInt(g->builder, expr_val, wanted_type->type_ref, "");
372 case CastOpIntWidenOrShorten:393 case CastOpIntWidenOrShorten:
...@@ -423,34 +444,33 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {...@@ -423,34 +444,33 @@ static LLVMValueRef gen_cast_expr(CodeGen *g, AstNode *node) {
423444
424}445}
425446
426static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,447static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g, AstNode *source_node,
427 LLVMValueRef val1, LLVMValueRef val2,448 LLVMValueRef val1, LLVMValueRef val2,
428 TypeTableEntry *op1_type, TypeTableEntry *op2_type,449 TypeTableEntry *op1_type, TypeTableEntry *op2_type,
429 AstNode *node)450 BinOpType bin_op)
430{451{
431 assert(node->type == NodeTypeBinOpExpr);
432 assert(op1_type == op2_type);452 assert(op1_type == op2_type);
433453
434 switch (node->data.bin_op_expr.bin_op) {454 switch (bin_op) {
435 case BinOpTypeBinOr:455 case BinOpTypeBinOr:
436 case BinOpTypeAssignBitOr:456 case BinOpTypeAssignBitOr:
437 add_debug_source_node(g, node);457 add_debug_source_node(g, source_node);
438 return LLVMBuildOr(g->builder, val1, val2, "");458 return LLVMBuildOr(g->builder, val1, val2, "");
439 case BinOpTypeBinXor:459 case BinOpTypeBinXor:
440 case BinOpTypeAssignBitXor:460 case BinOpTypeAssignBitXor:
441 add_debug_source_node(g, node);461 add_debug_source_node(g, source_node);
442 return LLVMBuildXor(g->builder, val1, val2, "");462 return LLVMBuildXor(g->builder, val1, val2, "");
443 case BinOpTypeBinAnd:463 case BinOpTypeBinAnd:
444 case BinOpTypeAssignBitAnd:464 case BinOpTypeAssignBitAnd:
445 add_debug_source_node(g, node);465 add_debug_source_node(g, source_node);
446 return LLVMBuildAnd(g->builder, val1, val2, "");466 return LLVMBuildAnd(g->builder, val1, val2, "");
447 case BinOpTypeBitShiftLeft:467 case BinOpTypeBitShiftLeft:
448 case BinOpTypeAssignBitShiftLeft:468 case BinOpTypeAssignBitShiftLeft:
449 add_debug_source_node(g, node);469 add_debug_source_node(g, source_node);
450 return LLVMBuildShl(g->builder, val1, val2, "");470 return LLVMBuildShl(g->builder, val1, val2, "");
451 case BinOpTypeBitShiftRight:471 case BinOpTypeBitShiftRight:
452 case BinOpTypeAssignBitShiftRight:472 case BinOpTypeAssignBitShiftRight:
453 add_debug_source_node(g, node);473 add_debug_source_node(g, source_node);
454 if (op1_type->id == TypeTableEntryIdInt) {474 if (op1_type->id == TypeTableEntryIdInt) {
455 return LLVMBuildAShr(g->builder, val1, val2, "");475 return LLVMBuildAShr(g->builder, val1, val2, "");
456 } else {476 } else {
...@@ -458,7 +478,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,...@@ -458,7 +478,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
458 }478 }
459 case BinOpTypeAdd:479 case BinOpTypeAdd:
460 case BinOpTypeAssignPlus:480 case BinOpTypeAssignPlus:
461 add_debug_source_node(g, node);481 add_debug_source_node(g, source_node);
462 if (op1_type->id == TypeTableEntryIdFloat) {482 if (op1_type->id == TypeTableEntryIdFloat) {
463 return LLVMBuildFAdd(g->builder, val1, val2, "");483 return LLVMBuildFAdd(g->builder, val1, val2, "");
464 } else {484 } else {
...@@ -466,7 +486,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,...@@ -466,7 +486,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
466 }486 }
467 case BinOpTypeSub:487 case BinOpTypeSub:
468 case BinOpTypeAssignMinus:488 case BinOpTypeAssignMinus:
469 add_debug_source_node(g, node);489 add_debug_source_node(g, source_node);
470 if (op1_type->id == TypeTableEntryIdFloat) {490 if (op1_type->id == TypeTableEntryIdFloat) {
471 return LLVMBuildFSub(g->builder, val1, val2, "");491 return LLVMBuildFSub(g->builder, val1, val2, "");
472 } else {492 } else {
...@@ -474,7 +494,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,...@@ -474,7 +494,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
474 }494 }
475 case BinOpTypeMult:495 case BinOpTypeMult:
476 case BinOpTypeAssignTimes:496 case BinOpTypeAssignTimes:
477 add_debug_source_node(g, node);497 add_debug_source_node(g, source_node);
478 if (op1_type->id == TypeTableEntryIdFloat) {498 if (op1_type->id == TypeTableEntryIdFloat) {
479 return LLVMBuildFMul(g->builder, val1, val2, "");499 return LLVMBuildFMul(g->builder, val1, val2, "");
480 } else {500 } else {
...@@ -482,7 +502,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,...@@ -482,7 +502,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
482 }502 }
483 case BinOpTypeDiv:503 case BinOpTypeDiv:
484 case BinOpTypeAssignDiv:504 case BinOpTypeAssignDiv:
485 add_debug_source_node(g, node);505 add_debug_source_node(g, source_node);
486 if (op1_type->id == TypeTableEntryIdFloat) {506 if (op1_type->id == TypeTableEntryIdFloat) {
487 return LLVMBuildFDiv(g->builder, val1, val2, "");507 return LLVMBuildFDiv(g->builder, val1, val2, "");
488 } else {508 } else {
...@@ -495,7 +515,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,...@@ -495,7 +515,7 @@ static LLVMValueRef gen_arithmetic_bin_op(CodeGen *g,
495 }515 }
496 case BinOpTypeMod:516 case BinOpTypeMod:
497 case BinOpTypeAssignMod:517 case BinOpTypeAssignMod:
498 add_debug_source_node(g, node);518 add_debug_source_node(g, source_node);
499 if (op1_type->id == TypeTableEntryIdFloat) {519 if (op1_type->id == TypeTableEntryIdFloat) {
500 return LLVMBuildFRem(g->builder, val1, val2, "");520 return LLVMBuildFRem(g->builder, val1, val2, "");
501 } else {521 } else {
...@@ -530,7 +550,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {...@@ -530,7 +550,7 @@ static LLVMValueRef gen_arithmetic_bin_op_expr(CodeGen *g, AstNode *node) {
530550
531 TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1);551 TypeTableEntry *op1_type = get_expr_type(node->data.bin_op_expr.op1);
532 TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);552 TypeTableEntry *op2_type = get_expr_type(node->data.bin_op_expr.op2);
533 return gen_arithmetic_bin_op(g, val1, val2, op1_type, op2_type, node);553 return gen_arithmetic_bin_op(g, node, val1, val2, op1_type, op2_type, node->data.bin_op_expr.bin_op);
534554
535}555}
536556
...@@ -660,7 +680,7 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {...@@ -660,7 +680,7 @@ static LLVMValueRef gen_bool_or_expr(CodeGen *g, AstNode *expr_node) {
660static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValueRef src, LLVMValueRef dest,680static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValueRef src, LLVMValueRef dest,
661 TypeTableEntry *type_entry)681 TypeTableEntry *type_entry)
662{682{
663 assert(type_entry->id == TypeTableEntryIdStruct);683 assert(type_entry->id == TypeTableEntryIdStruct || type_entry->id == TypeTableEntryIdMaybe);
664684
665 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);685 LLVMTypeRef ptr_u8 = LLVMPointerType(LLVMInt8Type(), 0);
666686
...@@ -679,6 +699,30 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValu...@@ -679,6 +699,30 @@ static LLVMValueRef gen_struct_memcpy(CodeGen *g, AstNode *source_node, LLVMValu
679 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");699 return LLVMBuildCall(g->builder, g->memcpy_fn_val, params, 5, "");
680}700}
681701
702static LLVMValueRef gen_assign_raw(CodeGen *g, AstNode *source_node, BinOpType bin_op,
703 LLVMValueRef target_ref, LLVMValueRef value,
704 TypeTableEntry *op1_type, TypeTableEntry *op2_type)
705{
706 if (op1_type->id == TypeTableEntryIdStruct) {
707 assert(op2_type->id == TypeTableEntryIdStruct);
708 assert(op1_type == op2_type);
709 assert(bin_op == BinOpTypeAssign);
710
711 return gen_struct_memcpy(g, source_node, value, target_ref, op1_type);
712 }
713
714 if (bin_op != BinOpTypeAssign) {
715 assert(source_node->type == NodeTypeBinOpExpr);
716 add_debug_source_node(g, source_node->data.bin_op_expr.op1);
717 LLVMValueRef left_value = LLVMBuildLoad(g->builder, target_ref, "");
718
719 value = gen_arithmetic_bin_op(g, source_node, left_value, value, op1_type, op2_type, bin_op);
720 }
721
722 add_debug_source_node(g, source_node);
723 return LLVMBuildStore(g->builder, value, target_ref);
724}
725
682static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {726static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
683 assert(node->type == NodeTypeBinOpExpr);727 assert(node->type == NodeTypeBinOpExpr);
684728
...@@ -692,23 +736,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {...@@ -692,23 +736,7 @@ static LLVMValueRef gen_assign_expr(CodeGen *g, AstNode *node) {
692736
693 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);737 LLVMValueRef value = gen_expr(g, node->data.bin_op_expr.op2);
694738
695 if (op1_type->id == TypeTableEntryIdStruct) {739 return gen_assign_raw(g, node, node->data.bin_op_expr.bin_op, target_ref, value, op1_type, op2_type);
696 assert(op2_type->id == TypeTableEntryIdStruct);
697 assert(op1_type == op2_type);
698 assert(node->data.bin_op_expr.bin_op == BinOpTypeAssign);
699
700 return gen_struct_memcpy(g, node, value, target_ref, op1_type);
701 }
702
703 if (node->data.bin_op_expr.bin_op != BinOpTypeAssign) {
704 add_debug_source_node(g, node->data.bin_op_expr.op1);
705 LLVMValueRef left_value = LLVMBuildLoad(g->builder, target_ref, "");
706
707 value = gen_arithmetic_bin_op(g, left_value, value, op1_type, op2_type, node);
708 }
709
710 add_debug_source_node(g, node);
711 return LLVMBuildStore(g->builder, value, target_ref);
712}740}
713741
714static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {742static LLVMValueRef gen_bin_op_expr(CodeGen *g, AstNode *node) {
...@@ -769,18 +797,14 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {...@@ -769,18 +797,14 @@ static LLVMValueRef gen_return_expr(CodeGen *g, AstNode *node) {
769 }797 }
770}798}
771799
772static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {800static LLVMValueRef gen_if_bool_expr_raw(CodeGen *g, AstNode *source_node, LLVMValueRef cond_value,
773 assert(node->type == NodeTypeIfBoolExpr);801 AstNode *then_node, AstNode *else_node)
774 assert(node->data.if_bool_expr.condition);802{
775 assert(node->data.if_bool_expr.then_block);803 TypeTableEntry *then_type = get_expr_type(then_node);
776
777 LLVMValueRef cond_value = gen_expr(g, node->data.if_bool_expr.condition);
778
779 TypeTableEntry *then_type = get_expr_type(node->data.if_bool_expr.then_block);
780 bool use_expr_value = (then_type->id != TypeTableEntryIdUnreachable &&804 bool use_expr_value = (then_type->id != TypeTableEntryIdUnreachable &&
781 then_type->id != TypeTableEntryIdVoid);805 then_type->id != TypeTableEntryIdVoid);
782806
783 if (node->data.if_bool_expr.else_node) {807 if (else_node) {
784 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");808 LLVMBasicBlockRef then_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Then");
785 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");809 LLVMBasicBlockRef else_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "Else");
786 LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");810 LLVMBasicBlockRef endif_block = LLVMAppendBasicBlock(g->cur_fn->fn_value, "EndIf");
...@@ -788,13 +812,13 @@ static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {...@@ -788,13 +812,13 @@ static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
788 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);812 LLVMBuildCondBr(g->builder, cond_value, then_block, else_block);
789813
790 LLVMPositionBuilderAtEnd(g->builder, then_block);814 LLVMPositionBuilderAtEnd(g->builder, then_block);
791 LLVMValueRef then_expr_result = gen_expr(g, node->data.if_bool_expr.then_block);815 LLVMValueRef then_expr_result = gen_expr(g, then_node);
792 if (get_expr_type(node->data.if_bool_expr.then_block)->id != TypeTableEntryIdUnreachable)816 if (get_expr_type(then_node)->id != TypeTableEntryIdUnreachable)
793 LLVMBuildBr(g->builder, endif_block);817 LLVMBuildBr(g->builder, endif_block);
794818
795 LLVMPositionBuilderAtEnd(g->builder, else_block);819 LLVMPositionBuilderAtEnd(g->builder, else_block);
796 LLVMValueRef else_expr_result = gen_expr(g, node->data.if_bool_expr.else_node);820 LLVMValueRef else_expr_result = gen_expr(g, else_node);
797 if (get_expr_type(node->data.if_bool_expr.else_node)->id != TypeTableEntryIdUnreachable)821 if (get_expr_type(else_node)->id != TypeTableEntryIdUnreachable)
798 LLVMBuildBr(g->builder, endif_block);822 LLVMBuildBr(g->builder, endif_block);
799823
800 LLVMPositionBuilderAtEnd(g->builder, endif_block);824 LLVMPositionBuilderAtEnd(g->builder, endif_block);
...@@ -818,17 +842,49 @@ static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {...@@ -818,17 +842,49 @@ static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
818 LLVMBuildCondBr(g->builder, cond_value, then_block, endif_block);842 LLVMBuildCondBr(g->builder, cond_value, then_block, endif_block);
819843
820 LLVMPositionBuilderAtEnd(g->builder, then_block);844 LLVMPositionBuilderAtEnd(g->builder, then_block);
821 gen_expr(g, node->data.if_bool_expr.then_block);845 gen_expr(g, then_node);
822 if (get_expr_type(node->data.if_bool_expr.then_block)->id != TypeTableEntryIdUnreachable)846 if (get_expr_type(then_node)->id != TypeTableEntryIdUnreachable)
823 LLVMBuildBr(g->builder, endif_block);847 LLVMBuildBr(g->builder, endif_block);
824848
825 LLVMPositionBuilderAtEnd(g->builder, endif_block);849 LLVMPositionBuilderAtEnd(g->builder, endif_block);
826 return nullptr;850 return nullptr;
827}851}
828852
853static LLVMValueRef gen_if_bool_expr(CodeGen *g, AstNode *node) {
854 assert(node->type == NodeTypeIfBoolExpr);
855 assert(node->data.if_bool_expr.condition);
856 assert(node->data.if_bool_expr.then_block);
857
858 LLVMValueRef cond_value = gen_expr(g, node->data.if_bool_expr.condition);
859
860 return gen_if_bool_expr_raw(g, node, cond_value,
861 node->data.if_bool_expr.then_block,
862 node->data.if_bool_expr.else_node);
863}
864
829static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {865static LLVMValueRef gen_if_var_expr(CodeGen *g, AstNode *node) {
830 assert(node->type == NodeTypeIfVarExpr);866 assert(node->type == NodeTypeIfVarExpr);
831 zig_panic("TODO gen_if_var_expr");867 assert(node->data.if_var_expr.var_decl.expr);
868
869 BlockContext *old_block_context = g->cur_block_context;
870 BlockContext *new_block_context = node->codegen_node->data.if_var_node.block_context;
871
872 LLVMValueRef init_val;
873 gen_var_decl_raw(g, node, &node->data.if_var_expr.var_decl, new_block_context, true, &init_val);
874
875 // test if value is the maybe state
876 add_debug_source_node(g, node);
877 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, init_val, 1, "");
878 LLVMValueRef cond_value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
879
880 g->cur_block_context = new_block_context;
881
882 LLVMValueRef return_value = gen_if_bool_expr_raw(g, node, cond_value,
883 node->data.if_var_expr.then_block,
884 node->data.if_var_expr.else_node);
885
886 g->cur_block_context = old_block_context;
887 return return_value;
832}888}
833889
834static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {890static LLVMValueRef gen_block(CodeGen *g, AstNode *block_node, TypeTableEntry *implicit_return_type) {
...@@ -1058,6 +1114,55 @@ static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {...@@ -1058,6 +1114,55 @@ static LLVMValueRef gen_continue(CodeGen *g, AstNode *node) {
1058 return LLVMBuildBr(g->builder, dest_block);1114 return LLVMBuildBr(g->builder, dest_block);
1059}1115}
10601116
1117static LLVMValueRef gen_var_decl_raw(CodeGen *g, AstNode *source_node, AstNodeVariableDeclaration *var_decl,
1118 BlockContext *block_context, bool unwrap_maybe, LLVMValueRef *init_value)
1119{
1120 VariableTableEntry *variable = find_variable(block_context, &var_decl->symbol);
1121
1122 assert(variable);
1123 assert(variable->is_ptr);
1124
1125 if (var_decl->expr) {
1126 *init_value = gen_expr(g, var_decl->expr);
1127 } else {
1128 *init_value = LLVMConstNull(variable->type->type_ref);
1129 }
1130 if (variable->type->id == TypeTableEntryIdVoid) {
1131 return nullptr;
1132 } else {
1133 LLVMValueRef store_instr;
1134 LLVMValueRef value;
1135 if (unwrap_maybe) {
1136 assert(var_decl->expr);
1137 add_debug_source_node(g, source_node);
1138 LLVMValueRef maybe_field_ptr = LLVMBuildStructGEP(g->builder, *init_value, 0, "");
1139 // TODO if it's a struct we might not want to load the pointer
1140 value = LLVMBuildLoad(g->builder, maybe_field_ptr, "");
1141 } else {
1142 value = *init_value;
1143 }
1144 if ((variable->type->id == TypeTableEntryIdStruct || variable->type->id == TypeTableEntryIdMaybe) &&
1145 var_decl->expr)
1146 {
1147 store_instr = gen_struct_memcpy(g, source_node, value, variable->value_ref, variable->type);
1148 } else {
1149 add_debug_source_node(g, source_node);
1150 store_instr = LLVMBuildStore(g->builder, value, variable->value_ref);
1151 }
1152
1153 LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(source_node->line + 1, source_node->column + 1,
1154 g->cur_block_context->di_scope);
1155 LLVMZigInsertDeclare(g->dbuilder, variable->value_ref, variable->di_loc_var, debug_loc, store_instr);
1156 return nullptr;
1157 }
1158}
1159
1160static LLVMValueRef gen_var_decl_expr(CodeGen *g, AstNode *node) {
1161 LLVMValueRef init_val;
1162 return gen_var_decl_raw(g, node, &node->data.variable_declaration,
1163 node->codegen_node->expr_node.block_context, false, &init_val);
1164}
1165
1061static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {1166static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1062 switch (node->type) {1167 switch (node->type) {
1063 case NodeTypeBinOpExpr:1168 case NodeTypeBinOpExpr:
...@@ -1065,38 +1170,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1065,38 +1170,7 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1065 case NodeTypeReturnExpr:1170 case NodeTypeReturnExpr:
1066 return gen_return_expr(g, node);1171 return gen_return_expr(g, node);
1067 case NodeTypeVariableDeclaration:1172 case NodeTypeVariableDeclaration:
1068 {1173 return gen_var_decl_expr(g, node);
1069 VariableTableEntry *variable = find_variable(
1070 node->codegen_node->expr_node.block_context,
1071 &node->data.variable_declaration.symbol);
1072
1073 assert(variable);
1074 assert(variable->is_ptr);
1075
1076 LLVMValueRef value;
1077 if (node->data.variable_declaration.expr) {
1078 value = gen_expr(g, node->data.variable_declaration.expr);
1079 } else {
1080 value = LLVMConstNull(variable->type->type_ref);
1081 }
1082 if (variable->type->id == TypeTableEntryIdVoid) {
1083 return nullptr;
1084 } else {
1085 LLVMValueRef store_instr;
1086 if (variable->type->id == TypeTableEntryIdStruct && node->data.variable_declaration.expr) {
1087 store_instr = gen_struct_memcpy(g, node, value, variable->value_ref, variable->type);
1088 } else {
1089 add_debug_source_node(g, node);
1090 store_instr = LLVMBuildStore(g->builder, value, variable->value_ref);
1091 }
1092
1093 LLVMZigDILocation *debug_loc = LLVMZigGetDebugLoc(node->line + 1, node->column + 1,
1094 g->cur_block_context->di_scope);
1095 LLVMZigInsertDeclare(g->dbuilder, variable->value_ref, variable->di_loc_var,
1096 debug_loc, store_instr);
1097 return nullptr;
1098 }
1099 }
1100 case NodeTypeCastExpr:1174 case NodeTypeCastExpr:
1101 return gen_cast_expr(g, node);1175 return gen_cast_expr(g, node);
1102 case NodeTypePrefixOpExpr:1176 case NodeTypePrefixOpExpr:
...@@ -1174,7 +1248,9 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1174,7 +1248,9 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1174 assert(variable->value_ref);1248 assert(variable->value_ref);
1175 if (variable->type->id == TypeTableEntryIdArray) {1249 if (variable->type->id == TypeTableEntryIdArray) {
1176 return variable->value_ref;1250 return variable->value_ref;
1177 } else if (variable->type->id == TypeTableEntryIdStruct) {1251 } else if (variable->type->id == TypeTableEntryIdStruct ||
1252 variable->type->id == TypeTableEntryIdMaybe)
1253 {
1178 return variable->value_ref;1254 return variable->value_ref;
1179 } else {1255 } else {
1180 add_debug_source_node(g, node);1256 add_debug_source_node(g, node);
...@@ -1225,6 +1301,12 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {...@@ -1225,6 +1301,12 @@ static LLVMValueRef gen_expr_no_cast(CodeGen *g, AstNode *node) {
1225 zig_unreachable();1301 zig_unreachable();
1226}1302}
12271303
1304static LLVMValueRef gen_cast_node(CodeGen *g, AstNode *node, LLVMValueRef val, TypeTableEntry *before_type,
1305 CastNode *cast_node)
1306{
1307 return cast_node->after_type ? gen_bare_cast(g, node, val, before_type, cast_node->after_type, cast_node) : val;
1308}
1309
1228static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {1310static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
1229 LLVMValueRef val = gen_expr_no_cast(g, node);1311 LLVMValueRef val = gen_expr_no_cast(g, node);
12301312
...@@ -1234,11 +1316,17 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {...@@ -1234,11 +1316,17 @@ static LLVMValueRef gen_expr(CodeGen *g, AstNode *node) {
12341316
1235 assert(node->codegen_node);1317 assert(node->codegen_node);
12361318
1237 TypeTableEntry *actual_type = node->codegen_node->expr_node.type_entry;1319 {
1238 TypeTableEntry *cast_type = node->codegen_node->expr_node.implicit_cast.type;1320 TypeTableEntry *before_type = node->codegen_node->expr_node.type_entry;
1321 val = gen_cast_node(g, node, val, before_type, &node->codegen_node->expr_node.implicit_cast);
1322 }
1323
1324 {
1325 TypeTableEntry *before_type = node->codegen_node->expr_node.implicit_cast.after_type;
1326 val = gen_cast_node(g, node, val, before_type, &node->codegen_node->expr_node.implicit_maybe_cast);
1327 }
12391328
1240 return cast_type ? gen_bare_cast(g, node, val, actual_type, cast_type,1329 return val;
1241 &node->codegen_node->expr_node.implicit_cast) : val;
1242}1330}
12431331
1244static void build_label_blocks(CodeGen *g, AstNode *block_node) {1332static void build_label_blocks(CodeGen *g, AstNode *block_node) {
...@@ -1460,7 +1548,7 @@ static void do_code_gen(CodeGen *g) {...@@ -1460,7 +1548,7 @@ static void do_code_gen(CodeGen *g) {
1460 for (int cea_i = 0; cea_i < block_context->cast_expr_alloca_list.length; cea_i += 1) {1548 for (int cea_i = 0; cea_i < block_context->cast_expr_alloca_list.length; cea_i += 1) {
1461 CastNode *cast_node = block_context->cast_expr_alloca_list.at(cea_i);1549 CastNode *cast_node = block_context->cast_expr_alloca_list.at(cea_i);
1462 add_debug_source_node(g, cast_node->source_node);1550 add_debug_source_node(g, cast_node->source_node);
1463 cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->type->type_ref, "");1551 cast_node->ptr = LLVMBuildAlloca(g->builder, cast_node->after_type->type_ref, "");
1464 }1552 }
14651553
1466 // allocate structs which are struct value expressions1554 // allocate structs which are struct value expressions
test/run_tests.cpp+18
...@@ -674,6 +674,24 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {...@@ -674,6 +674,24 @@ export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
674 return 0;674 return 0;
675}675}
676 )SOURCE", "loop\nloop\nloop\nloop\n");676 )SOURCE", "loop\nloop\nloop\nloop\n");
677
678 add_simple_case("maybe type", R"SOURCE(
679use "std.zig";
680export fn main(argc : isize, argv : &&u8, env : &&u8) -> i32 {
681 const x : ?bool = true;
682
683 if (const y ?= x) {
684 if (y) {
685 print_str("x is true\n");
686 } else {
687 print_str("x is false\n");
688 }
689 } else {
690 print_str("x is none\n");
691 }
692 return 0;
693}
694 )SOURCE", "x is true\n");
677}695}
678696
679////////////////////////////////////////////////////////////////////////////////////697////////////////////////////////////////////////////////////////////////////////////