| ... | ... | @@ -207,10 +207,12 @@ pub const DeclGen = struct { |
| 207 | 207 | if (t.isPtrLikeOptional()) { |
| 208 | 208 | return dg.renderValue(writer, child_type, val); |
| 209 | 209 | } |
| 210 | try writer.writeByte('('); |
| 211 | try dg.renderType(writer, t); |
| 210 | 212 | if (val.tag() == .null_value) { |
| 211 | | try writer.writeAll("{ .is_null = true }"); |
| 213 | try writer.writeAll("){ .is_null = true }"); |
| 212 | 214 | } else { |
| 213 | | try writer.writeAll("{ .is_null = false, .payload = "); |
| 215 | try writer.writeAll("){ .is_null = false, .payload = "); |
| 214 | 216 | try dg.renderValue(writer, child_type, val); |
| 215 | 217 | try writer.writeAll(" }"); |
| 216 | 218 | } |
| ... | ... | @@ -319,7 +321,11 @@ pub const DeclGen = struct { |
| 319 | 321 | if (t.isPtrLikeOptional()) { |
| 320 | 322 | return dg.renderType(w, child_type); |
| 321 | 323 | } |
| 322 | | return dg.fail(dg.decl.src(), "TODO: C backend: more optional types", .{}); |
| 324 | |
| 325 | // TODO this needs to be typedeffed since different structs are different types. |
| 326 | try w.writeAll("struct { "); |
| 327 | try dg.renderType(w, child_type); |
| 328 | try w.writeAll(" payload; bool is_null; }"); |
| 323 | 329 | }, |
| 324 | 330 | .Null, .Undefined => unreachable, // must be const or comptime |
| 325 | 331 | else => |e| return dg.fail(dg.decl.src(), "TODO: C backend: implement type {s}", .{ |
| ... | ... | @@ -834,6 +840,7 @@ fn genAsm(o: *Object, as: *Inst.Assembly) !CValue { |
| 834 | 840 | fn genIsNull(o: *Object, inst: *Inst.UnOp) !CValue { |
| 835 | 841 | const writer = o.writer(); |
| 836 | 842 | const invert_logic = inst.base.tag == .is_non_null or inst.base.tag == .is_non_null_ptr; |
| 843 | const operator = if (invert_logic) "!=" else "=="; |
| 837 | 844 | const maybe_deref = if (inst.base.tag == .is_null_ptr or inst.base.tag == .is_non_null_ptr) "[0]" else ""; |
| 838 | 845 | const operand = try o.resolveInst(inst.operand); |
| 839 | 846 | |
| ... | ... | @@ -843,10 +850,8 @@ fn genIsNull(o: *Object, inst: *Inst.UnOp) !CValue { |
| 843 | 850 | |
| 844 | 851 | if (inst.operand.ty.isPtrLikeOptional()) { |
| 845 | 852 | // operand is a regular pointer, test `operand !=/== NULL` |
| 846 | | const operator = if (invert_logic) "!=" else "=="; |
| 847 | 853 | try writer.print("){s} {s} NULL;\n", .{ maybe_deref, operator }); |
| 848 | 854 | } else { |
| 849 | | const operator = if (invert_logic) "!=" else "=="; |
| 850 | 855 | try writer.print("){s}.is_null {s} true;\n", .{ maybe_deref, operator }); |
| 851 | 856 | } |
| 852 | 857 | return local; |
| ... | ... | @@ -856,17 +861,26 @@ fn genOptionalPayload(o: *Object, inst: *Inst.UnOp) !CValue { |
| 856 | 861 | const writer = o.writer(); |
| 857 | 862 | const operand = try o.resolveInst(inst.operand); |
| 858 | 863 | |
| 864 | const opt_ty = if (inst.operand.ty.zigTypeTag() == .Pointer) |
| 865 | inst.operand.ty.elemType() |
| 866 | else |
| 867 | inst.operand.ty; |
| 868 | |
| 859 | 869 | if (opt_ty.isPtrLikeOptional()) { |
| 860 | 870 | // the operand is just a regular pointer, no need to do anything special. |
| 871 | // *?*T -> **T and ?*T -> *T are **T -> **T and *T -> *T in C |
| 861 | 872 | return operand; |
| 862 | 873 | } |
| 863 | 874 | |
| 864 | | const opt_ty = if (inst.operand.ty.zigTypeTag() == .Pointer) |
| 865 | | inst.operand.ty.elemType() |
| 866 | | else |
| 867 | | inst.operand.ty; |
| 875 | const maybe_deref = if (inst.operand.ty.zigTypeTag() == .Pointer) "->" else "."; |
| 876 | const maybe_addrof = if (inst.base.ty.zigTypeTag() == .Pointer) "&" else ""; |
| 877 | |
| 878 | const local = try o.allocLocal(inst.base.ty, .Const); |
| 879 | try writer.print(" = {s}(", .{maybe_addrof}); |
| 880 | try o.writeCValue(writer, operand); |
| 868 | 881 | |
| 869 | | return o.dg.fail(o.dg.decl.src(), "TODO: C backend: genOptionalPayload non ptr-like optionals", .{}); |
| 882 | try writer.print("){s}payload;\n", .{maybe_deref}); |
| 883 | return local; |
| 870 | 884 | } |
| 871 | 885 | |
| 872 | 886 | fn genWrapOptional(o: *Object, inst: *Inst.UnOp) !CValue { |
| ... | ... | @@ -878,7 +892,12 @@ fn genWrapOptional(o: *Object, inst: *Inst.UnOp) !CValue { |
| 878 | 892 | return operand; |
| 879 | 893 | } |
| 880 | 894 | |
| 881 | | return o.dg.fail(o.dg.decl.src(), "TODO: C backend: genWrapOptional non ptr-like optionals", .{}); |
| 895 | // .wrap_optional is used to convert non-optionals into optionals so it can never be null. |
| 896 | const local = try o.allocLocal(inst.base.ty, .Const); |
| 897 | try writer.writeAll(" = { .is_null = false, .payload ="); |
| 898 | try o.writeCValue(writer, operand); |
| 899 | try writer.writeAll("};\n"); |
| 900 | return local; |
| 882 | 901 | } |
| 883 | 902 | |
| 884 | 903 | fn IndentWriter(comptime UnderlyingWriter: type) type { |