translate-c: render array stuff

This commit is contained in:
Veikka Tuominen 2021-02-14 18:06:15 +02:00
parent 62162a0717
commit c0540967e9
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
3 changed files with 227 additions and 59 deletions

View File

@ -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);

View File

@ -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);
}
}

View File

@ -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,