| ... | @@ -78,6 +78,17 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: ZigNode) !void { | ... | @@ -78,6 +78,17 @@ fn addTopLevelDecl(c: *Context, name: []const u8, decl_node: ZigNode) !void { |
| 78 | } | 78 | } |
| 79 | } | 79 | } |
| 80 | | 80 | |
| | 81 | fn fail( |
| | 82 | c: *Context, |
| | 83 | err: anytype, |
| | 84 | source_loc: TokenIndex, |
| | 85 | comptime format: []const u8, |
| | 86 | args: anytype, |
| | 87 | ) (@TypeOf(err) || error{OutOfMemory}) { |
| | 88 | try warn(c, &c.global_scope.base, source_loc, format, args); |
| | 89 | return err; |
| | 90 | } |
| | 91 | |
| 81 | fn failDecl(c: *Context, loc: TokenIndex, name: []const u8, comptime format: []const u8, args: anytype) Error!void { | 92 | fn failDecl(c: *Context, loc: TokenIndex, name: []const u8, comptime format: []const u8, args: anytype) Error!void { |
| 82 | // location | 93 | // location |
| 83 | // pub const name = @compileError(msg); | 94 | // pub const name = @compileError(msg); |
| ... | @@ -185,7 +196,7 @@ fn prepopulateGlobalNameTable(c: *Context) !void { | ... | @@ -185,7 +196,7 @@ fn prepopulateGlobalNameTable(c: *Context) !void { |
| 185 | for (c.tree.root_decls) |node| { | 196 | for (c.tree.root_decls) |node| { |
| 186 | const data = node_data[@intFromEnum(node)]; | 197 | const data = node_data[@intFromEnum(node)]; |
| 187 | switch (node_tags[@intFromEnum(node)]) { | 198 | switch (node_tags[@intFromEnum(node)]) { |
| 188 | .typedef => @panic("TODO"), | 199 | .typedef => {}, |
| 189 | | 200 | |
| 190 | .struct_decl_two, | 201 | .struct_decl_two, |
| 191 | .union_decl_two, | 202 | .union_decl_two, |
| ... | @@ -243,6 +254,7 @@ fn transTopLevelDecls(c: *Context) !void { | ... | @@ -243,6 +254,7 @@ fn transTopLevelDecls(c: *Context) !void { |
| 243 | fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { | 254 | fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { |
| 244 | const node_tags = c.tree.nodes.items(.tag); | 255 | const node_tags = c.tree.nodes.items(.tag); |
| 245 | const node_data = c.tree.nodes.items(.data); | 256 | const node_data = c.tree.nodes.items(.data); |
| | 257 | const node_ty = c.tree.nodes.items(.ty); |
| 246 | const data = node_data[@intFromEnum(decl)]; | 258 | const data = node_data[@intFromEnum(decl)]; |
| 247 | switch (node_tags[@intFromEnum(decl)]) { | 259 | switch (node_tags[@intFromEnum(decl)]) { |
| 248 | .typedef => { | 260 | .typedef => { |
| ... | @@ -252,17 +264,12 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { | ... | @@ -252,17 +264,12 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { |
| 252 | .struct_decl_two, | 264 | .struct_decl_two, |
| 253 | .union_decl_two, | 265 | .union_decl_two, |
| 254 | => { | 266 | => { |
| 255 | var fields = [2]NodeIndex{ data.bin.lhs, data.bin.rhs }; | 267 | try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]); |
| 256 | var field_count: u2 = 0; | | |
| 257 | if (fields[0] != .none) field_count += 1; | | |
| 258 | if (fields[1] != .none) field_count += 1; | | |
| 259 | try transRecordDecl(c, scope, decl, fields[0..field_count]); | | |
| 260 | }, | 268 | }, |
| 261 | .struct_decl, | 269 | .struct_decl, |
| 262 | .union_decl, | 270 | .union_decl, |
| 263 | => { | 271 | => { |
| 264 | const fields = c.tree.data[data.range.start..data.range.end]; | 272 | try transRecordDecl(c, scope, node_ty[@intFromEnum(decl)]); |
| 265 | try transRecordDecl(c, scope, decl, fields); | | |
| 266 | }, | 273 | }, |
| 267 | | 274 | |
| 268 | .enum_decl_two => { | 275 | .enum_decl_two => { |
| ... | @@ -270,11 +277,13 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { | ... | @@ -270,11 +277,13 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { |
| 270 | var field_count: u8 = 0; | 277 | var field_count: u8 = 0; |
| 271 | if (fields[0] != .none) field_count += 1; | 278 | if (fields[0] != .none) field_count += 1; |
| 272 | if (fields[1] != .none) field_count += 1; | 279 | if (fields[1] != .none) field_count += 1; |
| 273 | try transEnumDecl(c, scope, decl, fields[0..field_count]); | 280 | const enum_decl = node_ty[@intFromEnum(decl)].canonicalize(.standard).data.@"enum"; |
| | 281 | try transEnumDecl(c, scope, enum_decl, fields[0..field_count]); |
| 274 | }, | 282 | }, |
| 275 | .enum_decl => { | 283 | .enum_decl => { |
| 276 | const fields = c.tree.data[data.range.start..data.range.end]; | 284 | const fields = c.tree.data[data.range.start..data.range.end]; |
| 277 | try transEnumDecl(c, scope, decl, fields); | 285 | const enum_decl = node_ty[@intFromEnum(decl)].canonicalize(.standard).data.@"enum"; |
| | 286 | try transEnumDecl(c, scope, enum_decl, fields); |
| 278 | }, | 287 | }, |
| 279 | | 288 | |
| 280 | .enum_field_decl, | 289 | .enum_field_decl, |
| ... | @@ -294,7 +303,7 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { | ... | @@ -294,7 +303,7 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { |
| 294 | .inline_fn_def, | 303 | .inline_fn_def, |
| 295 | .inline_static_fn_def, | 304 | .inline_static_fn_def, |
| 296 | => { | 305 | => { |
| 297 | try transFnDecl(c, decl); | 306 | try transFnDecl(c, decl, true); |
| 298 | }, | 307 | }, |
| 299 | | 308 | |
| 300 | .@"var", | 309 | .@"var", |
| ... | @@ -304,15 +313,51 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { | ... | @@ -304,15 +313,51 @@ fn transDecl(c: *Context, scope: *Scope, decl: NodeIndex) !void { |
| 304 | .threadlocal_extern_var, | 313 | .threadlocal_extern_var, |
| 305 | .threadlocal_static_var, | 314 | .threadlocal_static_var, |
| 306 | => { | 315 | => { |
| 307 | try transVarDecl(c, decl, null); | 316 | try transVarDecl(c, decl); |
| 308 | }, | 317 | }, |
| 309 | .static_assert => try warn(c, &c.global_scope.base, 0, "ignoring _Static_assert declaration", .{}), | 318 | .static_assert => try warn(c, &c.global_scope.base, 0, "ignoring _Static_assert declaration", .{}), |
| 310 | else => unreachable, | 319 | else => unreachable, |
| 311 | } | 320 | } |
| 312 | } | 321 | } |
| 313 | | 322 | |
| 314 | fn transTypeDef(_: *Context, _: *Scope, _: NodeIndex) Error!void { | 323 | fn transTypeDef(c: *Context, scope: *Scope, typedef_decl: NodeIndex) Error!void { |
| 315 | @panic("TODO"); | 324 | const ty = c.tree.nodes.items(.ty)[@intFromEnum(typedef_decl)]; |
| | 325 | const data = c.tree.nodes.items(.data)[@intFromEnum(typedef_decl)]; |
| | 326 | |
| | 327 | const toplevel = scope.id == .root; |
| | 328 | const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined; |
| | 329 | |
| | 330 | var name: []const u8 = c.tree.tokSlice(data.decl.name); |
| | 331 | try c.typedefs.put(c.gpa, name, {}); |
| | 332 | |
| | 333 | if (!toplevel) name = try bs.makeMangledName(c, name); |
| | 334 | |
| | 335 | const typedef_loc = data.decl.name; |
| | 336 | const init_node = transType(c, scope, ty, .standard, typedef_loc) catch |err| switch (err) { |
| | 337 | error.UnsupportedType => { |
| | 338 | return failDecl(c, typedef_loc, name, "unable to resolve typedef child type", .{}); |
| | 339 | }, |
| | 340 | error.OutOfMemory => |e| return e, |
| | 341 | }; |
| | 342 | |
| | 343 | const payload = try c.arena.create(ast.Payload.SimpleVarDecl); |
| | 344 | payload.* = .{ |
| | 345 | .base = .{ .tag = ([2]ZigTag{ .var_simple, .pub_var_simple })[@intFromBool(toplevel)] }, |
| | 346 | .data = .{ |
| | 347 | .name = name, |
| | 348 | .init = init_node, |
| | 349 | }, |
| | 350 | }; |
| | 351 | const node = ZigNode.initPayload(&payload.base); |
| | 352 | |
| | 353 | if (toplevel) { |
| | 354 | try addTopLevelDecl(c, name, node); |
| | 355 | } else { |
| | 356 | try scope.appendNode(node); |
| | 357 | if (node.tag() != .pub_var_simple) { |
| | 358 | try bs.discardVariable(c, name); |
| | 359 | } |
| | 360 | } |
| 316 | } | 361 | } |
| 317 | | 362 | |
| 318 | fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 { | 363 | fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 { |
| ... | @@ -330,16 +375,14 @@ fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 { | ... | @@ -330,16 +375,14 @@ fn mangleWeakGlobalName(c: *Context, want_name: []const u8) ![]const u8 { |
| 330 | return cur_name; | 375 | return cur_name; |
| 331 | } | 376 | } |
| 332 | | 377 | |
| 333 | fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nodes: []const NodeIndex) Error!void { | 378 | fn transRecordDecl(c: *Context, scope: *Scope, record_ty: Type) Error!void { |
| 334 | const node_types = c.tree.nodes.items(.ty); | 379 | const record_decl = record_ty.getRecord().?; |
| 335 | const raw_record_ty = node_types[@intFromEnum(record_node)]; | | |
| 336 | const record_decl = raw_record_ty.getRecord().?; | | |
| 337 | if (c.decl_table.get(@intFromPtr(record_decl))) |_| | 380 | if (c.decl_table.get(@intFromPtr(record_decl))) |_| |
| 338 | return; // Avoid processing this decl twice | 381 | return; // Avoid processing this decl twice |
| 339 | const toplevel = scope.id == .root; | 382 | const toplevel = scope.id == .root; |
| 340 | const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined; | 383 | const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined; |
| 341 | | 384 | |
| 342 | const container_kind: ZigTag = if (raw_record_ty.is(.@"union")) .@"union" else .@"struct"; | 385 | const container_kind: ZigTag = if (record_ty.is(.@"union")) .@"union" else .@"struct"; |
| 343 | const container_kind_name: []const u8 = @tagName(container_kind); | 386 | const container_kind_name: []const u8 = @tagName(container_kind); |
| 344 | | 387 | |
| 345 | var is_unnamed = false; | 388 | var is_unnamed = false; |
| ... | @@ -350,7 +393,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod | ... | @@ -350,7 +393,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod |
| 350 | bare_name = typedef_name; | 393 | bare_name = typedef_name; |
| 351 | name = typedef_name; | 394 | name = typedef_name; |
| 352 | } else { | 395 | } else { |
| 353 | if (raw_record_ty.isAnonymousRecord(c.comp)) { | 396 | if (record_ty.isAnonymousRecord(c.comp)) { |
| 354 | bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()}); | 397 | bare_name = try std.fmt.allocPrint(c.arena, "unnamed_{d}", .{c.getMangle()}); |
| 355 | is_unnamed = true; | 398 | is_unnamed = true; |
| 356 | } | 399 | } |
| ... | @@ -364,6 +407,11 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod | ... | @@ -364,6 +407,11 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod |
| 364 | | 407 | |
| 365 | const is_pub = toplevel and !is_unnamed; | 408 | const is_pub = toplevel and !is_unnamed; |
| 366 | const init_node = blk: { | 409 | const init_node = blk: { |
| | 410 | if (record_decl.isIncomplete()) { |
| | 411 | try c.opaque_demotes.put(c.gpa, @intFromPtr(record_decl), {}); |
| | 412 | break :blk ZigTag.opaque_literal.init(); |
| | 413 | } |
| | 414 | |
| 367 | var fields = try std.ArrayList(ast.Payload.Record.Field).initCapacity(c.gpa, record_decl.fields.len); | 415 | var fields = try std.ArrayList(ast.Payload.Record.Field).initCapacity(c.gpa, record_decl.fields.len); |
| 368 | defer fields.deinit(); | 416 | defer fields.deinit(); |
| 369 | | 417 | |
| ... | @@ -377,17 +425,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod | ... | @@ -377,17 +425,10 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod |
| 377 | // layout, then we can just use a simple `extern` type. If it does have attributes, | 425 | // layout, then we can just use a simple `extern` type. If it does have attributes, |
| 378 | // then we need to inspect the layout and assign an `align` value for each field. | 426 | // then we need to inspect the layout and assign an `align` value for each field. |
| 379 | const has_alignment_attributes = record_decl.field_attributes != null or | 427 | const has_alignment_attributes = record_decl.field_attributes != null or |
| 380 | raw_record_ty.hasAttribute(.@"packed") or | 428 | record_ty.hasAttribute(.@"packed") or |
| 381 | raw_record_ty.hasAttribute(.aligned); | 429 | record_ty.hasAttribute(.aligned); |
| 382 | const head_field_alignment: ?c_uint = if (has_alignment_attributes) headFieldAlignment(record_decl) else null; | 430 | const head_field_alignment: ?c_uint = if (has_alignment_attributes) headFieldAlignment(record_decl) else null; |
| 383 | | 431 | |
| 384 | // Iterate over field nodes so that we translate any type decls included in this record decl. | | |
| 385 | // TODO: Move this logic into `fn transType()` instead of handling decl translation here. | | |
| 386 | for (field_nodes) |field_node| { | | |
| 387 | const field_raw_ty = node_types[@intFromEnum(field_node)]; | | |
| 388 | if (field_raw_ty.isEnumOrRecord()) try transDecl(c, scope, field_node); | | |
| 389 | } | | |
| 390 | | | |
| 391 | for (record_decl.fields, 0..) |field, field_index| { | 432 | for (record_decl.fields, 0..) |field, field_index| { |
| 392 | const field_loc = field.name_tok; | 433 | const field_loc = field.name_tok; |
| 393 | | 434 | |
| ... | @@ -473,7 +514,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod | ... | @@ -473,7 +514,7 @@ fn transRecordDecl(c: *Context, scope: *Scope, record_node: NodeIndex, field_nod |
| 473 | } | 514 | } |
| 474 | } | 515 | } |
| 475 | | 516 | |
| 476 | fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void { | 517 | fn transFnDecl(c: *Context, fn_decl: NodeIndex, is_pub: bool) Error!void { |
| 477 | const raw_ty = c.tree.nodes.items(.ty)[@intFromEnum(fn_decl)]; | 518 | const raw_ty = c.tree.nodes.items(.ty)[@intFromEnum(fn_decl)]; |
| 478 | const fn_ty = raw_ty.canonicalize(.standard); | 519 | const fn_ty = raw_ty.canonicalize(.standard); |
| 479 | const node_data = c.tree.nodes.items(.data)[@intFromEnum(fn_decl)]; | 520 | const node_data = c.tree.nodes.items(.data)[@intFromEnum(fn_decl)]; |
| ... | @@ -498,6 +539,7 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void { | ... | @@ -498,6 +539,7 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void { |
| 498 | | 539 | |
| 499 | else => unreachable, | 540 | else => unreachable, |
| 500 | }, | 541 | }, |
| | 542 | .is_pub = is_pub, |
| 501 | }; | 543 | }; |
| 502 | | 544 | |
| 503 | const proto_node = transFnType(c, &c.global_scope.base, raw_ty, fn_ty, fn_decl_loc, proto_ctx) catch |err| switch (err) { | 545 | const proto_node = transFnType(c, &c.global_scope.base, raw_ty, fn_ty, fn_decl_loc, proto_ctx) catch |err| switch (err) { |
| ... | @@ -566,22 +608,22 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void { | ... | @@ -566,22 +608,22 @@ fn transFnDecl(c: *Context, fn_decl: NodeIndex) Error!void { |
| 566 | return addTopLevelDecl(c, fn_name, proto_node); | 608 | return addTopLevelDecl(c, fn_name, proto_node); |
| 567 | } | 609 | } |
| 568 | | 610 | |
| 569 | fn transVarDecl(_: *Context, _: NodeIndex, _: ?usize) Error!void { | 611 | fn transVarDecl(c: *Context, node: NodeIndex) Error!void { |
| 570 | @panic("TODO"); | 612 | const data = c.tree.nodes.items(.data)[@intFromEnum(node)]; |
| | 613 | const name = c.tree.tokSlice(data.decl.name); |
| | 614 | return failDecl(c, data.decl.name, name, "unable to translate variable declaration", .{}); |
| 571 | } | 615 | } |
| 572 | | 616 | |
| 573 | fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: []const NodeIndex) Error!void { | 617 | fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: *const Type.Enum, field_nodes: []const NodeIndex) Error!void { |
| 574 | const node_types = c.tree.nodes.items(.ty); | 618 | if (c.decl_table.get(@intFromPtr(enum_decl))) |_| |
| 575 | const ty = node_types[@intFromEnum(enum_decl)]; | | |
| 576 | if (c.decl_table.get(@intFromPtr(ty.data.@"enum"))) |_| | | |
| 577 | return; // Avoid processing this decl twice | 619 | return; // Avoid processing this decl twice |
| 578 | const toplevel = scope.id == .root; | 620 | const toplevel = scope.id == .root; |
| 579 | const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined; | 621 | const bs: *Scope.Block = if (!toplevel) try scope.findBlockScope(c) else undefined; |
| 580 | | 622 | |
| 581 | var is_unnamed = false; | 623 | var is_unnamed = false; |
| 582 | var bare_name: []const u8 = c.mapper.lookup(ty.data.@"enum".name); | 624 | var bare_name: []const u8 = c.mapper.lookup(enum_decl.name); |
| 583 | var name = bare_name; | 625 | var name = bare_name; |
| 584 | if (c.unnamed_typedefs.get(@intFromPtr(ty.data.@"enum"))) |typedef_name| { | 626 | if (c.unnamed_typedefs.get(@intFromPtr(enum_decl))) |typedef_name| { |
| 585 | bare_name = typedef_name; | 627 | bare_name = typedef_name; |
| 586 | name = typedef_name; | 628 | name = typedef_name; |
| 587 | } else { | 629 | } else { |
| ... | @@ -592,10 +634,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: | ... | @@ -592,10 +634,10 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: |
| 592 | name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name}); | 634 | name = try std.fmt.allocPrint(c.arena, "enum_{s}", .{bare_name}); |
| 593 | } | 635 | } |
| 594 | if (!toplevel) name = try bs.makeMangledName(c, name); | 636 | if (!toplevel) name = try bs.makeMangledName(c, name); |
| 595 | try c.decl_table.putNoClobber(c.gpa, @intFromPtr(ty.data.@"enum"), name); | 637 | try c.decl_table.putNoClobber(c.gpa, @intFromPtr(enum_decl), name); |
| 596 | | 638 | |
| 597 | const enum_type_node = if (!ty.data.@"enum".isIncomplete()) blk: { | 639 | const enum_type_node = if (!enum_decl.isIncomplete()) blk: { |
| 598 | for (ty.data.@"enum".fields, field_nodes) |field, field_node| { | 640 | for (enum_decl.fields, field_nodes) |field, field_node| { |
| 599 | var enum_val_name: []const u8 = c.mapper.lookup(field.name); | 641 | var enum_val_name: []const u8 = c.mapper.lookup(field.name); |
| 600 | if (!toplevel) { | 642 | if (!toplevel) { |
| 601 | enum_val_name = try bs.makeMangledName(c, enum_val_name); | 643 | enum_val_name = try bs.makeMangledName(c, enum_val_name); |
| ... | @@ -621,14 +663,14 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: | ... | @@ -621,14 +663,14 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: |
| 621 | } | 663 | } |
| 622 | } | 664 | } |
| 623 | | 665 | |
| 624 | break :blk transType(c, scope, ty.data.@"enum".tag_ty, .standard, 0) catch |err| switch (err) { | 666 | break :blk transType(c, scope, enum_decl.tag_ty, .standard, 0) catch |err| switch (err) { |
| 625 | error.UnsupportedType => { | 667 | error.UnsupportedType => { |
| 626 | return failDecl(c, 0, name, "unable to translate enum integer type", .{}); | 668 | return failDecl(c, 0, name, "unable to translate enum integer type", .{}); |
| 627 | }, | 669 | }, |
| 628 | else => |e| return e, | 670 | else => |e| return e, |
| 629 | }; | 671 | }; |
| 630 | } else blk: { | 672 | } else blk: { |
| 631 | try c.opaque_demotes.put(c.gpa, @intFromPtr(ty.data.@"enum"), {}); | 673 | try c.opaque_demotes.put(c.gpa, @intFromPtr(enum_decl), {}); |
| 632 | break :blk ZigTag.opaque_literal.init(); | 674 | break :blk ZigTag.opaque_literal.init(); |
| 633 | }; | 675 | }; |
| 634 | | 676 | |
| ... | @@ -654,8 +696,21 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: | ... | @@ -654,8 +696,21 @@ fn transEnumDecl(c: *Context, scope: *Scope, enum_decl: NodeIndex, field_nodes: |
| 654 | } | 696 | } |
| 655 | } | 697 | } |
| 656 | | 698 | |
| | 699 | fn getTypeStr(c: *Context, ty: Type) ![]const u8 { |
| | 700 | var buf: std.ArrayListUnmanaged(u8) = .{}; |
| | 701 | defer buf.deinit(c.gpa); |
| | 702 | const w = buf.writer(c.gpa); |
| | 703 | try ty.print(c.mapper, c.comp.langopts, w); |
| | 704 | return c.arena.dupe(u8, buf.items); |
| | 705 | } |
| | 706 | |
| 657 | fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualHandling, source_loc: TokenIndex) TypeError!ZigNode { | 707 | fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualHandling, source_loc: TokenIndex) TypeError!ZigNode { |
| 658 | const ty = raw_ty.canonicalize(qual_handling); | 708 | const ty = raw_ty.canonicalize(qual_handling); |
| | 709 | if (ty.qual.atomic) { |
| | 710 | const type_name = try getTypeStr(c, ty); |
| | 711 | return fail(c, error.UnsupportedType, source_loc, "unsupported type: '{s}'", .{type_name}); |
| | 712 | } |
| | 713 | |
| 659 | switch (ty.specifier) { | 714 | switch (ty.specifier) { |
| 660 | .void => return ZigTag.type.create(c.arena, "anyopaque"), | 715 | .void => return ZigTag.type.create(c.arena, "anyopaque"), |
| 661 | .bool => return ZigTag.type.create(c.arena, "bool"), | 716 | .bool => return ZigTag.type.create(c.arena, "bool"), |
| ... | @@ -678,13 +733,53 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH | ... | @@ -678,13 +733,53 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH |
| 678 | .long_double => return ZigTag.type.create(c.arena, "c_longdouble"), | 733 | .long_double => return ZigTag.type.create(c.arena, "c_longdouble"), |
| 679 | .float80 => return ZigTag.type.create(c.arena, "f80"), | 734 | .float80 => return ZigTag.type.create(c.arena, "f80"), |
| 680 | .float128 => return ZigTag.type.create(c.arena, "f128"), | 735 | .float128 => return ZigTag.type.create(c.arena, "f128"), |
| 681 | .@"enum" => @panic("TODO"), | 736 | .@"enum" => { |
| 682 | .pointer, | 737 | const enum_decl = ty.data.@"enum"; |
| 683 | .unspecified_variable_len_array, | 738 | var trans_scope = scope; |
| | 739 | if (enum_decl.name != .empty) { |
| | 740 | const decl_name = c.mapper.lookup(enum_decl.name); |
| | 741 | if (c.weak_global_names.contains(decl_name)) trans_scope = &c.global_scope.base; |
| | 742 | } |
| | 743 | try transEnumDecl(c, trans_scope, enum_decl, &.{}); |
| | 744 | return ZigTag.identifier.create(c.arena, c.decl_table.get(@intFromPtr(enum_decl)).?); |
| | 745 | }, |
| | 746 | .pointer => { |
| | 747 | const child_type = ty.elemType(); |
| | 748 | |
| | 749 | const is_fn_proto = child_type.isFunc(); |
| | 750 | const is_const = is_fn_proto or child_type.isConst(); |
| | 751 | const is_volatile = child_type.qual.@"volatile"; |
| | 752 | const elem_type = try transType(c, scope, child_type, qual_handling, source_loc); |
| | 753 | const ptr_info = .{ |
| | 754 | .is_const = is_const, |
| | 755 | .is_volatile = is_volatile, |
| | 756 | .elem_type = elem_type, |
| | 757 | }; |
| | 758 | if (is_fn_proto or |
| | 759 | typeIsOpaque(c, child_type) or |
| | 760 | typeWasDemotedToOpaque(c, child_type)) |
| | 761 | { |
| | 762 | const ptr = try ZigTag.single_pointer.create(c.arena, ptr_info); |
| | 763 | return ZigTag.optional_type.create(c.arena, ptr); |
| | 764 | } |
| | 765 | |
| | 766 | return ZigTag.c_pointer.create(c.arena, ptr_info); |
| | 767 | }, |
| | 768 | .unspecified_variable_len_array, .incomplete_array => { |
| | 769 | const child_type = ty.elemType(); |
| | 770 | const is_const = child_type.qual.@"const"; |
| | 771 | const is_volatile = child_type.qual.@"volatile"; |
| | 772 | const elem_type = try transType(c, scope, child_type, qual_handling, source_loc); |
| | 773 | |
| | 774 | return ZigTag.c_pointer.create(c.arena, .{ .is_const = is_const, .is_volatile = is_volatile, .elem_type = elem_type }); |
| | 775 | }, |
| 684 | .array, | 776 | .array, |
| 685 | .static_array, | 777 | .static_array, |
| 686 | .incomplete_array, | 778 | => { |
| 687 | => @panic("TODO"), | 779 | const size = ty.arrayLen().?; |
| | 780 | const elem_type = try transType(c, scope, ty.elemType(), qual_handling, source_loc); |
| | 781 | return ZigTag.array_type.create(c.arena, .{ .len = size, .elem_type = elem_type }); |
| | 782 | }, |
| 688 | .func, | 783 | .func, |
| 689 | .var_args_func, | 784 | .var_args_func, |
| 690 | .old_style_func, | 785 | .old_style_func, |
| ... | @@ -698,6 +793,7 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH | ... | @@ -698,6 +793,7 @@ fn transType(c: *Context, scope: *Scope, raw_ty: Type, qual_handling: Type.QualH |
| 698 | const name_id = c.mapper.lookup(record_decl.name); | 793 | const name_id = c.mapper.lookup(record_decl.name); |
| 699 | if (c.weak_global_names.contains(name_id)) trans_scope = &c.global_scope.base; | 794 | if (c.weak_global_names.contains(name_id)) trans_scope = &c.global_scope.base; |
| 700 | } | 795 | } |
| | 796 | try transRecordDecl(c, trans_scope, ty); |
| 701 | const name = c.decl_table.get(@intFromPtr(ty.data.record)).?; | 797 | const name = c.decl_table.get(@intFromPtr(ty.data.record)).?; |
| 702 | return ZigTag.identifier.create(c.arena, name); | 798 | return ZigTag.identifier.create(c.arena, name); |
| 703 | }, | 799 | }, |
| ... | @@ -927,7 +1023,9 @@ fn transFnType( | ... | @@ -927,7 +1023,9 @@ fn transFnType( |
| 927 | } | 1023 | } |
| 928 | | 1024 | |
| 929 | fn transStmt(c: *Context, node: NodeIndex) TransError!ZigNode { | 1025 | fn transStmt(c: *Context, node: NodeIndex) TransError!ZigNode { |
| 930 | return transExpr(c, node, .unused); | 1026 | _ = c; |
| | 1027 | _ = node; |
| | 1028 | return error.UnsupportedTranslation; |
| 931 | } | 1029 | } |
| 932 | | 1030 | |
| 933 | fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block) TransError!void { | 1031 | fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block) TransError!void { |
| ... | @@ -952,6 +1050,45 @@ fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block | ... | @@ -952,6 +1050,45 @@ fn transCompoundStmtInline(c: *Context, compound: NodeIndex, block: *Scope.Block |
| 952 | } | 1050 | } |
| 953 | } | 1051 | } |
| 954 | | 1052 | |
| | 1053 | fn recordHasBitfield(record: *const Type.Record) bool { |
| | 1054 | if (record.isIncomplete()) return false; |
| | 1055 | for (record.fields) |field| { |
| | 1056 | if (!field.isRegularField()) return true; |
| | 1057 | } |
| | 1058 | return false; |
| | 1059 | } |
| | 1060 | |
| | 1061 | fn typeIsOpaque(c: *Context, ty: Type) bool { |
| | 1062 | return switch (ty.specifier) { |
| | 1063 | .void => true, |
| | 1064 | .@"struct", .@"union" => recordHasBitfield(ty.getRecord().?), |
| | 1065 | .typeof_type => typeIsOpaque(c, ty.data.sub_type.*), |
| | 1066 | .typeof_expr => typeIsOpaque(c, ty.data.expr.ty), |
| | 1067 | .attributed => typeIsOpaque(c, ty.data.attributed.base), |
| | 1068 | else => false, |
| | 1069 | }; |
| | 1070 | } |
| | 1071 | |
| | 1072 | fn typeWasDemotedToOpaque(c: *Context, ty: Type) bool { |
| | 1073 | switch (ty.specifier) { |
| | 1074 | .@"struct", .@"union" => { |
| | 1075 | const record = ty.getRecord().?; |
| | 1076 | if (c.opaque_demotes.contains(@intFromPtr(record))) return true; |
| | 1077 | for (record.fields) |field| { |
| | 1078 | if (typeWasDemotedToOpaque(c, field.ty)) return true; |
| | 1079 | } |
| | 1080 | return false; |
| | 1081 | }, |
| | 1082 | |
| | 1083 | .@"enum" => return c.opaque_demotes.contains(@intFromPtr(ty.data.@"enum")), |
| | 1084 | |
| | 1085 | .typeof_type => return typeWasDemotedToOpaque(c, ty.data.sub_type.*), |
| | 1086 | .typeof_expr => return typeWasDemotedToOpaque(c, ty.data.expr.ty), |
| | 1087 | .attributed => return typeWasDemotedToOpaque(c, ty.data.attributed.base), |
| | 1088 | else => return false, |
| | 1089 | } |
| | 1090 | } |
| | 1091 | |
| 955 | fn transCompoundStmt(c: *Context, scope: *Scope, compound: NodeIndex) TransError!ZigNode { | 1092 | fn transCompoundStmt(c: *Context, scope: *Scope, compound: NodeIndex) TransError!ZigNode { |
| 956 | var block_scope = try Scope.Block.init(c, scope, false); | 1093 | var block_scope = try Scope.Block.init(c, scope, false); |
| 957 | defer block_scope.deinit(); | 1094 | defer block_scope.deinit(); |