authorgravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-12-18 09:51:40+02:00
committergravatar for git@vexu.euVeikka Tuominen <git@vexu.eu> 2019-12-18 09:51:40+02:00
log90eed4172d9c4caebe736c2fbf4f9f70c98013c6
treef2ae133a9e20eebde8087d19fcae4b613f040f19
parent21bc3353b8812ea097afb52fef411a4fb32bfea9
parent0c03fe48b308ba907e69d1e442d60f556b7bdd8c
signature Commit is signed but in an unrecognized format.

Merge remote-tracking branch 'kavika13/master' into translate-c-2


2 files changed, 798 insertions(+), 43 deletions(-)

src-self-hosted/translate_c.zig+631-26
......@@ -943,26 +943,110 @@ fn transBinaryOperator(
943943 return maybeSuppressResult(rp, scope, result_used, node);
944944 }
945945 },
946 .Shl,
947 .Shr,
948 .LT,
949 .GT,
950 .LE,
951 .GE,
952 .EQ,
953 .NE,
954 .And,
955 .Xor,
956 .Or,
957 .LAnd,
958 .LOr,
959 => return revertAndWarn(
960 rp,
961 error.UnsupportedTranslation,
962 ZigClangBinaryOperator_getBeginLoc(stmt),
963 "TODO: handle more C binary operators: {}",
964 .{op},
965 ),
946 .Shl => {
947 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftLeft, .AngleBracketAngleBracketLeft, "<<");
948 return maybeSuppressResult(rp, scope, result_used, TransResult{
949 .node = node,
950 .child_scope = scope,
951 .node_scope = scope,
952 });
953 },
954 .Shr => {
955 const node = try transCreateNodeShiftOp(rp, scope, stmt, .BitShiftRight, .AngleBracketAngleBracketRight, ">>");
956 return maybeSuppressResult(rp, scope, result_used, TransResult{
957 .node = node,
958 .child_scope = scope,
959 .node_scope = scope,
960 });
961 },
962 .LT => {
963 const node = try transCreateNodeInfixOp(rp, scope, stmt, .LessThan, .AngleBracketLeft, "<", true);
964 return maybeSuppressResult(rp, scope, result_used, TransResult{
965 .node = node,
966 .child_scope = scope,
967 .node_scope = scope,
968 });
969 },
970 .GT => {
971 const node = try transCreateNodeInfixOp(rp, scope, stmt, .GreaterThan, .AngleBracketRight, ">", true);
972 return maybeSuppressResult(rp, scope, result_used, TransResult{
973 .node = node,
974 .child_scope = scope,
975 .node_scope = scope,
976 });
977 },
978 .LE => {
979 const node = try transCreateNodeInfixOp(rp, scope, stmt, .LessOrEqual, .AngleBracketLeftEqual, "<=", true);
980 return maybeSuppressResult(rp, scope, result_used, TransResult{
981 .node = node,
982 .child_scope = scope,
983 .node_scope = scope,
984 });
985 },
986 .GE => {
987 const node = try transCreateNodeInfixOp(rp, scope, stmt, .GreaterOrEqual, .AngleBracketRightEqual, ">=", true);
988 return maybeSuppressResult(rp, scope, result_used, TransResult{
989 .node = node,
990 .child_scope = scope,
991 .node_scope = scope,
992 });
993 },
994 .EQ => {
995 const node = try transCreateNodeInfixOp(rp, scope, stmt, .EqualEqual, .EqualEqual, "==", true);
996 return maybeSuppressResult(rp, scope, result_used, TransResult{
997 .node = node,
998 .child_scope = scope,
999 .node_scope = scope,
1000 });
1001 },
1002 .NE => {
1003 const node = try transCreateNodeInfixOp(rp, scope, stmt, .BangEqual, .BangEqual, "!=", true);
1004 return maybeSuppressResult(rp, scope, result_used, TransResult{
1005 .node = node,
1006 .child_scope = scope,
1007 .node_scope = scope,
1008 });
1009 },
1010 .And => {
1011 const node = try transCreateNodeInfixOp(rp, scope, stmt, .BitAnd, .Ampersand, "&", true);
1012 return maybeSuppressResult(rp, scope, result_used, TransResult{
1013 .node = node,
1014 .child_scope = scope,
1015 .node_scope = scope,
1016 });
1017 },
1018 .Xor => {
1019 const node = try transCreateNodeInfixOp(rp, scope, stmt, .BitXor, .Caret, "^", true);
1020 return maybeSuppressResult(rp, scope, result_used, TransResult{
1021 .node = node,
1022 .child_scope = scope,
1023 .node_scope = scope,
1024 });
1025 },
1026 .Or => {
1027 const node = try transCreateNodeInfixOp(rp, scope, stmt, .BitOr, .Pipe, "|", true);
1028 return maybeSuppressResult(rp, scope, result_used, TransResult{
1029 .node = node,
1030 .child_scope = scope,
1031 .node_scope = scope,
1032 });
1033 },
1034 .LAnd => {
1035 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolAnd, .Keyword_and, "and");
1036 return maybeSuppressResult(rp, scope, result_used, TransResult{
1037 .node = node,
1038 .child_scope = scope,
1039 .node_scope = scope,
1040 });
1041 },
1042 .LOr => {
1043 const node = try transCreateNodeBoolInfixOp(rp, scope, stmt, .BoolOr, .Keyword_or, "or");
1044 return maybeSuppressResult(rp, scope, result_used, TransResult{
1045 .node = node,
1046 .child_scope = scope,
1047 .node_scope = scope,
1048 });
1049 },
9661050 .Comma => {
9671051 const block_scope = try scope.findBlockScope(rp.c);
9681052 const expr = block_scope.base.parent == scope;
......@@ -1147,6 +1231,327 @@ fn transImplicitCastExpr(
11471231 }
11481232}
11491233
1234fn toEnumZeroCmp(
1235 rp: RestorePoint,
1236 scope: *Scope,
1237 expr: *ast.Node,
1238 generate_enum_node: fn (RestorePoint, *const struct_ZigClangType, source_loc: ZigClangSourceLocation) TransError!*ast.Node,
1239 enum_ty: *const struct_ZigClangType,
1240 enum_source_loc: ZigClangSourceLocation,
1241) !*ast.Node {
1242 // expr != @bitCast(EnumType, @as(@TagType(EnumType), 0))
1243
1244 // @bitCast(Enum,
1245 const bitcast = try transCreateNodeBuiltinFnCall(rp.c, "@bitCast");
1246 const bitcast_enum_identifier = try generate_enum_node(rp, enum_ty, enum_source_loc);
1247 try bitcast.params.push(bitcast_enum_identifier);
1248 _ = try appendToken(rp.c, .Comma, ",");
1249
1250 // @as(
1251 const cast_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
1252
1253 // @TagType(Enum),
1254 const tag_type = try transCreateNodeBuiltinFnCall(rp.c, "@TagType");
1255 const tag_type_enum_identifier = try generate_enum_node(rp, enum_ty, enum_source_loc);
1256 try tag_type.params.push(tag_type_enum_identifier);
1257 tag_type.rparen_token = try appendToken(rp.c, .RParen, ")");
1258 try cast_node.params.push(&tag_type.base);
1259 _ = try appendToken(rp.c, .Comma, ",");
1260
1261 // 0)
1262 const zero = try transCreateNodeInt(rp.c, 0);
1263 try cast_node.params.push(zero);
1264 cast_node.rparen_token = try appendToken(rp.c, .RParen, ")");
1265
1266 try bitcast.params.push(&cast_node.base);
1267 bitcast.rparen_token = try appendToken(rp.c, .RParen, ")");
1268
1269 // expr != @bitCast(EnumType, @as(@TagType(EnumType), 0))
1270 return transCreateNodeNotEqual(rp, scope, expr, &bitcast.base);
1271}
1272
1273fn transBoolExpr(
1274 rp: RestorePoint,
1275 scope: *Scope,
1276 expr: *const ZigClangExpr,
1277 used: ResultUsed,
1278 lrvalue: LRValue,
1279) !*ast.Node {
1280 var res = try transExpr(rp, scope, expr, used, lrvalue);
1281
1282 switch (res.node.id) {
1283 .InfixOp => switch (@ptrCast(*const ast.Node.InfixOp, &res.node).op) {
1284 .BoolOr,
1285 .BoolAnd,
1286 .EqualEqual,
1287 .BangEqual,
1288 .LessThan,
1289 .GreaterThan,
1290 .LessOrEqual,
1291 .GreaterOrEqual,
1292 => return res.node,
1293
1294 else => {},
1295 },
1296
1297 .PrefixOp => switch (@ptrCast(*const ast.Node.PrefixOp, &res.node).op) {
1298 .BoolNot => return res.node,
1299
1300 else => {},
1301 },
1302
1303 .BoolLiteral => return res.node,
1304
1305 else => {},
1306 }
1307
1308 const ty = ZigClangQualType_getTypePtr(getExprQualTypeBeforeImplicitCast(rp.c, expr));
1309
1310 switch (ZigClangType_getTypeClass(ty)) {
1311 .Builtin => {
1312 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
1313
1314 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
1315 .Bool,
1316 .Char_U,
1317 .UChar,
1318 .Char_S,
1319 .SChar,
1320 .UShort,
1321 .UInt,
1322 .ULong,
1323 .ULongLong,
1324 .Short,
1325 .Int,
1326 .Long,
1327 .LongLong,
1328 .UInt128,
1329 .Int128,
1330 .Float,
1331 .Double,
1332 .Float128,
1333 .LongDouble,
1334 .WChar_U,
1335 .Char8,
1336 .Char16,
1337 .Char32,
1338 .WChar_S,
1339 .Float16,
1340 => return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeInt(rp.c, 0)),
1341
1342 .NullPtr => return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeNullLiteral(rp.c)),
1343
1344 .Void,
1345 .Half,
1346 .ObjCId,
1347 .ObjCClass,
1348 .ObjCSel,
1349 .OMPArraySection,
1350 .Dependent,
1351 .Overload,
1352 .BoundMember,
1353 .PseudoObject,
1354 .UnknownAny,
1355 .BuiltinFn,
1356 .ARCUnbridgedCast,
1357 .OCLImage1dRO,
1358 .OCLImage1dArrayRO,
1359 .OCLImage1dBufferRO,
1360 .OCLImage2dRO,
1361 .OCLImage2dArrayRO,
1362 .OCLImage2dDepthRO,
1363 .OCLImage2dArrayDepthRO,
1364 .OCLImage2dMSAARO,
1365 .OCLImage2dArrayMSAARO,
1366 .OCLImage2dMSAADepthRO,
1367 .OCLImage2dArrayMSAADepthRO,
1368 .OCLImage3dRO,
1369 .OCLImage1dWO,
1370 .OCLImage1dArrayWO,
1371 .OCLImage1dBufferWO,
1372 .OCLImage2dWO,
1373 .OCLImage2dArrayWO,
1374 .OCLImage2dDepthWO,
1375 .OCLImage2dArrayDepthWO,
1376 .OCLImage2dMSAAWO,
1377 .OCLImage2dArrayMSAAWO,
1378 .OCLImage2dMSAADepthWO,
1379 .OCLImage2dArrayMSAADepthWO,
1380 .OCLImage3dWO,
1381 .OCLImage1dRW,
1382 .OCLImage1dArrayRW,
1383 .OCLImage1dBufferRW,
1384 .OCLImage2dRW,
1385 .OCLImage2dArrayRW,
1386 .OCLImage2dDepthRW,
1387 .OCLImage2dArrayDepthRW,
1388 .OCLImage2dMSAARW,
1389 .OCLImage2dArrayMSAARW,
1390 .OCLImage2dMSAADepthRW,
1391 .OCLImage2dArrayMSAADepthRW,
1392 .OCLImage3dRW,
1393 .OCLSampler,
1394 .OCLEvent,
1395 .OCLClkEvent,
1396 .OCLQueue,
1397 .OCLReserveID,
1398 .ShortAccum,
1399 .Accum,
1400 .LongAccum,
1401 .UShortAccum,
1402 .UAccum,
1403 .ULongAccum,
1404 .ShortFract,
1405 .Fract,
1406 .LongFract,
1407 .UShortFract,
1408 .UFract,
1409 .ULongFract,
1410 .SatShortAccum,
1411 .SatAccum,
1412 .SatLongAccum,
1413 .SatUShortAccum,
1414 .SatUAccum,
1415 .SatULongAccum,
1416 .SatShortFract,
1417 .SatFract,
1418 .SatLongFract,
1419 .SatUShortFract,
1420 .SatUFract,
1421 .SatULongFract,
1422 .OCLIntelSubgroupAVCMcePayload,
1423 .OCLIntelSubgroupAVCImePayload,
1424 .OCLIntelSubgroupAVCRefPayload,
1425 .OCLIntelSubgroupAVCSicPayload,
1426 .OCLIntelSubgroupAVCMceResult,
1427 .OCLIntelSubgroupAVCImeResult,
1428 .OCLIntelSubgroupAVCRefResult,
1429 .OCLIntelSubgroupAVCSicResult,
1430 .OCLIntelSubgroupAVCImeResultSingleRefStreamout,
1431 .OCLIntelSubgroupAVCImeResultDualRefStreamout,
1432 .OCLIntelSubgroupAVCImeSingleRefStreamin,
1433 .OCLIntelSubgroupAVCImeDualRefStreamin,
1434 => return res.node,
1435
1436 else => {},
1437 }
1438 },
1439 .Pointer => return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeNullLiteral(rp.c)),
1440
1441 .Typedef => {
1442 return transCreateNodeNotEqual(rp, scope, res.node, try transCreateNodeInt(rp.c, 0)); // TODO currently assuming it is like an int/char/bool builtin type. Coerce the type and recurse? Add a toTypedefZeroCmp function?
1443
1444 // TODO This is the code that was in translate-c, but it seems like it is giving wrong results! It just prints the typedef name instead of the value
1445 // const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
1446 // const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
1447 // const typedef_name_decl = ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl);
1448
1449 // const typedef_name = if (rp.c.decl_table.get(@ptrToInt(typedef_name_decl))) |existing_entry|
1450 // existing_entry.value
1451 // else
1452 // try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_name_decl)));
1453
1454 // return transCreateNodeIdentifier(rp.c, typedef_name);
1455 },
1456
1457 .Enum => {
1458 const gen_enum_decl_node = struct {
1459 // Have to use a callback because node must be generated inline in order to avoid weird AST printing behavior,
1460 // and the code to generate the nodes is a little different for each case
1461 fn generate_node(inner_rp: RestorePoint, enum_ty: *const struct_ZigClangType, source_loc: ZigClangSourceLocation) TransError!*ast.Node {
1462 const actual_enum_ty = @ptrCast(*const ZigClangEnumType, enum_ty);
1463 const enum_decl = ZigClangEnumType_getDecl(actual_enum_ty);
1464 const enum_type = (try transEnumDecl(inner_rp.c, enum_decl)) orelse {
1465 return revertAndWarn(inner_rp, error.UnsupportedType, source_loc, "unable to translate enum declaration", .{});
1466 };
1467 return enum_type;
1468 }
1469 };
1470
1471 return toEnumZeroCmp(rp, scope, res.node, gen_enum_decl_node.generate_node, ty, ZigClangExpr_getBeginLoc(expr));
1472 },
1473
1474 .Elaborated => {
1475 const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty);
1476
1477 switch (ZigClangElaboratedType_getKeyword(elaborated_ty)) {
1478 .Enum => {
1479 // Have to use a callback because node must be generated inline in order to avoid weird AST printing behavior,
1480 // and the code to generate the nodes is a little different for each case
1481 const gen_enum_type_node = struct {
1482 fn generate_node(inner_rp: RestorePoint, enum_ty: *const struct_ZigClangType, source_loc: ZigClangSourceLocation) TransError!*ast.Node {
1483 const inner_elaborated_ty = @ptrCast(*const ZigClangElaboratedType, enum_ty);
1484 const enum_type = try transQualType(inner_rp, ZigClangElaboratedType_getNamedType(inner_elaborated_ty), source_loc);
1485 return enum_type;
1486 }
1487 };
1488
1489 return toEnumZeroCmp(rp, scope, res.node, gen_enum_type_node.generate_node, ty, ZigClangExpr_getBeginLoc(expr));
1490 },
1491
1492 .Struct,
1493 .Union,
1494 .Interface,
1495 .Class,
1496 .Typename,
1497 .None,
1498 => return res.node,
1499
1500 else => {},
1501 }
1502 },
1503
1504 .FunctionProto,
1505 .Record,
1506 .ConstantArray,
1507 .Paren,
1508 .Decayed,
1509 .Attributed,
1510 .IncompleteArray,
1511 .BlockPointer,
1512 .LValueReference,
1513 .RValueReference,
1514 .MemberPointer,
1515 .VariableArray,
1516 .DependentSizedArray,
1517 .DependentSizedExtVector,
1518 .Vector,
1519 .ExtVector,
1520 .FunctionNoProto,
1521 .UnresolvedUsing,
1522 .Adjusted,
1523 .TypeOfExpr,
1524 .TypeOf,
1525 .Decltype,
1526 .UnaryTransform,
1527 .TemplateTypeParm,
1528 .SubstTemplateTypeParm,
1529 .SubstTemplateTypeParmPack,
1530 .TemplateSpecialization,
1531 .Auto,
1532 .InjectedClassName,
1533 .DependentName,
1534 .DependentTemplateSpecialization,
1535 .PackExpansion,
1536 .ObjCObject,
1537 .ObjCInterface,
1538 .Complex,
1539 .ObjCObjectPointer,
1540 .Atomic,
1541 .Pipe,
1542 .ObjCTypeParam,
1543 .DeducedTemplateSpecialization,
1544 .DependentAddressSpace,
1545 .DependentVector,
1546 .MacroQualified,
1547 => return res.node,
1548
1549 else => unreachable,
1550 }
1551
1552 unreachable;
1553}
1554
11501555fn transIntegerLiteral(
11511556 rp: RestorePoint,
11521557 scope: *Scope,
......@@ -1925,6 +2330,95 @@ fn qualTypeIsPtr(qt: ZigClangQualType) bool {
19252330 return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer;
19262331}
19272332
2333fn qualTypeIntBitWidth(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !u32 {
2334 const ty = ZigClangQualType_getTypePtr(qt);
2335
2336 switch (ZigClangType_getTypeClass(ty)) {
2337 .Builtin => {
2338 const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);
2339
2340 switch (ZigClangBuiltinType_getKind(builtin_ty)) {
2341 .Char_U,
2342 .UChar,
2343 .Char_S,
2344 .SChar,
2345 => return 8,
2346 .UInt128,
2347 .Int128,
2348 => return 128,
2349 else => return 0,
2350 }
2351
2352 unreachable;
2353 },
2354 .Typedef => {
2355 const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty);
2356 const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty);
2357 const type_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl)));
2358
2359 if (std.mem.eql(u8, type_name, "uint8_t") or std.mem.eql(u8, type_name, "int8_t")) {
2360 return 8;
2361 } else if (std.mem.eql(u8, type_name, "uint16_t") or std.mem.eql(u8, type_name, "int16_t")) {
2362 return 16;
2363 } else if (std.mem.eql(u8, type_name, "uint32_t") or std.mem.eql(u8, type_name, "int32_t")) {
2364 return 32;
2365 } else if (std.mem.eql(u8, type_name, "uint64_t") or std.mem.eql(u8, type_name, "int64_t")) {
2366 return 64;
2367 } else {
2368 return 0;
2369 }
2370 },
2371 else => return 0,
2372 }
2373
2374 unreachable;
2375}
2376
2377fn qualTypeToLog2IntRef(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSourceLocation) !*ast.Node {
2378 const int_bit_width = try qualTypeIntBitWidth(rp, qt, source_loc);
2379
2380 if (int_bit_width != 0) {
2381 // we can perform the log2 now.
2382 const cast_bit_width = std.math.log2_int(u64, int_bit_width);
2383 const node = try rp.c.a().create(ast.Node.IntegerLiteral);
2384 node.* = ast.Node.IntegerLiteral{
2385 .token = try appendTokenFmt(rp.c, .Identifier, "u{}", .{cast_bit_width}),
2386 };
2387 return &node.base;
2388 }
2389
2390 const zig_type_node = try transQualType(rp, qt, source_loc);
2391
2392 // @import("std").math.Log2Int(c_long);
2393 //
2394 // FnCall
2395 // FieldAccess
2396 // FieldAccess
2397 // FnCall (.builtin = true)
2398 // Symbol "import"
2399 // StringLiteral "std"
2400 // Symbol "math"
2401 // Symbol "Log2Int"
2402 // Symbol <zig_type_node> (var from above)
2403
2404 const import_fn_call = try transCreateNodeBuiltinFnCall(rp.c, "@import");
2405 const std_token = try appendToken(rp.c, .StringLiteral, "\"std\"");
2406 const std_node = try rp.c.a().create(ast.Node.StringLiteral);
2407 std_node.* = ast.Node.StringLiteral{
2408 .token = std_token,
2409 };
2410 try import_fn_call.params.push(&std_node.base);
2411 import_fn_call.rparen_token = try appendToken(rp.c, .RParen, ")");
2412
2413 const inner_field_access = try transCreateNodeFieldAccess(rp.c, &import_fn_call.base, "math");
2414 const outer_field_access = try transCreateNodeFieldAccess(rp.c, &inner_field_access.base, "Log2Int");
2415 const log2int_fn_call = try transCreateNodeFnCall(rp.c, &outer_field_access.base);
2416 try @ptrCast(*ast.Node.SuffixOp.Op.Call, &log2int_fn_call.op).params.push(zig_type_node);
2417 log2int_fn_call.rtoken = try appendToken(rp.c, .RParen, ")");
2418
2419 return &log2int_fn_call.base;
2420}
2421
19282422fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool {
19292423 const ty = ZigClangQualType_getTypePtr(qt);
19302424
......@@ -1974,6 +2468,14 @@ fn getExprQualType(c: *Context, expr: *const ZigClangExpr) ZigClangQualType {
19742468 return ZigClangExpr_getType(expr);
19752469}
19762470
2471fn getExprQualTypeBeforeImplicitCast(c: *Context, expr: *const ZigClangExpr) ZigClangQualType {
2472 if (ZigClangExpr_getStmtClass(expr) == .ImplicitCastExprClass) {
2473 const cast_expr = @ptrCast(*const ZigClangImplicitCastExpr, expr);
2474 return getExprQualType(c, ZigClangImplicitCastExpr_getSubExpr(cast_expr));
2475 }
2476 return ZigClangExpr_getType(expr);
2477}
2478
19772479fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocation) bool {
19782480 switch (ZigClangType_getTypeClass(ty)) {
19792481 .Builtin => {
......@@ -2142,6 +2644,17 @@ fn transCreateNodeFnCall(c: *Context, fn_expr: *ast.Node) !*ast.Node.SuffixOp {
21422644 return node;
21432645}
21442646
2647fn transCreateNodeFieldAccess(c: *Context, container: *ast.Node, field_name: []const u8) !*ast.Node.InfixOp {
2648 const field_access_node = try c.a().create(ast.Node.InfixOp);
2649 field_access_node.* = .{
2650 .op_token = try appendToken(c, .Period, "."),
2651 .lhs = container,
2652 .op = .Period,
2653 .rhs = try transCreateNodeIdentifier(c, field_name),
2654 };
2655 return field_access_node;
2656}
2657
21452658fn transCreateNodePrefixOp(
21462659 c: *Context,
21472660 op: ast.Node.PrefixOp.Op,
......@@ -2157,25 +2670,24 @@ fn transCreateNodePrefixOp(
21572670 return node;
21582671}
21592672
2160fn transCreateNodeInfixOp(
2673fn transCreateNodeInfixOpImpl(
21612674 rp: RestorePoint,
21622675 scope: *Scope,
2163 stmt: *const ZigClangBinaryOperator,
2676 lhs_node: *ast.Node,
2677 rhs_node: *ast.Node,
21642678 op: ast.Node.InfixOp.Op,
21652679 op_tok_id: std.zig.Token.Id,
21662680 bytes: []const u8,
21672681 grouped: bool,
21682682) !*ast.Node {
21692683 const lparen = if (grouped) try appendToken(rp.c, .LParen, "(") else undefined;
2170 const lhs = try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .l_value);
21712684 const op_token = try appendToken(rp.c, op_tok_id, bytes);
2172 const rhs = try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value);
21732685 const node = try rp.c.a().create(ast.Node.InfixOp);
21742686 node.* = ast.Node.InfixOp{
21752687 .op_token = op_token,
2176 .lhs = lhs,
2688 .lhs = lhs_node,
21772689 .op = op,
2178 .rhs = rhs,
2690 .rhs = rhs_node,
21792691 };
21802692 if (!grouped) return &node.base;
21812693 const rparen = try appendToken(rp.c, .RParen, ")");
......@@ -2188,6 +2700,60 @@ fn transCreateNodeInfixOp(
21882700 return &grouped_expr.base;
21892701}
21902702
2703fn transCreateNodeInfixOp(
2704 rp: RestorePoint,
2705 scope: *Scope,
2706 stmt: *const ZigClangBinaryOperator,
2707 op: ast.Node.InfixOp.Op,
2708 op_tok_id: std.zig.Token.Id,
2709 bytes: []const u8,
2710 grouped: bool,
2711) !*ast.Node {
2712 return transCreateNodeInfixOpImpl(
2713 rp,
2714 scope,
2715 (try transExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .r_value)).node,
2716 (try transExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value)).node,
2717 op,
2718 op_tok_id,
2719 bytes,
2720 grouped,
2721 );
2722}
2723
2724fn transCreateNodeNotEqual(
2725 rp: RestorePoint,
2726 scope: *Scope,
2727 lhs_node: *ast.Node,
2728 rhs_node: *ast.Node,
2729) !*ast.Node {
2730 return transCreateNodeInfixOpImpl(rp, scope, lhs_node, rhs_node, .BangEqual, .BangEqual, "!=", true);
2731}
2732
2733fn transCreateNodeBoolInfixOp(
2734 rp: RestorePoint,
2735 scope: *Scope,
2736 stmt: *const ZigClangBinaryOperator,
2737 comptime op: ast.Node.InfixOp.Op,
2738 comptime op_tok_id: std.zig.Token.Id,
2739 comptime bytes: []const u8,
2740) !*ast.Node {
2741 if (!(op == .BoolAnd or op == .BoolOr)) {
2742 @compileError("op must be either .BoolAnd or .BoolOr");
2743 }
2744
2745 return transCreateNodeInfixOpImpl(
2746 rp,
2747 scope,
2748 try transBoolExpr(rp, scope, ZigClangBinaryOperator_getLHS(stmt), .used, .r_value),
2749 try transBoolExpr(rp, scope, ZigClangBinaryOperator_getRHS(stmt), .used, .r_value),
2750 op,
2751 op_tok_id,
2752 bytes,
2753 true,
2754 );
2755}
2756
21912757fn transCreateNodePtrType(
21922758 c: *Context,
21932759 is_const: bool,
......@@ -2575,6 +3141,45 @@ fn transCreateNodeSwitchElse(c: *Context) !*ast.Node {
25753141 return &node.base;
25763142}
25773143
3144fn transCreateNodeShiftOp(
3145 rp: RestorePoint,
3146 scope: *Scope,
3147 stmt: *const ZigClangBinaryOperator,
3148 comptime op: ast.Node.InfixOp.Op,
3149 comptime op_tok_id: std.zig.Token.Id,
3150 comptime bytes: []const u8,
3151) !*ast.Node {
3152 if (!(op == .BitShiftLeft or op == .BitShiftRight)) {
3153 @compileError("op must be either .BitShiftLeft or .BitShiftRight");
3154 }
3155
3156 const lhs_expr = ZigClangBinaryOperator_getLHS(stmt);
3157 const rhs_expr = ZigClangBinaryOperator_getRHS(stmt);
3158 const rhs_location = ZigClangExpr_getBeginLoc(rhs_expr);
3159 // lhs >> u5(rh)
3160
3161 const lhs = try transExpr(rp, scope, lhs_expr, .used, .r_value);
3162 const op_token = try appendToken(rp.c, op_tok_id, bytes);
3163
3164 const as_node = try transCreateNodeBuiltinFnCall(rp.c, "@as");
3165 const rhs_type = try qualTypeToLog2IntRef(rp, ZigClangBinaryOperator_getType(stmt), rhs_location);
3166 try as_node.params.push(rhs_type);
3167 _ = try appendToken(rp.c, .Comma, ",");
3168 const rhs = try transExpr(rp, scope, rhs_expr, .used, .r_value);
3169 try as_node.params.push(rhs.node);
3170 as_node.rparen_token = try appendToken(rp.c, .RParen, ")");
3171
3172 const node = try rp.c.a().create(ast.Node.InfixOp);
3173 node.* = ast.Node.InfixOp{
3174 .op_token = op_token,
3175 .lhs = lhs.node,
3176 .op = op,
3177 .rhs = &as_node.base,
3178 };
3179
3180 return &node.base;
3181}
3182
25783183const RestorePoint = struct {
25793184 c: *Context,
25803185 token_index: ast.TokenIndex,
test/translate_c.zig+167-17
......@@ -1334,6 +1334,71 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
13341334 \\}
13351335 });
13361336
1337 cases.add_2("shift right with a fixed size type, no while", // TODO can fold this into "shift right assign with a fixed size type" once `while` and `>>=` and `uint32_t` are handled in translate-c-2
1338 \\#include <stdint.h>
1339 \\uint32_t some_func(uint32_t a) {
1340 \\ uint32_t b = a >> 1;
1341 \\ return b;
1342 \\}
1343 , &[_][]const u8{
1344 \\pub export fn some_func(a: uint32_t) uint32_t {
1345 \\ var b: uint32_t = a >> @as(u5, 1);
1346 \\ return b;
1347 \\}
1348 });
1349
1350 cases.add_2("logical and, logical or, on non-bool values, extra parens",
1351 \\enum Foo {
1352 \\ FooA,
1353 \\ FooB,
1354 \\ FooC,
1355 \\};
1356 \\typedef int SomeTypedef;
1357 \\int and_or_non_bool(int a, float b, void *c) {
1358 \\ enum Foo d = FooA;
1359 \\ int e = (a && b);
1360 \\ int f = (b && c);
1361 \\ int g = (a && c);
1362 \\ int h = (a || b);
1363 \\ int i = (b || c);
1364 \\ int j = (a || c);
1365 \\ int k = (a || d);
1366 \\ int l = (d && b);
1367 \\ int m = (c || d);
1368 \\ SomeTypedef td = 44;
1369 \\ int o = (td || b);
1370 \\ int p = (c && td);
1371 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
1372 \\}
1373 , &[_][]const u8{
1374 \\pub const FooA = enum_Foo.A;
1375 \\pub const FooB = enum_Foo.B;
1376 \\pub const FooC = enum_Foo.C;
1377 \\pub const enum_Foo = extern enum {
1378 \\ A,
1379 \\ B,
1380 \\ C,
1381 \\};
1382 \\pub const SomeTypedef = c_int;
1383 \\pub export fn and_or_non_bool(a: c_int, b: f32, c: ?*c_void) c_int {
1384 \\ var d: enum_Foo = @as(enum_Foo, FooA);
1385 \\ var e: c_int = ((a != 0) and (b != 0));
1386 \\ var f: c_int = ((b != 0) and (c != null));
1387 \\ var g: c_int = ((a != 0) and (c != null));
1388 \\ var h: c_int = ((a != 0) or (b != 0));
1389 \\ var i: c_int = ((b != 0) or (c != null));
1390 \\ var j: c_int = ((a != 0) or (c != null));
1391 \\ var k: c_int = ((a != 0) or (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))));
1392 \\ var l: c_int = ((@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))) and (b != 0));
1393 \\ var m: c_int = ((c != null) or (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))));
1394 \\ var td: SomeTypedef = 44;
1395 \\ var o: c_int = ((td != 0) or (b != 0));
1396 \\ var p: c_int = ((c != null) and (td != 0));
1397 \\ return ((((((((((e + f) + g) + h) + i) + j) + k) + l) + m) + o) + p);
1398 \\}
1399 \\pub const Foo = enum_Foo;
1400 });
1401
13371402 /////////////// Cases for only stage1 which are TODO items for stage2 ////////////////
13381403
13391404 cases.addAllowWarnings("simple data types",
......@@ -1461,6 +1526,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
14611526 \\}
14621527 });
14631528
1529 cases.add_2("==, !=, no if", // TODO remove this test after `if` conversion supported, and switch "==, !=" to addC_both
1530 \\int max(int a, int b) {
1531 \\ int c = (a == b);
1532 \\ int d = (a != b);
1533 \\ return (c != d);
1534 \\}
1535 , &[_][]const u8{
1536 \\pub export fn max(a: c_int, b: c_int) c_int {
1537 \\ var c: c_int = (a == b);
1538 \\ var d: c_int = (a != b);
1539 \\ return (c != d);
1540 \\}
1541 });
1542
14641543 cases.addC("bitwise binary operators",
14651544 \\int max(int a, int b) {
14661545 \\ return (a & b) ^ (a | b);
......@@ -1471,6 +1550,20 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
14711550 \\}
14721551 });
14731552
1553 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
1554 \\int max(int a, int b) {
1555 \\ int c = (a & b);
1556 \\ int d = (a | b);
1557 \\ return (c ^ d);
1558 \\}
1559 , &[_][]const u8{
1560 \\pub export fn max(a: c_int, b: c_int) c_int {
1561 \\ var c: c_int = (a & b);
1562 \\ var d: c_int = (a | b);
1563 \\ return (c ^ d);
1564 \\}
1565 });
1566
14741567 cases.addC("logical and, logical or",
14751568 \\int max(int a, int b) {
14761569 \\ if (a < b || a == b)
......@@ -1487,25 +1580,70 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
14871580 \\}
14881581 });
14891582
1490 cases.addC("logical and, logical or on none bool values",
1491 \\int and_or_none_bool(int a, float b, void *c) {
1492 \\ if (a && b) return 0;
1493 \\ if (b && c) return 1;
1494 \\ if (a && c) return 2;
1495 \\ if (a || b) return 3;
1496 \\ if (b || c) return 4;
1497 \\ if (a || c) return 5;
1498 \\ return 6;
1583 cases.add_2("comparison operators (no if)", // TODO Come up with less contrived tests? Make sure to cover all these comparisons. Can use `if` after it is added to translate-c-2
1584 \\int test_comparisons(int a, int b) {
1585 \\ int c = (a < b);
1586 \\ int d = (a > b);
1587 \\ int e = (a <= b);
1588 \\ int f = (a >= b);
1589 \\ int g = (c < d);
1590 \\ int h = (e < f);
1591 \\ int i = (g < h);
1592 \\ return i;
14991593 \\}
15001594 , &[_][]const u8{
1501 \\pub export fn and_or_none_bool(a: c_int, b: f32, c: ?*c_void) c_int {
1502 \\ if ((a != 0) and (b != 0)) return 0;
1503 \\ if ((b != 0) and (c != null)) return 1;
1504 \\ if ((a != 0) and (c != null)) return 2;
1505 \\ if ((a != 0) or (b != 0)) return 3;
1506 \\ if ((b != 0) or (c != null)) return 4;
1507 \\ if ((a != 0) or (c != null)) return 5;
1508 \\ return 6;
1595 \\pub export fn test_comparisons(a: c_int, b: c_int) c_int {
1596 \\ var c: c_int = (a < b);
1597 \\ var d: c_int = (a > b);
1598 \\ var e: c_int = (a <= b);
1599 \\ var f: c_int = (a >= b);
1600 \\ var g: c_int = (c < d);
1601 \\ var h: c_int = (e < f);
1602 \\ var i: c_int = (g < h);
1603 \\ return i;
1604 \\}
1605 });
1606
1607 cases.addC("logical and, logical or, on non-bool values", // Note this gets cut off by extra C symbols being injected in middle: `pub const Foo = enum_Foo;`
1608 \\enum Foo {
1609 \\ FooA,
1610 \\ FooB,
1611 \\ FooC,
1612 \\};
1613 \\int and_or_non_bool(int a, float b, void *c) {
1614 \\ enum Foo d = FooA;
1615 \\ int e = (a && b);
1616 \\ int f = (b && c);
1617 \\ int g = (a && c);
1618 \\ int h = (a || b);
1619 \\ int i = (b || c);
1620 \\ int j = (a || c);
1621 \\ int k = (a || d);
1622 \\ int l = (d && b);
1623 \\ int m = (c || d);
1624 \\ return (((((((e + f) + g) + h) + i) + j) + k) + l) + m;
1625 \\}
1626 , &[_][]const u8{
1627 \\pub const FooA = enum_Foo.A;
1628 \\pub const FooB = enum_Foo.B;
1629 \\pub const FooC = enum_Foo.C;
1630 \\pub const enum_Foo = extern enum {
1631 \\ A,
1632 \\ B,
1633 \\ C,
1634 \\};
1635 \\pub export fn and_or_non_bool(a: c_int, b: f32, c: ?*c_void) c_int {
1636 \\ var d: enum_Foo = @as(enum_Foo, FooA);
1637 \\ var e: c_int = (a != 0) and (b != 0);
1638 \\ var f: c_int = (b != 0) and (c != null);
1639 \\ var g: c_int = (a != 0) and (c != null);
1640 \\ var h: c_int = (a != 0) or (b != 0);
1641 \\ var i: c_int = (b != 0) or (c != null);
1642 \\ var j: c_int = (a != 0) or (c != null);
1643 \\ var k: c_int = (a != 0) or (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0)));
1644 \\ var l: c_int = (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0))) and (b != 0);
1645 \\ var m: c_int = (c != null) or (@as(c_int, d) != @bitCast(enum_Foo, @as(@TagType(enum_Foo), 0)));
1646 \\ return (((((((e + f) + g) + h) + i) + j) + k) + l) + m;
15091647 \\}
15101648 });
15111649
......@@ -1622,6 +1760,18 @@ pub fn addCases(cases: *tests.TranslateCContext) void {
16221760 \\}
16231761 });
16241762
1763 cases.add_2("bitshift, no parens", // TODO can fold this into "bitshift" once parens are preserved correctly in translate-c-2
1764 \\int foo(void) {
1765 \\ int a = (1 << 2);
1766 \\ return a >> 1;
1767 \\}
1768 , &[_][]const u8{
1769 \\pub export fn foo() c_int {
1770 \\ var a: c_int = 1 << @as(@import("std").math.Log2Int(c_int), 2);
1771 \\ return a >> @as(@import("std").math.Log2Int(c_int), 1);
1772 \\}
1773 });
1774
16251775 cases.addC("compound assignment operators",
16261776 \\void foo(void) {
16271777 \\ int a = 0;