Commit c0540967e9

Veikka Tuominen <git@vexu.eu>
2021-02-14 17:06:15
translate-c: render array stuff
1 parent 62162a0
Changed files (3)
src/translate_c/ast.zig
@@ -291,7 +291,6 @@ pub const Node = extern union {
                 .array_cat,
                 .ellipsis3,
                 .switch_prong,
-                .field_access,
                 .assign,
                 .align_cast,
                 .array_access,
@@ -309,7 +308,7 @@ pub const Node = extern union {
                 => Payload.Value,
                 .@"if" => Payload.If,
                 .@"while" => Payload.While,
-                .@"switch" => Payload.Switch,
+                .@"switch", .array_init => Payload.Switch,
                 .@"break" => Payload.Break,
                 .break_val => Payload.BreakVal,
                 .call => Payload.Call,
@@ -317,7 +316,7 @@ pub const Node = extern union {
                 .func => Payload.Func,
                 .@"enum" => Payload.Enum,
                 .@"struct", .@"union" => Payload.Record,
-                .array_init, .tuple => Payload.ArrayInit,
+                .tuple => Payload.TupleInit,
                 .container_init => Payload.ContainerInit,
                 .std_meta_cast => Payload.Infix,
                 .block => Payload.Block,
@@ -329,6 +328,7 @@ pub const Node = extern union {
                 .enum_redecl => Payload.EnumRedecl,
                 .array_filler => Payload.ArrayFiller,
                 .pub_inline_fn => Payload.PubInlineFn,
+                .field_access => Payload.FieldAccess,
             };
         }
 
@@ -513,7 +513,7 @@ pub const Payload = struct {
         };
     };
 
-    pub const ArrayInit = struct {
+    pub const TupleInit = struct {
         base: Payload,
         data: []Node,
     };
@@ -601,6 +601,14 @@ pub const Payload = struct {
             body: Node,
         },
     };
+
+    pub const FieldAccess = struct {
+        base: Payload,
+        data: struct {
+            lhs: Node,
+            field_name: []const u8,
+        },
+    };
 };
 
 /// Converts the nodes into a Zig ast.
@@ -995,6 +1003,32 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
             });
         },
         .var_decl => return renderVar(c, node),
+        .arg_redecl, .alias => {
+            const payload = @fieldParentPtr(Payload.ArgRedecl, "base", node.ptr_otherwise).data;
+            if (node.tag() == .alias) _ = try c.addToken(.keyword_pub, "pub");
+            const mut_tok = if (node.tag() == .alias)
+                try c.addToken(.keyword_const, "const")
+            else
+                try c.addToken(.keyword_var, "var");
+            _ = try c.addIdentifier(payload.actual);
+            _ = try c.addToken(.equal, "=");
+
+            const init = try c.addNode(.{
+                .tag = .identifier,
+                .main_token = try c.addIdentifier(payload.mangled),
+                .data = undefined,
+            });
+            _ = try c.addToken(.semicolon, ";");
+
+            return c.addNode(.{
+                .tag = .simple_var_decl,
+                .main_token = mut_tok,
+                .data = .{
+                    .lhs = 0,
+                    .rhs = init,
+                },
+            });
+        },
         .int_cast => {
             const payload = node.castTag(.int_cast).?.data;
             return renderBuiltinCall(c, "@intCast", &.{ payload.lhs, payload.rhs });
@@ -1339,7 +1373,7 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
             _ = try c.addToken(.l_paren, "(");
             const cond = try c.addNode(.{
                 .tag = .bool_not,
-                .main_token = try c.addToken(.bang,  "!"),
+                .main_token = try c.addToken(.bang, "!"),
                 .data = .{
                     .lhs = try renderNodeGrouped(c, payload),
                     .rhs = undefined,
@@ -1430,7 +1464,77 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
                 },
             });
         },
