diff options
| author | Veikka Tuominen <git@vexu.eu> | 2021-02-07 22:02:42 +0200 |
|---|---|---|
| committer | Veikka Tuominen <git@vexu.eu> | 2021-02-16 16:37:07 +0200 |
| commit | f5041caa2e9d1e891bd93aa2721a4a283123f0d9 (patch) | |
| tree | d54ecc828fd0f04431939c31a5019c3820e14f78 /src | |
| parent | 4c0c9b07555bb69d05142dfe038a7cad79068ba9 (diff) | |
| download | zig-f5041caa2e9d1e891bd93aa2721a4a283123f0d9.tar.gz zig-f5041caa2e9d1e891bd93aa2721a4a283123f0d9.zip | |
translate-c: more binaryoperator chagnes, blocks and unary type expressions
Diffstat (limited to 'src')
| -rw-r--r-- | src/translate_c.zig | 273 | ||||
| -rw-r--r-- | src/translate_c/ast.zig | 80 |
2 files changed, 156 insertions, 197 deletions
diff --git a/src/translate_c.zig b/src/translate_c.zig index f885ea98b9..6570766988 100644 --- a/src/translate_c.zig +++ b/src/translate_c.zig @@ -68,16 +68,15 @@ const Scope = struct { } }; - /// Represents an in-progress ast.Node.Block. This struct is stack-allocated. - /// When it is deinitialized, it produces an ast.Node.Block which is allocated + /// Represents an in-progress Node.Block. This struct is stack-allocated. + /// When it is deinitialized, it produces an Node.Block which is allocated /// into the main arena. const Block = struct { base: Scope, - statements: std.ArrayList(*ast.Node), + statements: std.ArrayList(Node), variables: AliasList, - label: ?ast.TokenIndex, mangle_count: u32 = 0, - lbrace: ast.TokenIndex, + label: ?[]const u8 = null, /// When the block corresponds to a function, keep track of the return type /// so that the return expression can be cast, if necessary @@ -89,14 +88,11 @@ const Scope = struct { .id = .Block, .parent = parent, }, - .statements = std.ArrayList(*ast.Node).init(c.gpa), + .statements = std.ArrayList(Node).init(c.gpa), .variables = AliasList.init(c.gpa), - .label = null, - .lbrace = try appendToken(c, .LBrace, "{"), }; if (labeled) { - blk.label = try appendIdentifier(c, try blk.makeMangledName(c, "blk")); - _ = try appendToken(c, .Colon, ":"); + blk.label = try blk.makeMangledName(c, "blk"); } return blk; } @@ -107,31 +103,16 @@ const Scope = struct { self.* = undefined; } - fn complete(self: *Block, c: *Context) !*ast.Node { + fn complete(self: *Block, c: *Context) !Node { // We reserve 1 extra statement if the parent is a Loop. This is in case of // do while, we want to put `if (cond) break;` at the end. const alloc_len = self.statements.items.len + @boolToInt(self.base.parent.?.id == .Loop); - const rbrace = try appendToken(c, .RBrace, "}"); - if (self.label) |label| { - const node = try ast.Node.LabeledBlock.alloc(c.arena, alloc_len); - node.* = .{ - .statements_len = self.statements.items.len, - .lbrace = self.lbrace, - .rbrace = rbrace, - .label = label, - }; - mem.copy(*ast.Node, node.statements(), self.statements.items); - return &node.base; - } else { - const node = try ast.Node.Block.alloc(c.arena, alloc_len); - node.* = .{ - .statements_len = self.statements.items.len, - .lbrace = self.lbrace, - .rbrace = rbrace, - }; - mem.copy(*ast.Node, node.statements(), self.statements.items); - return &node.base; - } + const stmts = try c.arena.alloc(Node, alloc_len); + mem.copy(Node, stmts, self.statements.items); + return Node.block.create(c.arena, .{ + .lable = self.label, + .stmts = stmts, + }); } /// Given the desired name, return a name that does not shadow anything from outer scopes. @@ -1390,7 +1371,7 @@ fn transBinaryOperator( // signed integer division uses @divTrunc const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value); const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value); - const div_trunc = try Node.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs}); + const div_trunc = try Node.div_trunc.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); return maybeSuppressResult(c, scope, result_used, div_trunc); } }, @@ -1399,7 +1380,7 @@ fn transBinaryOperator( // signed integer division uses @rem const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value); const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value); - const rem = try Node.rem.create(c.arena, .{ .lhs = lhs, .rhs = rhs}); + const rem = try Node.rem.create(c.arena, .{ .lhs = lhs, .rhs = rhs }); return maybeSuppressResult(c, scope, result_used, rem); } }, @@ -1411,6 +1392,12 @@ fn transBinaryOperator( const node = try transCreateNodeShiftOp(c, scope, stmt, .shr); return maybeSuppressResult(c, scope, result_used, node); }, + .LAnd => { + return transCreateNodeBoolInfixOp(c, scope, stmt, .bool_and, result_used, true); + }, + .LOr => { + return transCreateNodeBoolInfixOp(c, scope, stmt, .bool_or, result_used, true); + }, else => {}, } var op_id: Node.Tag = undefined; @@ -1471,17 +1458,19 @@ fn transBinaryOperator( .Or => { op_id = .bit_or; }, - .LAnd => { - op_id = .@"and"; - }, - .LOr => { - op_id = .@"or"; - }, else => unreachable, } - const lhs = try transExpr(c, scope, stmt.getLHS(), .used, .l_value); - const rhs = try transExpr(c, scope, stmt.getRHS(), .used, .r_value); + const lhs_uncasted = try transExpr(c, scope, stmt.getLHS(), .used, .l_value); + const rhs_uncasted = try transExpr(c, scope, stmt.getRHS(), .used, .r_value); + + const lhs = if (isBoolRes(lhs_uncasted)) + try Node.bool_to_int.create(c.arena, lhs_uncasted) + else lhs_uncasted; + + const rhs = if (isBoolRes(rhs_uncasted)) + try Node.bool_to_int.create(c.arena, rhs_uncasted) + else rhs_uncasted; const payload = try c.arena.create(ast.Payload.BinOp); payload.* = .{ @@ -1495,7 +1484,7 @@ fn transBinaryOperator( } fn transCompoundStmtInline( - rp: RestorePoint, + c: *Context, parent_scope: *Scope, stmt: *const clang.CompoundStmt, block: *Scope.Block, @@ -1503,16 +1492,16 @@ fn transCompoundStmtInline( var it = stmt.body_begin(); const end_it = stmt.body_end(); while (it != end_it) : (it += 1) { - const result = try transStmt(rp, parent_scope, it[0], .unused, .r_value); + const result = try transStmt(c, parent_scope, it[0], .unused, .r_value); try block.statements.append(result); } } -fn transCompoundStmt(rp: RestorePoint, scope: *Scope, stmt: *const clang.CompoundStmt) TransError!*ast.Node { - var block_scope = try Scope.Block.init(rp.c, scope, false); +fn transCompoundStmt(c: *Context, scope: *Scope, stmt: *const clang.CompoundStmt) TransError!Node { + var block_scope = try Scope.Block.init(c, scope, false); defer block_scope.deinit(); - try transCompoundStmtInline(rp, &block_scope.base, stmt, &block_scope); - return try block_scope.complete(rp.c); + try transCompoundStmtInline(c, &block_scope.base, stmt, &block_scope); + return try block_scope.complete(c); } fn transCStyleCastExprClass( @@ -3233,22 +3222,18 @@ fn qualTypeGetFnProto(qt: clang.QualType, is_ptr: *bool) ?ClangFunctionType { } fn transUnaryExprOrTypeTraitExpr( - rp: RestorePoint, + c: *Context, scope: *Scope, stmt: *const clang.UnaryExprOrTypeTraitExpr, result_used: ResultUsed, -) TransError!*ast.Node { +) TransError!Node { const loc = stmt.getBeginLoc(); - const type_node = try transQualType( - rp, - stmt.getTypeOfArgument(), - loc, - ); + const type_node = try transQualType(rp, stmt.getTypeOfArgument(), loc); const kind = stmt.getKind(); - const kind_str = switch (kind) { - .SizeOf => "@sizeOf", - .AlignOf => "@alignOf", + switch (kind) { + .SizeOf => return Node.sizeof.create(c.arena, type_node), + .AlignOf => return Node.alignof.create(c.arena, type_node), .PreferredAlignOf, .VecStep, .OpenMPRequiredSimdAlign, @@ -3259,12 +3244,7 @@ fn transUnaryExprOrTypeTraitExpr( "Unsupported type trait kind {}", .{kind}, ), - }; - - const builtin_node = try rp.c.createBuiltinCall(kind_str, 1); - builtin_node.params()[0] = type_node; - builtin_node.rparen_token = try appendToken(rp.c, .RParen, ")"); - return maybeSuppressResult(rp, scope, result_used, &builtin_node.base); + } } fn qualTypeHasWrappingOverflow(qt: clang.QualType) bool { @@ -3967,8 +3947,8 @@ fn transQualTypeInitialized( return transQualType(rp, qt, source_loc); } -fn transQualType(rp: RestorePoint, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!*ast.Node { - return transType(rp, qt.getTypePtr(), source_loc); +fn transQualType(c: *Context, qt: clang.QualType, source_loc: clang.SourceLocation) TypeError!Node { + return transType(c, qt.getTypePtr(), source_loc); } /// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness. @@ -4318,19 +4298,27 @@ fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []c return &field_access_node.base; } -fn transCreateNodeSimplePrefixOp( +fn transCreateNodeBoolInfixOp( c: *Context, - comptime tag: ast.Node.Tag, - op_tok_id: std.zig.Token.Id, - bytes: []const u8, -) !*ast.Node.SimplePrefixOp { - const node = try c.arena.create(ast.Node.SimplePrefixOp); - node.* = .{ - .base = .{ .tag = tag }, - .op_token = try appendToken(c, op_tok_id, bytes), - .rhs = undefined, // translate and set afterward + scope: *Scope, + stmt: *const clang.BinaryOperator, + op: ast.Node.Tag, + used: ResultUsed, +) !Node { + std.debug.assert(op == .bool_and or op == .bool_or); + + const lhs = try transBoolExpr(rp, scope, stmt.getLHS(), .used, .l_value, true); + const rhs = try transBoolExpr(rp, scope, stmt.getRHS(), .used, .r_value, true); + + const payload = try c.arena.create(ast.Payload.BinOp); + payload.* = .{ + .base = .{ .tag = op }, + .data = .{ + .lhs = lhs, + .rhs = rhs, + }, }; - return node; + return maybeSuppressResult(c, scope, used, &payload.base); } fn transCreateNodePtrType( @@ -4784,30 +4772,30 @@ fn transCreateNodeArrayAccess(c: *Context, lhs: *ast.Node) !*ast.Node.ArrayAcces return node; } -fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Type { +fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocation) TypeError!Node { switch (ty.getTypeClass()) { .Builtin => { const builtin_ty = @ptrCast(*const clang.BuiltinType, ty); - return Type.initTag(switch (builtin_ty.getKind()) { - .Void => .c_void, - .Bool => .bool, - .Char_U, .UChar, .Char_S, .Char8 => .u8, - .SChar => .i8, - .UShort => .c_ushort, - .UInt => .c_uint, - .ULong => .c_ulong, - .ULongLong => .c_ulonglong, - .Short => .c_short, - .Int => .c_int, - .Long => .c_long, - .LongLong => .c_longlong, - .UInt128 => .u128, - .Int128 => .i128, - .Float => .f32, - .Double => .f64, - .Float128 => .f128, - .Float16 => .f16, - .LongDouble => .c_longdouble, + return Node.type.create(c.arena, switch (builtin_ty.getKind()) { + .Void => "c_void", + .Bool => "bool", + .Char_U, .UChar, .Char_S, .Char8 => "u8", + .SChar => "i8", + .UShort => "c_ushort", + .UInt => "c_uint", + .ULong => "c_ulong", + .ULongLong => "c_ulonglong", + .Short => "c_short", + .Int => "c_int", + .Long => "c_long", + .LongLong => "c_longlong", + .UInt128 => "u128", + .Int128 => "i128", + .Float => "f32", + .Double => "f64", + .Float128 => "f128", + .Float16 => "f16", + .LongDouble => "c_longdouble", else => return fail(c, error.UnsupportedType, source_loc, "unsupported builtin type", .{}), }); }, @@ -4826,61 +4814,25 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio .Pointer => { const child_qt = ty.getPointeeType(); if (qualTypeChildIsFnProto(child_qt)) { - return Type.optional_single_mut_pointer.create(c.arena, try transQualType(c, child_qt, source_loc)); + return Node.optional_type.create(c.arena, try transQualType(c, child_qt, source_loc)); } const is_const = child_qt.isConstQualified(); const is_volatile = child_qt.isVolatileQualified(); const elem_type = try transQualType(c, child_qt, source_loc); - if (elem_type.zigTypeTag() == .Opaque) { - if (!is_volatile) { - if (is_const) { - return Type.optional_single_const_pointer.create(c.arena, elem_type); - } else { - return Type.optional_single_mut_pointer.create(c.arena, elem_type); - } - } - - return Type.pointer.create(c.arena, .{ - .pointee_type = elem_type, - .sentinel = null, - .@"align" = 0, - .bit_offset = 0, - .host_size = 0, - .@"allowzero" = false, - .mutable = !is_const, - .@"volatile" = true, - .size = .Single, - }); + if (typeIsOpaque(rp.c, child_qt.getTypePtr(), source_loc) or qualTypeWasDemotedToOpaque(rp.c, child_qt)) { + return Node.single_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); } - if (!is_volatile) { - if (is_const) { - return Type.c_const_pointer.create(c.arena, elem_type); - } else { - return Type.c_mut_pointer.create(c.arena, elem_type); - } - } - - return Type.pointer.create(c.arena, .{ - .pointee_type = elem_type, - .sentinel = null, - .@"align" = 0, - .bit_offset = 0, - .host_size = 0, - .@"allowzero" = false, - .mutable = !is_const, - .@"volatile" = true, - .size = .C, - }); + return Node.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); }, .ConstantArray => { const const_arr_ty = @ptrCast(*const clang.ConstantArrayType, ty); const size_ap_int = const_arr_ty.getSize(); const size = size_ap_int.getLimitedValue(math.maxInt(usize)); - const elem_type = try transType1(c, const_arr_ty.getElementType().getTypePtr(), source_loc); - - return Type.array.create(c.arena, .{ .len = size, .elem_type = elem_type }); + const elem_type = try transType(c, const_arr_ty.getElementType().getTypePtr(), source_loc); + + return Node.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type }); }, .IncompleteArray => { const incomplete_array_ty = @ptrCast(*const clang.IncompleteArrayType, ty); @@ -4890,25 +4842,7 @@ fn transType(c: *Context, ty: *const clang.Type, source_loc: clang.SourceLocatio const is_volatile = child_qt.isVolatileQualified(); const elem_type = try transQualType(c, child_qt, source_loc); - if (!is_volatile) { - if (is_const) { - return Type.c_const_pointer.create(c.arena, elem_type); - } else { - return Type.c_mut_pointer.create(c.arena, elem_type); - } - } - - return Type.pointer.create(c.arena, .{ - .pointee_type = elem_type, - .sentinel = null, - .@"align" = 0, - .bit_offset = 0, - .host_size = 0, - .@"allowzero" = false, - .mutable = !is_const, - .@"volatile" = true, - .size = .C, - }); + return Node.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); }, .Typedef => { const typedef_ty = @ptrCast(*const clang.TypedefType, ty); @@ -5233,25 +5167,14 @@ fn finishTransFnProto( return fn_proto; } -fn revertAndWarn( - rp: RestorePoint, - err: anytype, - source_loc: clang.SourceLocation, - comptime format: []const u8, - args: anytype, -) (@TypeOf(err) || error{OutOfMemory}) { - rp.activate(); - try emitWarning(rp.c, source_loc, format, args); - return err; -} - -fn emitWarning(c: *Context, loc: clang.SourceLocation, comptime format: []const u8, args: anytype) !void { +fn warn(c: *Context, scope: *Scope, loc: clang.SourceLocation, comptime format: []const u8, args: anytype) !void { const args_prefix = .{c.locStr(loc)}; - _ = try appendTokenFmt(c, .LineComment, "// {s}: warning: " ++ format, args_prefix ++ args); + const value = std.fmt.allocPrint(c.arena, "// {s}: warning: " ++ format, args_prefix ++ args); + try scope.appendNode(c.gpa, try Node.warning.create(c.arena, value)); } fn fail( - rp: RestorePoint, + c: *Context, err: anytype, source_loc: clang.SourceLocation, comptime format: []const u8, diff --git a/src/translate_c/ast.zig b/src/translate_c/ast.zig index 3ceccf16b8..638d4cefa0 100644 --- a/src/translate_c/ast.zig +++ b/src/translate_c/ast.zig @@ -107,6 +107,25 @@ pub const Node = extern union { rem, /// @divTrunc(lhs, rhs) div_trunc, + /// @boolToInt(lhs, rhs) + bool_to_int, + + negate, + negate_wrap, + bit_not, + not, + + block, + @"break", + + sizeof, + alignof, + type, + + optional_type, + c_pointer, + single_pointer, + array_type, pub const last_no_payload_tag = Tag.false_literal; pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1; @@ -127,6 +146,14 @@ pub const Node = extern union { .@"return", .discard, .std_math_Log2Int, + .negate, + .negate_wrap, + .bit_not, + .not, + .optional_type, + .c_pointer, + .single_pointer, + .array_type, => Payload.UnOp, .add, @@ -180,6 +207,7 @@ pub const Node = extern union { .div_trunc, .rem, .int_cast, + .bool_to_int, => Payload.BinOp, .int, @@ -191,6 +219,9 @@ pub const Node = extern union { .field_access_arrow, .warning, .failed_decl, + .sizeof, + .alignof, + .type, => Payload.Value, .@"if" => Payload.If, .@"while" => Payload.While, @@ -234,8 +265,8 @@ pub const Payload = struct { pub const Infix = struct { base: Node, data: struct { - lhs: *Node, - rhs: *Node, + lhs: Node, + rhs: Node, }, }; @@ -246,44 +277,44 @@ pub const Payload = struct { pub const UnOp = struct { base: Node, - data: *Node, + data: Node, }; pub const BinOp = struct { base: Node, data: struct { - lhs: *Node, - rhs: *Node, + lhs: Node, + rhs: Node, }, }; pub const If = struct { base: Node = .{ .tag = .@"if" }, data: struct { - cond: *Node, - then: *Node, - @"else": ?*Node, + cond: Node, + then: Node, + @"else": ?Node, }, }; pub const While = struct { base: Node = .{ .tag = .@"while" }, data: struct { - cond: *Node, - body: *Node, + cond: Node, + body: Node, }, }; pub const Switch = struct { base: Node = .{ .tag = .@"switch" }, data: struct { - cond: *Node, + cond: Node, cases: []Prong, default: ?[]const u8, pub const Prong = struct { - lhs: *Node, - rhs: ?*Node, + lhs: Node, + rhs: ?Node, label: []const u8, }; }, @@ -293,15 +324,15 @@ pub const Payload = struct { base: Node = .{ .tag = .@"break" }, data: struct { label: ?[]const u8, - rhs: ?*Node, + rhs: ?Node, }, }; pub const Call = struct { base: Node = .{.call}, data: struct { - lhs: *Node, - args: []*Node, + lhs: Node, + args: []Node, }, }; @@ -314,7 +345,7 @@ pub const Payload = struct { @"export": bool, name: []const u8, type: Type, - init: *Node, + init: Node, }, }; @@ -328,7 +359,7 @@ pub const Payload = struct { cc: std.builtin.CallingConvention, params: []Param, return_type: Type, - body: ?*Node, + body: ?Node, pub const Param = struct { @"noalias": bool, @@ -368,7 +399,7 @@ pub const Payload = struct { pub const ArrayInit = struct { base: Node = .{ .tag = .array_init }, - data: []*Node, + data: []Node, }; pub const ContainerInit = struct { @@ -377,17 +408,22 @@ pub const Payload = struct { pub const Initializer = struct { name: []const u8, - value: *Node, + value: Node, }; }; pub const Block = struct { - base: Node = .{ .tag = .block }, + base: Node, data: struct { label: ?[]const u8, - stmts: []*Node, + stmts: []Node }, }; + + pub const Break = struct { + base: Node = .{ .tag = .@"break" }, + data: *Block + }; }; /// Converts the nodes into a Zig ast and then renders it. |
