| ... | ... | @@ -15,7 +15,7 @@ pub const Error = error{OutOfMemory}; |
| 15 | 15 | const TypeError = Error || error{UnsupportedType}; |
| 16 | 16 | const TransError = TypeError || error{UnsupportedTranslation}; |
| 17 | 17 | |
| 18 | | const DeclTable = std.HashMap(usize, void, addrHash, addrEql); |
| 18 | const DeclTable = std.HashMap(usize, []const u8, addrHash, addrEql); |
| 19 | 19 | |
| 20 | 20 | fn addrHash(x: usize) u32 { |
| 21 | 21 | switch (@typeInfo(usize).Int.bits) { |
| ... | ... | @@ -194,6 +194,7 @@ pub fn translate( |
| 194 | 194 | |
| 195 | 195 | tree.root_node.eof_token = try appendToken(&context, .Eof, ""); |
| 196 | 196 | tree.source = source_buffer.toOwnedSlice(); |
| 197 | |
| 197 | 198 | if (false) { |
| 198 | 199 | std.debug.warn("debug source:\n{}\n==EOF==\ntokens:\n", tree.source); |
| 199 | 200 | var i: usize = 0; |
| ... | ... | @@ -220,13 +221,13 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 220 | 221 | return visitFnDecl(c, @ptrCast(*const ZigClangFunctionDecl, decl)); |
| 221 | 222 | }, |
| 222 | 223 | .Typedef => { |
| 223 | | try resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); |
| 224 | return resolveTypeDef(c, @ptrCast(*const ZigClangTypedefNameDecl, decl)); |
| 224 | 225 | }, |
| 225 | 226 | .Enum => { |
| 226 | 227 | try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for enums", .{}); |
| 227 | 228 | }, |
| 228 | 229 | .Record => { |
| 229 | | try emitWarning(c, ZigClangDecl_getLocation(decl), "TODO implement translate-c for structs", .{}); |
| 230 | return resolveRecordDecl(c, @ptrCast(*const ZigClangRecordDecl, decl)); |
| 230 | 231 | }, |
| 231 | 232 | .Var => { |
| 232 | 233 | return visitVarDecl(c, @ptrCast(*const ZigClangVarDecl, decl)); |
| ... | ... | @@ -239,9 +240,10 @@ fn declVisitor(c: *Context, decl: *const ZigClangDecl) Error!void { |
| 239 | 240 | } |
| 240 | 241 | |
| 241 | 242 | fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 242 | | if (try c.decl_table.put(@ptrToInt(fn_decl), {})) |_| return; // Avoid processing this decl twice |
| 243 | if (c.decl_table.contains(@ptrToInt(fn_decl))) return; // Avoid processing this decl twice |
| 243 | 244 | const rp = makeRestorePoint(c); |
| 244 | 245 | const fn_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, fn_decl))); |
| 246 | _ = try c.decl_table.put(@ptrToInt(fn_decl), fn_name); |
| 245 | 247 | const fn_decl_loc = ZigClangFunctionDecl_getLocation(fn_decl); |
| 246 | 248 | const fn_qt = ZigClangFunctionDecl_getType(fn_decl); |
| 247 | 249 | const fn_type = ZigClangQualType_getTypePtr(fn_qt); |
| ... | ... | @@ -303,7 +305,7 @@ fn visitFnDecl(c: *Context, fn_decl: *const ZigClangFunctionDecl) Error!void { |
| 303 | 305 | } |
| 304 | 306 | |
| 305 | 307 | fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 306 | | if (try c.decl_table.put(@ptrToInt(var_decl), {})) |_| return; // Avoid processing this decl twice |
| 308 | if (c.decl_table.contains(@ptrToInt(var_decl))) return; // Avoid processing this decl twice |
| 307 | 309 | const rp = makeRestorePoint(c); |
| 308 | 310 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 309 | 311 | |
| ... | ... | @@ -314,6 +316,7 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 314 | 316 | |
| 315 | 317 | var scope = &c.global_scope.base; |
| 316 | 318 | const var_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, var_decl))); |
| 319 | _ = try c.decl_table.put(@ptrToInt(var_decl), var_name); |
| 317 | 320 | const var_decl_loc = ZigClangVarDecl_getLocation(var_decl); |
| 318 | 321 | |
| 319 | 322 | const qual_type = ZigClangVarDecl_getTypeSourceInfo_getType(var_decl); |
| ... | ... | @@ -385,12 +388,13 @@ fn visitVarDecl(c: *Context, var_decl: *const ZigClangVarDecl) Error!void { |
| 385 | 388 | } |
| 386 | 389 | |
| 387 | 390 | fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Error!void { |
| 388 | | if (try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), {})) |_| return; // Avoid processing this decl twice |
| 391 | if (c.decl_table.contains(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)))) return; // Avoid processing this decl twice |
| 389 | 392 | const rp = makeRestorePoint(c); |
| 390 | 393 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 391 | 394 | const const_tok = try appendToken(c, .Keyword_const, "const"); |
| 392 | 395 | |
| 393 | 396 | const typedef_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); |
| 397 | _ = try c.decl_table.put(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl)), typedef_name); |
| 394 | 398 | const name_tok = try appendToken(c, .Identifier, typedef_name); |
| 395 | 399 | const eq_tok = try appendToken(c, .Equal, "="); |
| 396 | 400 | |
| ... | ... | @@ -398,9 +402,7 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err |
| 398 | 402 | const typedef_loc = ZigClangTypedefNameDecl_getLocation(typedef_decl); |
| 399 | 403 | const type_node = transQualType(rp, child_qt, typedef_loc) catch |err| switch (err) { |
| 400 | 404 | error.UnsupportedType => { |
| 401 | | const node = try failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{}); |
| 402 | | _ = try c.decl_table.put(@ptrToInt(typedef_decl), node); |
| 403 | | return node; |
| 405 | return failDecl(c, typedef_loc, typedef_name, "unable to resolve typedef child type", .{}); |
| 404 | 406 | }, |
| 405 | 407 | error.OutOfMemory => |e| return e, |
| 406 | 408 | }; |
| ... | ... | @@ -426,6 +428,60 @@ fn resolveTypeDef(c: *Context, typedef_decl: *const ZigClangTypedefNameDecl) Err |
| 426 | 428 | try addTopLevelDecl(c, typedef_name, &node.base); |
| 427 | 429 | } |
| 428 | 430 | |
| 431 | fn resolveRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) Error!void { |
| 432 | if (c.decl_table.contains(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) return; // Avoid processing this decl twice |
| 433 | const rp = makeRestorePoint(c); |
| 434 | |
| 435 | const visib_tok = try appendToken(c, .Keyword_pub, "pub"); |
| 436 | const const_tok = try appendToken(c, .Keyword_const, "const"); |
| 437 | |
| 438 | const bare_name = try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, record_decl))); |
| 439 | |
| 440 | const container_kind_name = if (ZigClangRecordDecl_isUnion(record_decl)) |
| 441 | "union" |
| 442 | else if (ZigClangRecordDecl_isStruct(record_decl)) |
| 443 | "struct" |
| 444 | else |
| 445 | return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), bare_name, "record {} is not a struct or union", .{bare_name}); |
| 446 | |
| 447 | if (ZigClangRecordDecl_isAnonymousStructOrUnion(record_decl) or bare_name.len == 0) |
| 448 | return; |
| 449 | |
| 450 | const name = try std.fmt.allocPrint(c.a(), "{}_{}", .{ container_kind_name, bare_name }); |
| 451 | _ = try c.decl_table.put(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)), name); |
| 452 | const name_tok = try appendToken(c, .Identifier, name); |
| 453 | |
| 454 | const eq_tok = try appendToken(c, .Equal, "="); |
| 455 | const init_node = transRecordDecl(c, record_decl) catch |err| switch (err) { |
| 456 | error.UnsupportedType => { |
| 457 | return failDecl(c, ZigClangRecordDecl_getLocation(record_decl), name, "unable to resolve record type", .{}); |
| 458 | }, |
| 459 | error.OutOfMemory => |e| return e, |
| 460 | }; |
| 461 | const semicolon_token = try appendToken(c, .Semicolon, ";"); |
| 462 | |
| 463 | const node = try c.a().create(ast.Node.VarDecl); |
| 464 | node.* = ast.Node.VarDecl{ |
| 465 | .base = ast.Node{ .id = .VarDecl }, |
| 466 | .doc_comments = null, |
| 467 | .visib_token = visib_tok, |
| 468 | .thread_local_token = null, |
| 469 | .name_token = name_tok, |
| 470 | .eq_token = eq_tok, |
| 471 | .mut_token = const_tok, |
| 472 | .comptime_token = null, |
| 473 | .extern_export_token = null, |
| 474 | .lib_name = null, |
| 475 | .type_node = null, |
| 476 | .align_node = null, |
| 477 | .section_node = null, |
| 478 | .init_node = init_node, |
| 479 | .semicolon_token = semicolon_token, |
| 480 | }; |
| 481 | |
| 482 | try addTopLevelDecl(c, name, &node.base); |
| 483 | } |
| 484 | |
| 429 | 485 | const ResultUsed = enum { |
| 430 | 486 | used, |
| 431 | 487 | unused, |
| ... | ... | @@ -1148,22 +1204,113 @@ fn transQualType(rp: RestorePoint, qt: ZigClangQualType, source_loc: ZigClangSou |
| 1148 | 1204 | return transType(rp, ZigClangQualType_getTypePtr(qt), source_loc); |
| 1149 | 1205 | } |
| 1150 | 1206 | |
| 1207 | fn transRecordDecl(c: *Context, record_decl: *const ZigClangRecordDecl) TypeError!*ast.Node { |
| 1208 | const rp = makeRestorePoint(c); |
| 1209 | |
| 1210 | const record_loc = ZigClangRecordDecl_getLocation(record_decl); |
| 1211 | |
| 1212 | var container_kind_name: []const u8 = undefined; |
| 1213 | var container_kind: std.zig.Token.Id = undefined; |
| 1214 | |
| 1215 | if (ZigClangRecordDecl_isUnion(record_decl)) { |
| 1216 | container_kind_name = "union"; |
| 1217 | container_kind = .Keyword_union; |
| 1218 | } else if (ZigClangRecordDecl_isStruct(record_decl)) { |
| 1219 | container_kind_name = "struct"; |
| 1220 | container_kind = .Keyword_struct; |
| 1221 | } else { |
| 1222 | return revertAndWarn( |
| 1223 | rp, |
| 1224 | error.UnsupportedType, |
| 1225 | record_loc, |
| 1226 | "unsupported record type", |
| 1227 | .{}, |
| 1228 | ); |
| 1229 | } |
| 1230 | |
| 1231 | const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse { |
| 1232 | return transCreateNodeOpaqueType(c); |
| 1233 | }; |
| 1234 | |
| 1235 | const extern_tok = try appendToken(c, .Keyword_extern, "extern"); |
| 1236 | const container_tok = try appendToken(c, container_kind, container_kind_name); |
| 1237 | const lbrace_token = try appendToken(c, .LBrace, "{"); |
| 1238 | |
| 1239 | const container_node = try c.a().create(ast.Node.ContainerDecl); |
| 1240 | container_node.* = .{ |
| 1241 | .base = ast.Node{ .id = .ContainerDecl }, |
| 1242 | .layout_token = extern_tok, |
| 1243 | .kind_token = container_tok, |
| 1244 | .init_arg_expr = .None, |
| 1245 | .fields_and_decls = ast.Node.ContainerDecl.DeclList.init(c.a()), |
| 1246 | .lbrace_token = lbrace_token, |
| 1247 | .rbrace_token = undefined, // TODO |
| 1248 | }; |
| 1249 | |
| 1250 | var it = ZigClangRecordDecl_field_begin(record_def); |
| 1251 | const end_it = ZigClangRecordDecl_field_end(record_def); |
| 1252 | while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { |
| 1253 | const field_decl = ZigClangRecordDecl_field_iterator_deref(it); |
| 1254 | const field_loc = ZigClangFieldDecl_getLocation(field_decl); |
| 1255 | |
| 1256 | if (ZigClangFieldDecl_isBitField(field_decl)) { |
| 1257 | rp.activate(); |
| 1258 | const node = try transCreateNodeOpaqueType(c); |
| 1259 | try emitWarning(c, field_loc, "{} demoted to opaque type - has bitfield", .{container_kind_name}); |
| 1260 | return node; |
| 1261 | } |
| 1262 | |
| 1263 | const field_name = try appendToken(c, .Identifier, try c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, field_decl)))); |
| 1264 | _ = try appendToken(c, .Colon, ":"); |
| 1265 | const field_type = try transQualType(rp, ZigClangFieldDecl_getType(field_decl), field_loc); |
| 1266 | |
| 1267 | const field_node = try c.a().create(ast.Node.ContainerField); |
| 1268 | field_node.* = .{ |
| 1269 | .doc_comments = null, |
| 1270 | .comptime_token = null, |
| 1271 | .name_token = field_name, |
| 1272 | .type_expr = field_type, |
| 1273 | .value_expr = null, |
| 1274 | .align_expr = null, |
| 1275 | }; |
| 1276 | |
| 1277 | try container_node.fields_and_decls.push(&field_node.base); |
| 1278 | _ = try appendToken(c, .Comma, ","); |
| 1279 | } |
| 1280 | |
| 1281 | container_node.rbrace_token = try appendToken(c, .RBrace, "}"); |
| 1282 | return &container_node.base; |
| 1283 | } |
| 1284 | |
| 1151 | 1285 | fn qualTypeIsPtr(qt: ZigClangQualType) bool { |
| 1152 | 1286 | return ZigClangType_getTypeClass(qualTypeCanon(qt)) == .Pointer; |
| 1153 | 1287 | } |
| 1154 | 1288 | |
| 1155 | 1289 | fn qualTypeChildIsFnProto(qt: ZigClangQualType) bool { |
| 1156 | 1290 | const ty = ZigClangQualType_getTypePtr(qt); |
| 1157 | | if (ZigClangType_getTypeClass(ty) == .Paren) { |
| 1158 | | const paren_type = @ptrCast(*const ZigClangParenType, ty); |
| 1159 | | const inner_type = ZigClangParenType_getInnerType(paren_type); |
| 1160 | | return ZigClangQualType_getTypeClass(inner_type) == .FunctionProto; |
| 1161 | | } |
| 1162 | | if (ZigClangType_getTypeClass(ty) == .Attributed) { |
| 1163 | | const attr_type = @ptrCast(*const ZigClangAttributedType, ty); |
| 1164 | | return qualTypeChildIsFnProto(ZigClangAttributedType_getEquivalentType(attr_type)); |
| 1291 | |
| 1292 | switch (ZigClangType_getTypeClass(ty)) { |
| 1293 | .FunctionProto, .FunctionNoProto => return true, |
| 1294 | .Elaborated => { |
| 1295 | const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); |
| 1296 | return qualTypeChildIsFnProto(ZigClangElaboratedType_getNamedType(elaborated_ty)); |
| 1297 | }, |
| 1298 | .Typedef => { |
| 1299 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); |
| 1300 | const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); |
| 1301 | return qualTypeChildIsFnProto(ZigClangTypedefNameDecl_getUnderlyingType(typedef_decl)); |
| 1302 | }, |
| 1303 | .Paren => { |
| 1304 | const paren_type = @ptrCast(*const ZigClangParenType, ty); |
| 1305 | const inner_type = ZigClangParenType_getInnerType(paren_type); |
| 1306 | return ZigClangQualType_getTypeClass(inner_type) == .FunctionProto; |
| 1307 | }, |
| 1308 | .Attributed => { |
| 1309 | const attr_type = @ptrCast(*const ZigClangAttributedType, ty); |
| 1310 | return qualTypeChildIsFnProto(ZigClangAttributedType_getEquivalentType(attr_type)); |
| 1311 | }, |
| 1312 | else => return false, |
| 1165 | 1313 | } |
| 1166 | | return false; |
| 1167 | 1314 | } |
| 1168 | 1315 | |
| 1169 | 1316 | fn qualTypeCanon(qt: ZigClangQualType) *const ZigClangType { |
| ... | ... | @@ -1197,7 +1344,18 @@ fn typeIsOpaque(c: *Context, ty: *const ZigClangType, loc: ZigClangSourceLocatio |
| 1197 | 1344 | .Record => { |
| 1198 | 1345 | const record_ty = @ptrCast(*const ZigClangRecordType, ty); |
| 1199 | 1346 | const record_decl = ZigClangRecordType_getDecl(record_ty); |
| 1200 | | return (ZigClangRecordDecl_getDefinition(record_decl) == null); |
| 1347 | const record_def = ZigClangRecordDecl_getDefinition(record_decl) orelse |
| 1348 | return true; |
| 1349 | var it = ZigClangRecordDecl_field_begin(record_def); |
| 1350 | const end_it = ZigClangRecordDecl_field_end(record_def); |
| 1351 | while (ZigClangRecordDecl_field_iterator_neq(it, end_it)) : (it = ZigClangRecordDecl_field_iterator_next(it)) { |
| 1352 | const field_decl = ZigClangRecordDecl_field_iterator_deref(it); |
| 1353 | |
| 1354 | if (ZigClangFieldDecl_isBitField(field_decl)) { |
| 1355 | return true; |
| 1356 | } |
| 1357 | } |
| 1358 | return false; |
| 1201 | 1359 | }, |
| 1202 | 1360 | .Elaborated => { |
| 1203 | 1361 | const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); |
| ... | ... | @@ -1450,7 +1608,7 @@ fn transCreateNodeArrayInitializer(c: *Context, type_node: *ast.Node) !*ast.Node |
| 1450 | 1608 | } |
| 1451 | 1609 | |
| 1452 | 1610 | fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { |
| 1453 | | const token = try appendToken(c, .IntegerLiteral, try std.fmt.allocPrint(c.a(), "{}", .{int})); |
| 1611 | const token = try appendTokenFmt(c, .IntegerLiteral, "{}", .{int}); |
| 1454 | 1612 | const node = try c.a().create(ast.Node.IntegerLiteral); |
| 1455 | 1613 | node.* = ast.Node.IntegerLiteral{ |
| 1456 | 1614 | .base = ast.Node{ .id = .IntegerLiteral }, |
| ... | ... | @@ -1459,6 +1617,21 @@ fn transCreateNodeInt(c: *Context, int: var) !*ast.Node { |
| 1459 | 1617 | return &node.base; |
| 1460 | 1618 | } |
| 1461 | 1619 | |
| 1620 | fn transCreateNodeOpaqueType(c: *Context) !*ast.Node { |
| 1621 | const builtin_tok = try appendToken(c, .Builtin, "@OpaqueType"); |
| 1622 | _ = try appendToken(c, .LParen, "("); |
| 1623 | const rparen_tok = try appendToken(c, .RParen, ")"); |
| 1624 | |
| 1625 | const call_node = try c.a().create(ast.Node.BuiltinCall); |
| 1626 | call_node.* = ast.Node.BuiltinCall{ |
| 1627 | .base = ast.Node{ .id = ast.Node.Id.BuiltinCall }, |
| 1628 | .builtin_token = builtin_tok, |
| 1629 | .params = ast.Node.BuiltinCall.ParamList.init(c.a()), |
| 1630 | .rparen_token = rparen_tok, |
| 1631 | }; |
| 1632 | return &call_node.base; |
| 1633 | } |
| 1634 | |
| 1462 | 1635 | const RestorePoint = struct { |
| 1463 | 1636 | c: *Context, |
| 1464 | 1637 | token_index: ast.TokenIndex, |
| ... | ... | @@ -1580,9 +1753,26 @@ fn transType(rp: RestorePoint, ty: *const ZigClangType, source_loc: ZigClangSour |
| 1580 | 1753 | const typedef_ty = @ptrCast(*const ZigClangTypedefType, ty); |
| 1581 | 1754 | |
| 1582 | 1755 | const typedef_decl = ZigClangTypedefType_getDecl(typedef_ty); |
| 1756 | // const typedef_name = rp.c.decl_table.get(@ptrToInt(ZigClangTypedefNameDecl_getCanonicalDecl(typedef_decl))).?.value; |
| 1583 | 1757 | const typedef_name = try rp.c.str(ZigClangDecl_getName_bytes_begin(@ptrCast(*const ZigClangDecl, typedef_decl))); |
| 1584 | 1758 | return appendIdentifier(rp.c, typedef_name); |
| 1585 | 1759 | }, |
| 1760 | .Record => { |
| 1761 | const record_ty = @ptrCast(*const ZigClangRecordType, ty); |
| 1762 | |
| 1763 | const record_decl = ZigClangRecordType_getDecl(record_ty); |
| 1764 | if (rp.c.decl_table.get(@ptrToInt(ZigClangRecordDecl_getCanonicalDecl(record_decl)))) |kv| |
| 1765 | return appendIdentifier(rp.c, kv.value) |
| 1766 | else |
| 1767 | return transRecordDecl(rp.c, record_decl); |
| 1768 | }, |
| 1769 | .Elaborated => { |
| 1770 | const elaborated_ty = @ptrCast(*const ZigClangElaboratedType, ty); |
| 1771 | switch (ZigClangElaboratedType_getKeyword(elaborated_ty)) { |
| 1772 | .Struct, .Enum, .Union => return try transQualType(rp, ZigClangElaboratedType_getNamedType(elaborated_ty), source_loc), |
| 1773 | else => return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported elaborated type", .{}), |
| 1774 | } |
| 1775 | }, |
| 1586 | 1776 | else => { |
| 1587 | 1777 | const type_name = rp.c.str(ZigClangType_getTypeClassName(ty)); |
| 1588 | 1778 | return revertAndWarn(rp, error.UnsupportedType, source_loc, "unsupported type: '{}'", .{type_name}); |