-        else => return c.addNode(.{
+        .array_access => {
+            const payload = node.castTag(.array_access).?.data;
+            const lhs = try renderNode(c, payload.lhs);
+            const l_bracket = try c.addToken(.l_bracket, "[");
+            const index_expr = try renderNode(c, payload.rhs);
+            _ = try c.addToken(.r_bracket, "]");
+            return c.addNode(.{
+                .tag = .array_access,
+                .main_token = l_bracket,
+                .data = .{
+                    .lhs = lhs,
+                    .rhs = index_expr,
+                },
+            });
+        },
+        .array_type => {
+            const payload = node.castTag(.array_type).?.data;
+            return renderArrayType(c, payload.len, payload.elem_type);
+        },
+        .array_filler => {
+            const payload = node.castTag(.array_filler).?.data;
+
+            const type_expr = try renderArrayType(c, 1, payload.type);
+            const l_brace = try c.addToken(.l_brace, "{");
+            const val = try renderNode(c, payload.filler);
+            _ = try c.addToken(.r_brace, "}");
+
+            const init = try c.addNode(.{
+                .tag = .array_init_one,
+                .main_token = l_brace,
+                .data = .{
+                    .lhs = type_expr,
+                    .rhs = val,
+                },
+            });
+            return c.addNode(.{
+                .tag = .array_cat,
+                .main_token = try c.addToken(.asterisk_asterisk, "**"),
+                .data = .{
+                    .lhs = init,
+                    .rhs = try c.addNode(.{
+                        .tag = .integer_literal,
+                        .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{payload.count}),
+                        .data = .{ .lhs = undefined, .rhs = undefined },
+                    }),
+                },
+            });
+        },
+        .empty_array => {
+            const payload = node.castTag(.empty_array).?.data;
+
+            const type_expr = try renderArrayType(c, 0, payload);
+            return renderArrayInit(c, 0, &.{});
+        },
+        .array_init => {
+            const payload = node.castTag(.array_init).?.data;
+            const type_expr = try renderNode(c, payload.cond);
+            return renderArrayInit(c, type_expr, payload.cases);
+        },
+        .field_access => {
+            const payload = node.castTag(.field_access).?.data;
+            const lhs = try renderNode(c, payload.lhs);
+            return renderFieldAccess(c, lhs, payload.field_name);
+        },
+        .tuple,
+        .@"enum",
+        .@"struct",
+        .@"union",
+        .container_init,
+        .enum_redecl,
+        => return c.addNode(.{
             .tag = .identifier,
             .main_token = try c.addTokenFmt(.identifier, "@\"TODO {}\"", .{node.tag()}),
             .data = .{
@@ -1441,10 +1545,88 @@ fn renderNode(c: *Context, node: Node) Allocator.Error!NodeIndex {
     }
 }
 
+fn renderFieldAccess(c: *Context, lhs: NodeIndex, field_name: []const u8) !NodeIndex {
+    return c.addNode(.{
+        .tag = .field_access,
+        .main_token = try c.addToken(.period, "."),
+        .data = .{
+            .lhs = lhs,
+            .rhs = try c.addIdentifier(field_name),
+        },
+    });
+}
+
+fn renderArrayInit(c: *Context, lhs: NodeIndex, inits: []const Node) !NodeIndex {
+    const l_brace = try c.addToken(.l_brace, "{");
+    const res = switch (inits.len) {
+        0 => try c.addNode(.{
+            .tag = .struct_init_one,
+            .main_token = l_brace,
+            .data = .{
+                .lhs = lhs,
+                .rhs = 0,
+            },
+        }),
+        1 => blk: {
+            const init = try renderNode(c, inits[0]);
+            break :blk try c.addNode(.{
+                .tag = .array_init_one,
+                .main_token = l_brace,
+                .data = .{
+                    .lhs = lhs,
+                    .rhs = init,
+                },
+            });
+        },
+        else => blk: {
+            var rendered = try c.gpa.alloc(NodeIndex, inits.len);
+            defer c.gpa.free(rendered);
+
+            for (inits) |init, i| {
+                if (i != 0) _ = try c.addToken(.comma, ",");
+                rendered[i] = try renderNode(c, init);
+            }
+            const span = try c.listToSpan(rendered);
+            break :blk try c.addNode(.{
+                .tag = .array_init,
+                .main_token = l_brace,
+                .data = .{
+                    .lhs = lhs,
+                    .rhs = try c.addExtra(NodeSubRange{
+                        .start = span.start,
+                        .end = span.end,
+                    }),
+                },
+            });
+        },
+    };
+    _ = try c.addToken(.r_brace, "}");
+    return res;
+}
+
+fn renderArrayType(c: *Context, len: usize, elem_type: Node) !NodeIndex {
+    const l_bracket = try c.addToken(.l_bracket, "[");
+    const len_expr = try c.addNode(.{
+        .tag = .integer_literal,
+        .main_token = try c.addTokenFmt(.integer_literal, "{d}", .{len}),
+        .data = .{ .lhs = undefined, .rhs = undefined },
+    });
+    _ = try c.addToken(.r_bracket, "]");
+    const elem_type_expr = try renderNode(c, elem_type);
+    return c.addNode(.{
+        .tag = .array_type,
+        .main_token = l_bracket,
+        .data = .{
+            .lhs = len_expr,
+            .rhs = elem_type_expr,
+        },
+    });
+}
+
 fn addSemicolonIfNeeded(c: *Context, node: Node) !void {
     switch (node.tag()) {
         .warning => unreachable,
-        .var_decl, .var_simple, .block, .empty_block, .@"switch" => {},
+        .var_decl, .var_simple, .arg_redecl, .alias, .enum_redecl, .block, .empty_block, .@"switch" => {},
         .while_true => {
             const payload = node.castTag(.while_true).?.data;
             return addSemicolonIfNeeded(c, payload);
@@ -1517,6 +1699,7 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
         .negate,
         .negate_wrap,
         .bit_not,
+        .func,
         => {
             // no grouping needed
             return renderNode(c, node);
@@ -1572,7 +1755,6 @@ fn renderNodeGrouped(c: *Context, node: Node) !NodeIndex {
         .switch_prong,
         .warning,
         .var_decl,
-        .func,
         .fail_decl,
         .arg_redecl,
         .alias,
@@ -1658,22 +1840,8 @@ fn renderStdImport(c: *Context, first: []const u8, second: []const u8) !NodeInde
     });
 
     var access_chain = import_node;
-    access_chain = try c.addNode(.{
-        .tag = .field_access,
-        .main_token = try c.addToken(.period, "."),
-        .data = .{
-            .lhs = access_chain,
-            .rhs = try c.addIdentifier(first),
-        },
-    });
-    access_chain = try c.addNode(.{
-        .tag = .field_access,
-        .main_token = try c.addToken(.period, "."),
-        .data = .{
-            .lhs = access_chain,
-            .rhs = try c.addIdentifier(second),
-        },
-    });
+    access_chain = try renderFieldAccess(c, access_chain, first);
+    access_chain = try renderFieldAccess(c, access_chain, second);
     return access_chain;
 }
 
@@ -1974,10 +2142,10 @@ fn renderFunc(c: *Context, node: Node) !NodeIndex {
 
     const body = if (payload.body) |some|
         try renderNode(c, some)
-    else blk: {
+    else if (payload.is_extern) blk: {
         _ = try c.addToken(.semicolon, ";");
         break :blk 0;
-    };
+    } else return fn_proto;
 
     return c.addNode(.{
         .tag = .fn_decl,
src/Compilation.zig
@@ -1334,7 +1334,7 @@ pub fn update(self: *Compilation) !void {
         self.c_object_work_queue.writeItemAssumeCapacity(entry.key);
     }
 
-    const use_stage1 = build_options.is_stage1 and self.bin_file.options.use_llvm;
+    const use_stage1 = build_options.omit_stage2 or build_options.is_stage1 and self.bin_file.options.use_llvm;
     if (!use_stage1) {
         if (self.bin_file.options.module) |module| {
             module.compile_log_text.shrinkAndFree(module.gpa, 0);
src/translate_c.zig
@@ -1689,7 +1689,10 @@ fn transStringLiteralAsArray(
         init_list[i] = try transCreateNodeNumber(c, 0, .int);
     }
 
-    return Tag.array_init.create(c.arena, init_list);
+    return Tag.array_init.create(c.arena, .{
+        .cond = arr_type,
+        .cases = init_list,
+    });
 }
 
 fn cIsEnum(qt: clang.QualType) bool {
@@ -1880,6 +1883,7 @@ fn transInitListExprArray(
 ) TransError!Node {
     const arr_type = ty.getAsArrayTypeUnsafe();
     const child_qt = arr_type.getElementType();
+    const child_type = try transQualType(c, child_qt, loc);
     const init_count = expr.getNumInits();
     assert(@ptrCast(*const clang.Type, arr_type).isConstantArrayType());
     const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, arr_type);
@@ -1888,18 +1892,20 @@ fn transInitListExprArray(
     const leftover_count = all_count - init_count;
 
     if (all_count == 0) {
-        return Tag.empty_array.create(c.arena, try transQualType(c, child_qt, loc));
+        return Tag.empty_array.create(c.arena, child_type);
     }
 
-    const ty_node = try transType(c, ty, loc);
     const init_node = if (init_count != 0) blk: {
         const init_list = try c.arena.alloc(Node, init_count);
 
         for (init_list) |*init, i| {
             const elem_expr = expr.getInit(@intCast(c_uint, i));
-            init.* = try transExpr(c, scope, elem_expr, .used);
+            init.* = try transExprCoercing(c, scope, elem_expr, .used);
         }
-        const init_node = try Tag.array_init.create(c.arena, init_list);
+        const init_node = try Tag.array_init.create(c.arena, .{
+            .cond = try Tag.array_type.create(c.arena, .{ .len = init_count, .elem_type = child_type }),
+            .cases = init_list,
+        });
         if (leftover_count == 0) {
             return init_node;
         }
@@ -1908,8 +1914,8 @@ fn transInitListExprArray(
 
     const filler_val_expr = expr.getArrayFiller();
     const filler_node = try Tag.array_filler.create(c.arena, .{
-        .type = ty_node,
-        .filler = try transExpr(c, scope, filler_val_expr, .used),
+        .type = child_type,
+        .filler = try transExprCoercing(c, scope, filler_val_expr, .used),
         .count = leftover_count,
     });
 
@@ -2422,9 +2428,7 @@ fn transMemberExpr(c: *Context, scope: *Scope, stmt: *const clang.MemberExpr, re
         const decl = @ptrCast(*const clang.NamedDecl, member_decl);
         break :blk try c.str(decl.getName_bytes_begin());
     };
-    const ident = try Tag.identifier.create(c.arena, name);
-
-    const node = try Tag.field_access.create(c.arena, .{ .lhs = container_node, .rhs = ident });
+    const node = try Tag.field_access.create(c.arena, .{ .lhs = container_node, .field_name = name });
     return maybeSuppressResult(c, scope, result_used, node);
 }
 
@@ -2698,14 +2702,14 @@ fn transCreatePreCrement(
     defer block_scope.deinit();
     const ref = try block_scope.makeMangledName(c, "ref");
 
-    const expr = try transExpr(c, scope, op_expr, .used);
+    const expr = try transExpr(c, &block_scope.base, op_expr, .used);
     const addr_of = try Tag.address_of.create(c.arena, expr);
     const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of });
     try block_scope.statements.append(ref_decl);
 
     const lhs_node = try Tag.identifier.create(c.arena, ref);
     const ref_node = try Tag.deref.create(c.arena, lhs_node);
-    const node = try transCreateNodeInfixOp(c, scope, op, ref_node, Tag.one_literal.init(), .used);
+    const node = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, Tag.one_literal.init(), .used);
     try block_scope.statements.append(node);
 
     const break_node = try Tag.break_val.create(c.arena, .{
@@ -2745,7 +2749,7 @@ fn transCreatePostCrement(
     defer block_scope.deinit();
     const ref = try block_scope.makeMangledName(c, "ref");
 
-    const expr = try transExpr(c, scope, op_expr, .used);
+    const expr = try transExpr(c, &block_scope.base, op_expr, .used);
     const addr_of = try Tag.address_of.create(c.arena, expr);
     const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of });
     try block_scope.statements.append(ref_decl);
@@ -2757,7 +2761,7 @@ fn transCreatePostCrement(
     const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = ref_node });
     try block_scope.statements.append(tmp_decl);
 
-    const node = try transCreateNodeInfixOp(c, scope, op, ref_node, Tag.one_literal.init(), .used);
+    const node = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, Tag.one_literal.init(), .used);
     try block_scope.statements.append(node);
 
     const break_node = try Tag.break_val.create(c.arena, .{
@@ -2864,7 +2868,7 @@ fn transCreateCompoundAssign(
     defer block_scope.deinit();
     const ref = try block_scope.makeMangledName(c, "ref");
 
-    const expr = try transExpr(c, scope, lhs, .used);
+    const expr = try transExpr(c, &block_scope.base, lhs, .used);
     const addr_of = try Tag.address_of.create(c.arena, expr);
     const ref_decl = try Tag.var_simple.create(c.arena, .{ .name = ref, .init = addr_of });
     try block_scope.statements.append(ref_decl);
@@ -2873,16 +2877,16 @@ fn transCreateCompoundAssign(
     const ref_node = try Tag.deref.create(c.arena, lhs_node);
 
     if ((is_mod or is_div) and is_signed) {
-        const rhs_node = try transExpr(c, scope, rhs, .used);
+        const rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
         const builtin = if (is_mod)
             try Tag.rem.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node })
         else
             try Tag.div_trunc.create(c.arena, .{ .lhs = lhs_node, .rhs = rhs_node });
 
-        const assign = try transCreateNodeInfixOp(c, scope, .assign, lhs_node, builtin, .used);
+        const assign = try transCreateNodeInfixOp(c, &block_scope.base, .assign, lhs_node, builtin, .used);
         try block_scope.statements.append(assign);
     } else {
-        var rhs_node = try transExpr(c, scope, rhs, .used);
+        var rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
 
         if (is_shift or requires_int_cast) {
             // @intCast(rhs)
@@ -2894,7 +2898,7 @@ fn transCreateCompoundAssign(
             rhs_node = try Tag.int_cast.create(c.arena, .{ .lhs = cast_to_type, .rhs = rhs_node });
         }
 
-        const assign = try transCreateNodeInfixOp(c, scope, op, ref_node, rhs_node, .used);
+        const assign = try transCreateNodeInfixOp(c, &block_scope.base, op, ref_node, rhs_node, .used);
         try block_scope.statements.append(assign);
     }
 
@@ -3395,7 +3399,7 @@ fn transCreateNodeAssign(
     defer block_scope.deinit();
 
     const tmp = try block_scope.makeMangledName(c, "tmp");
-    const rhs_node = try transExpr(c, scope, rhs, .used);
+    const rhs_node = try transExpr(c, &block_scope.base, rhs, .used);
     const tmp_decl = try Tag.var_simple.create(c.arena, .{ .name = tmp, .init = rhs_node });
     try block_scope.statements.append(tmp_decl);
 
@@ -4756,8 +4760,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
                     return error.ParseError;
                 }
 
-                const ident = try Tag.identifier.create(c.arena, m.slice());
-                node = try Tag.field_access.create(c.arena, .{ .lhs = node, .rhs = ident });
+                node = try Tag.field_access.create(c.arena, .{ .lhs = node, .field_name = m.slice() });
             },
             .Arrow => {
                 if (m.next().? != .Identifier) {
@@ -4766,8 +4769,7 @@ fn parseCPostfixExpr(c: *Context, m: *MacroCtx, scope: *Scope) ParseError!Node {
                 }
 
                 const deref = try Tag.deref.create(c.arena, node);
-                const ident = try Tag.identifier.create(c.arena, m.slice());
-                node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .rhs = ident });
+                node = try Tag.field_access.create(c.arena, .{ .lhs = deref, .field_name = m.slice() });
             },
             .LBracket => {
                 const index = try macroBoolToInt(c, try parseCExpr(c, m, scope));
@@ -4914,13 +4916,12 @@ fn getContainer(c: *Context, node: Node) ?Node {
         },
 
         .field_access => {
-            const infix = node.castTag(.field_access).?;
+            const field_access = node.castTag(.field_access).?;
 
-            if (getContainerTypeOf(c, infix.data.lhs)) |ty_node| {
+            if (getContainerTypeOf(c, field_access.data.lhs)) |ty_node| {
                 if (ty_node.castTag(.@"struct") orelse ty_node.castTag(.@"union")) |container| {
                     for (container.data.fields) |field| {
-                        const ident = infix.data.rhs.castTag(.identifier).?;
-                        if (mem.eql(u8, field.name, ident.data)) {
+                        if (mem.eql(u8, field.name, field_access.data.field_name)) {
                             return getContainer(c, field.type);
                         }
                     }
@@ -4940,12 +4941,11 @@ fn getContainerTypeOf(c: *Context, ref: Node) ?Node {
                 return getContainer(c, var_decl.data.type);
             }
         }
-    } else if (ref.castTag(.field_access)) |infix| {
-        if (getContainerTypeOf(c, infix.data.lhs)) |ty_node| {
+    } else if (ref.castTag(.field_access)) |field_access| {
+        if (getContainerTypeOf(c, field_access.data.lhs)) |ty_node| {
             if (ty_node.castTag(.@"struct") orelse ty_node.castTag(.@"union")) |container| {
                 for (container.data.fields) |field| {
-                    const ident = infix.data.rhs.castTag(.identifier).?;
-                    if (mem.eql(u8, field.name, ident.data)) {
+                    if (mem.eql(u8, field.name, field_access.data.field_name)) {
                         return getContainer(c, field.type);
                     }
                 }