translate-c-2 fix expression grouping bugs

master
Vexu 2019-12-18 13:30:34 +02:00
parent f54e7d6c99
commit 62bfff5e87
No known key found for this signature in database
GPG Key ID: 59AEB8936E16A6AC
3 changed files with 88 additions and 66 deletions

View File

@ -1629,7 +1629,7 @@ fn renderExpression(
.If => {
const if_node = @fieldParentPtr(ast.Node.If, "base", base);
const lparen = tree.prevToken(if_node.condition.firstToken());
const lparen = tree.nextToken(if_node.if_token);
const rparen = tree.nextToken(if_node.condition.lastToken());
try renderToken(tree, stream, if_node.if_token, indent, start_col, Space.Space); // if

View File

@ -954,13 +954,6 @@ fn transBinaryOperator(
}
const lhs_node = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
switch (op) {
.PtrMemD, .PtrMemI, .Cmp => return revertAndWarn(
rp,
error.UnsupportedTranslation,
ZigClangBinaryOperator_getBeginLoc(stmt),
"TODO: handle more C binary operators: {}",
.{op},
),
.Add => {
if (cIsUnsignedInteger(qt)) {
op_token = try appendToken(rp.c, .PlusPercent, "+%");
@ -1205,6 +1198,26 @@ fn transBoolExpr(
undefined;
var res = try transExpr(rp, scope, expr, used, lrvalue);
if (isBoolRes(res))
return res;
const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr));
const node = try finishBoolExpr(rp, scope, ZigClangExpr_getBeginLoc(expr), ty, res, used);
if (grouped) {
const rparen = try appendToken(rp.c, .RParen, ")");
const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
grouped_expr.* = .{
.lparen = lparen,
.expr = node,
.rparen = rparen,
};
return maybeSuppressResult(rp, scope, used, &grouped_expr.base);
} else {
return maybeSuppressResult(rp, scope, used, node);
}
}
fn isBoolRes(res: *ast.Node) bool {
switch (res.id) {
.InfixOp => switch (@fieldParentPtr(ast.Node.InfixOp, "base", res).op) {
.BoolOr,
@ -1215,23 +1228,20 @@ fn transBoolExpr(
.GreaterThan,
.LessOrEqual,
.GreaterOrEqual,
=> return res,
=> return true,
else => {},
},
.PrefixOp => switch (@fieldParentPtr(ast.Node.PrefixOp, "base", res).op) {
.BoolNot => return res,
.BoolNot => return true,
else => {},
},
.BoolLiteral => return res,
.BoolLiteral => return true,
.GroupedExpression => return isBoolRes(@fieldParentPtr(ast.Node.GroupedExpression, "base", res).expr),
else => {},
}
const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr));
return finishBoolExpr(rp, scope, ZigClangExpr_getBeginLoc(expr), ty, res, used, grouped);
return false;
}
fn finishBoolExpr(
@ -1241,14 +1251,13 @@ fn finishBoolExpr(
ty: *const ZigClangType,
node: *ast.Node,
used: ResultUsed,
grouped: bool,
) TransError!*ast.Node {
switch (ZigClangType_getTypeClass(ty)) {
.Builtin => {
const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
switch (ZigClangBuiltinType_getKind(builtin_ty)) {
.Bool,
.Bool => return node,
.Char_U,
.UChar,
.Char_S,
@ -1276,12 +1285,12 @@ fn finishBoolExpr(
=> {
const op_token = try appendToken(rp.c, .BangEqual, "!=");
const rhs_node = try transCreateNodeInt(rp.c, 0);
return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, grouped);
return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
},
.NullPtr => {
const op_token = try appendToken(rp.c, .EqualEqual, "==");
const rhs_node = try transCreateNodeNullLiteral(rp.c);
return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, grouped);
return transCreateNodeInfixOp(rp, scope, node, .EqualEqual, op_token, rhs_node, used, false);
},
else => {},
}
@ -1289,13 +1298,13 @@ fn finishBoolExpr(
.Pointer => {
const op_token = try appendToken(rp.c, .BangEqual, "!=");
const rhs_node = try transCreateNodeNullLiteral(rp.c);
return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, grouped);
return transCreateNodeInfixOp(rp, scope, node, .BangEqual, op_token, rhs_node, used, false);
},
.Typedef => {
const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
const underlying_type = ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl);
return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(underlying_type), node, used, grouped);
return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(underlying_type), node, used);
},
.Enum => {
const enum_ty = @ptrCast(*const ZigClangEnumType, ty);
@ -1305,12 +1314,12 @@ fn finishBoolExpr(
const op_token = try appendToken(rp.c, .BangEqual, "!=");
const rhs_node = try transCreateNodeInt(rp.c, 0);
return transCreateNodeInfixOp(rp, scope, &builtin_node.base, .BangEqual, op_token, rhs_node, used, grouped);
return transCreateNodeInfixOp(rp, scope, &builtin_node.base, .BangEqual, op_token, rhs_node, used, false);
},
.Elaborated => {
const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);
const named_type = ZigClangElaboratedType_getNamedType(elaborated_ty);
return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(named_type), node, used, grouped);
return finishBoolExpr(rp, scope, loc, ZigClangQualType_getTypePtr(named_type), node, used);
},
else => {},
}
@ -2009,8 +2018,8 @@ fn transFloatingLiteral(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangFl
}
fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigClangConditionalOperator, used: ResultUsed) TransError!*ast.Node {
const gropued = scope.id == .Condition;
const lparen = if (gropued) try appendToken(rp.c, .LParen, "(") else undefined;
const grouped = scope.id == .Condition;
const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
const if_node = try transCreateNodeIf(rp.c);
var cond_scope = Scope{
.parent = scope,
@ -2029,7 +2038,7 @@ fn transConditionalOperator(rp: RestorePoint, scope: *Scope, stmt: *const ZigCla
if_node.@"else" = try transCreateNodeElse(rp.c);
if_node.@"else".?.body = try transExpr(rp, scope, false_expr, .used, .r_value);
if (gropued) {
if (grouped) {
const rparen = try appendToken(rp.c, .RParen, ")");
const grouped_expr = try rp.c.a().create(ast.Node.GroupedExpression);
grouped_expr.* = .{

View File

@ -1400,17 +1400,13 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\pub const Bar = enum_Bar;
});
cases.add_2("bitwise binary operators, simpler parens", // TODO can combine with "bitwise binary operators" when parens are correctly preserved/not added in translate-c-2
cases.add_2("bitwise binary operators, simpler parens",
\\int max(int a, int b) {
\\ int c = (a & b);
\\ int d = (a | b);
\\ return (c ^ d);
\\ return (a & b) ^ (a | b);
\\}
, &[_][]const u8{
\\pub export fn max(a: c_int, b: c_int) c_int {
\\ var c: c_int = (a & b);
\\ var d: c_int = (a | b);
\\ return (c ^ d);
\\ return ((a & b) ^ (a | b));
\\}
});
@ -1438,17 +1434,19 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
cases.add_2("==, !=, no if", // TODO remove this test after `if` conversion supported, and switch "==, !=" to addC_both
cases.add_2("==, !=",
\\int max(int a, int b) {
\\ int c = (a == b);
\\ int d = (a != b);
\\ return (c != d);
\\ if (a == b)
\\ return a;
\\ if (a != b)
\\ return b;
\\ return a;
\\}
, &[_][]const u8{
\\pub export fn max(a: c_int, b: c_int) c_int {
\\ var c: c_int = (a == b);
\\ var d: c_int = (a != b);
\\ return (c != d);
\\ if ((a == b)) return a;
\\ if ((a != b)) return b;
\\ return a;
\\}
});
@ -1464,6 +1462,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
cases.add_2("typedeffed bool expression",
\\typedef char* yes;
\\void foo(void) {
\\ yes a;
\\ if (a) 2;
\\}
, &[_][]const u8{
\\pub const yes = [*c]u8;
\\pub export fn foo() void {
\\ var a: yes = undefined;
\\ if (a != null) _ = 2;
\\}
});
/////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
cases.addAllowWarnings("simple data types",
@ -1575,31 +1587,6 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\}
});
cases.addC("==, !=",
\\int max(int a, int b) {
\\ if (a == b)
\\ return a;
\\ if (a != b)
\\ return b;
\\ return a;
\\}
, &[_][]const u8{
\\pub export fn max(a: c_int, b: c_int) c_int {
\\ if (a == b) return a;
\\ if (a != b) return b;
\\ return a;
\\}
});
cases.addC("bitwise binary operators",
\\int max(int a, int b) {
\\ return (a & b) ^ (a | b);
\\}
, &[_][]const u8{
\\pub export fn max(a: c_int, b: c_int) c_int {
\\ return (a & b) ^ (a | b);
\\}
});
cases.addC("logical and, logical or",
\\int max(int a, int b) {
\\ if (a < b || a == b)
@ -2596,4 +2583,30 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
\\ }
\\}
});
cases.addC("==, !=",
\\int max(int a, int b) {
\\ if (a == b)
\\ return a;
\\ if (a != b)
\\ return b;
\\ return a;
\\}
, &[_][]const u8{
\\pub export fn max(a: c_int, b: c_int) c_int {
\\ if (a == b) return a;
\\ if (a != b) return b;
\\ return a;
\\}
});
cases.addC("bitwise binary operators",
\\int max(int a, int b) {
\\ return (a & b) ^ (a | b);
\\}
, &[_][]const u8{
\\pub export fn max(a: c_int, b: c_int) c_int {
\\ return (a & b) ^ (a | b);
\\}
});
}