13 files changed, 298 insertions(+), 56 deletions(-)
CHANGELOG.md+1| ... | @@ -2,6 +2,7 @@ | ... | @@ -2,6 +2,7 @@ |
| 2 | 2 | ||
| 3 | - feat: clarify "defined runtime representation" and "can be represented at runtime" | 3 | - feat: clarify "defined runtime representation" and "can be represented at runtime" |
| 4 | - feat: implement inferred structs + result type semantics | 4 | - feat: implement inferred structs + result type semantics |
| 5 | - feat: add `--dump-state=./filename.json` to dump compiler state as JSON | ||
| 5 | - chore: remove group expressions, use single expression blocks instead | 6 | - chore: remove group expressions, use single expression blocks instead |
| 6 | - fix(sema): fix passing structs as function params | 7 | - fix(sema): fix passing structs as function params |
| 7 | - fix: diagnostic box drawing characters line up after line 9 | 8 | - fix: diagnostic box drawing characters line up after line 9 |
build.zig+8-2| ... | @@ -92,7 +92,6 @@ pub fn build(b: *std.Build) !void { | ... | @@ -92,7 +92,6 @@ pub fn build(b: *std.Build) !void { |
| 92 | .root_source_file = b.path("src/manual/generate-man.zig"), | 92 | .root_source_file = b.path("src/manual/generate-man.zig"), |
| 93 | .target = native_target, | 93 | .target = native_target, |
| 94 | .optimize = .Debug, | 94 | .optimize = .Debug, |
| 95 | .link_libc = true, | ||
| 96 | }); | 95 | }); |
| 97 | manual_generator.root_module.addImport("build_options", native_debug.opts_mod); | 96 | manual_generator.root_module.addImport("build_options", native_debug.opts_mod); |
| 98 | manual_generator.root_module.addImport("core", native_debug.core); | 97 | manual_generator.root_module.addImport("core", native_debug.core); |
| ... | @@ -204,10 +203,11 @@ fn buildWithTarget( | ... | @@ -204,10 +203,11 @@ fn buildWithTarget( |
| 204 | const opts_mod = opts.createModule(); | 203 | const opts_mod = opts.createModule(); |
| 205 | 204 | ||
| 206 | // Core | 205 | // Core |
| 207 | const core = b.addModule("compiler", .{ | 206 | const core = b.addModule("core", .{ |
| 208 | .root_source_file = b.path("src/core/mod.zig"), | 207 | .root_source_file = b.path("src/core/mod.zig"), |
| 209 | .optimize = optimize, | 208 | .optimize = optimize, |
| 210 | .target = target, | 209 | .target = target, |
| 210 | .strip = false, | ||
| 211 | }); | 211 | }); |
| 212 | core.addImport("build_options", opts_mod); | 212 | core.addImport("build_options", opts_mod); |
| 213 | core.addImport("tracer", tracer.module("tracer")); | 213 | core.addImport("tracer", tracer.module("tracer")); |
| ... | @@ -220,6 +220,7 @@ fn buildWithTarget( | ... | @@ -220,6 +220,7 @@ fn buildWithTarget( |
| 220 | .optimize = optimize, | 220 | .optimize = optimize, |
| 221 | .use_lld = use_lld, | 221 | .use_lld = use_lld, |
| 222 | .use_llvm = use_llvm, | 222 | .use_llvm = use_llvm, |
| 223 | .strip = false, | ||
| 223 | }); | 224 | }); |
| 224 | core_tests.root_module.addImport("build_options", opts_mod); | 225 | core_tests.root_module.addImport("build_options", opts_mod); |
| 225 | core_tests.root_module.addImport("tracer", tracer.module("tracer")); | 226 | core_tests.root_module.addImport("tracer", tracer.module("tracer")); |
| ... | @@ -233,6 +234,8 @@ fn buildWithTarget( | ... | @@ -233,6 +234,8 @@ fn buildWithTarget( |
| 233 | .optimize = optimize, | 234 | .optimize = optimize, |
| 234 | .use_lld = use_lld, | 235 | .use_lld = use_lld, |
| 235 | .use_llvm = use_llvm, | 236 | .use_llvm = use_llvm, |
| 237 | .strip = false, | ||
| 238 | .omit_frame_pointer = false, | ||
| 236 | }); | 239 | }); |
| 237 | compiler_exe.root_module.addImport("build_options", opts_mod); | 240 | compiler_exe.root_module.addImport("build_options", opts_mod); |
| 238 | compiler_exe.root_module.addImport("core", core); | 241 | compiler_exe.root_module.addImport("core", core); |
| ... | @@ -246,6 +249,9 @@ fn buildWithTarget( | ... | @@ -246,6 +249,9 @@ fn buildWithTarget( |
| 246 | .optimize = optimize, | 249 | .optimize = optimize, |
| 247 | .use_lld = use_lld, | 250 | .use_lld = use_lld, |
| 248 | .use_llvm = use_llvm, | 251 | .use_llvm = use_llvm, |
| 252 | .strip = false, | ||
| 253 | .omit_frame_pointer = false, | ||
| 254 | .unwind_tables = false, | ||
| 249 | }); | 255 | }); |
| 250 | lsp_exe.root_module.addImport("build_options", opts_mod); | 256 | lsp_exe.root_module.addImport("build_options", opts_mod); |
| 251 | lsp_exe.root_module.addImport("core", core); | 257 | lsp_exe.root_module.addImport("core", core); |
src/core/Air.Dump.zig+1-1| ... | @@ -143,7 +143,7 @@ pub const State = struct { | ... | @@ -143,7 +143,7 @@ pub const State = struct { |
| 143 | try tty.setColor(w, .reset); | 143 | try tty.setColor(w, .reset); |
| 144 | try w.writeAll(")"); | 144 | try w.writeAll(")"); |
| 145 | }, | 145 | }, |
| 146 | inline .call, .new => |t| { | 146 | inline .call, .js_new => |t| { |
| 147 | const call: Air.Call = air.instData(t, inst); | 147 | const call: Air.Call = air.instData(t, inst); |
| 148 | const call_data = call.call_data.get(air); | 148 | const call_data = call.call_data.get(air); |
| 149 | try w.writeAll("("); | 149 | try w.writeAll("("); |
src/core/Air.zig+5-5| ... | @@ -16,7 +16,7 @@ pub const Inst = struct { | ... | @@ -16,7 +16,7 @@ pub const Inst = struct { |
| 16 | block, | 16 | block, |
| 17 | js_global_ref, | 17 | js_global_ref, |
| 18 | call, | 18 | call, |
| 19 | new, | 19 | js_new, |
| 20 | @"break", | 20 | @"break", |
| 21 | @"if", | 21 | @"if", |
| 22 | arg, | 22 | arg, |
| ... | @@ -53,7 +53,7 @@ pub const Inst = struct { | ... | @@ -53,7 +53,7 @@ pub const Inst = struct { |
| 53 | .js_global_ref => InternPool.String.WithLen, | 53 | .js_global_ref => InternPool.String.WithLen, |
| 54 | .@"break" => Break, | 54 | .@"break" => Break, |
| 55 | .@"if" => If, | 55 | .@"if" => If, |
| 56 | .call, .new => Call, | 56 | .call, .js_new => Call, |
| 57 | .arg => Arg, | 57 | .arg => Arg, |
| 58 | .memory => Memory, | 58 | .memory => Memory, |
| 59 | .store => Store, | 59 | .store => Store, |
| ... | @@ -323,7 +323,7 @@ pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *const InternPool) InternPool. | ... | @@ -323,7 +323,7 @@ pub fn typeOf(air: *const Air, ref: Inst.Ref, ip: *const InternPool) InternPool. |
| 323 | pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) InternPool.Type { | 323 | pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) InternPool.Type { |
| 324 | return switch (air.instTag(index)) { | 324 | return switch (air.instTag(index)) { |
| 325 | // These values are by definition, opaque | 325 | // These values are by definition, opaque |
| 326 | .js_global_ref, .new => .@"opaque", | 326 | .js_global_ref, .js_new => .@"opaque", |
| 327 | 327 | ||
| 328 | // These operations always produce known types | 328 | // These operations always produce known types |
| 329 | .lt, .gt, .eq, .bool_not => .bool, | 329 | .lt, .gt, .eq, .bool_not => .bool, |
| ... | @@ -375,7 +375,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In | ... | @@ -375,7 +375,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In |
| 375 | .field_struct => { | 375 | .field_struct => { |
| 376 | const inst = air.instData(.field_struct, index); | 376 | const inst = air.instData(.field_struct, index); |
| 377 | const base_type = air.typeOfIndex(inst.base, ip) | 377 | const base_type = air.typeOfIndex(inst.base, ip) |
| 378 | .toStructType(ip) orelse unreachable; // not a struct | 378 | .toStructType(ip) orelse unreachable; // field_struct demands struct type |
| 379 | return base_type.field_types[inst.field_index]; | 379 | return base_type.field_types[inst.field_index]; |
| 380 | }, | 380 | }, |
| 381 | 381 | ||
| ... | @@ -383,7 +383,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In | ... | @@ -383,7 +383,7 @@ pub fn typeOfIndex(air: *const Air, index: Inst.Index, ip: *const InternPool) In |
| 383 | .index => { | 383 | .index => { |
| 384 | const inst = air.instData(.index, index); | 384 | const inst = air.instData(.index, index); |
| 385 | const base_type = air.typeOf(inst.lhs, ip) | 385 | const base_type = air.typeOf(inst.lhs, ip) |
| 386 | .toArrayType(ip) orelse unreachable; // not an array | 386 | .toArrayType(ip) orelse unreachable; // index demands array type |
| 387 | return base_type.item_type; | 387 | return base_type.item_type; |
| 388 | }, | 388 | }, |
| 389 | }; | 389 | }; |
src/core/Comp.zig+132-20| ... | @@ -8,7 +8,8 @@ gpa: Allocator, | ... | @@ -8,7 +8,8 @@ gpa: Allocator, |
| 8 | /// Stores all Type and Value objects. | 8 | /// Stores all Type and Value objects. |
| 9 | intern_pool: InternPool = .{}, | 9 | intern_pool: InternPool = .{}, |
| 10 | /// All files in the compilation | 10 | /// All files in the compilation |
| 11 | files: std.StringArrayHashMapUnmanaged(*File) = .{}, | 11 | /// TODO: turn this into a HashMap(*File, void) as File owns it's key |
| 12 | files: std.StringHashMapUnmanaged(*File) = .{}, | ||
| 12 | 13 | ||
| 13 | options: Options = .{}, | 14 | options: Options = .{}, |
| 14 | 15 | ||
| ... | @@ -20,8 +21,9 @@ pub fn init(comp: *Comp) !void { | ... | @@ -20,8 +21,9 @@ pub fn init(comp: *Comp) !void { |
| 20 | 21 | ||
| 21 | pub fn deinit(comp: *Comp) void { | 22 | pub fn deinit(comp: *Comp) void { |
| 22 | comp.intern_pool.deinit(comp.gpa); | 23 | comp.intern_pool.deinit(comp.gpa); |
| 23 | for (comp.files.values()) |file| { | 24 | var it = comp.files.valueIterator(); |
| 24 | file.deinit(comp.gpa); | 25 | while (it.next()) |file| { |
| 26 | file.*.deinit(comp.gpa); | ||
| 25 | } | 27 | } |
| 26 | comp.files.deinit(comp.gpa); | 28 | comp.files.deinit(comp.gpa); |
| 27 | comp.backend.deinit(comp); | 29 | comp.backend.deinit(comp); |
| ... | @@ -96,7 +98,7 @@ pub const File = struct { | ... | @@ -96,7 +98,7 @@ pub const File = struct { |
| 96 | /// TODO: change this to a URL | 98 | /// TODO: change this to a URL |
| 97 | file_path: []const u8, | 99 | file_path: []const u8, |
| 98 | 100 | ||
| 99 | root_namespace: Decl.Index.Optional, | 101 | root_namespace: Namespace.Index.Optional, |
| 100 | status: enum { | 102 | status: enum { |
| 101 | never_loaded, | 103 | never_loaded, |
| 102 | /// A failure occurred while loading the file. Retrying might succeed. | 104 | /// A failure occurred while loading the file. Retrying might succeed. |
| ... | @@ -249,6 +251,36 @@ pub const File = struct { | ... | @@ -249,6 +251,36 @@ pub const File = struct { |
| 249 | file.unloadSource(gpa); | 251 | file.unloadSource(gpa); |
| 250 | gpa.destroy(file); | 252 | gpa.destroy(file); |
| 251 | } | 253 | } |
| 254 | |||
| 255 | pub fn fmtJson(file: *const File, comp: *const Comp) JsonFormatter { | ||
| 256 | return .{ .file = file, .comp = comp }; | ||
| 257 | } | ||
| 258 | |||
| 259 | const JsonFormatter = struct { | ||
| 260 | file: *const File, | ||
| 261 | comp: *const Comp, | ||
| 262 | |||
| 263 | pub fn jsonStringify(ctx: JsonFormatter, json_writer: anytype) !void { | ||
| 264 | // file path is already written | ||
| 265 | const jw = core.jsonWriterCast(json_writer); | ||
| 266 | try jw.beginObject(); | ||
| 267 | try jw.objectField("path_digest"); | ||
| 268 | try if (ctx.file.path_digest) |digest| | ||
| 269 | jw.write(std.fmt.bytesToHex(digest, .lower)) | ||
| 270 | else | ||
| 271 | jw.write(null); | ||
| 272 | try jw.objectField("status"); | ||
| 273 | try jw.write(ctx.file.status); | ||
| 274 | try jw.objectField("root_namespace"); | ||
| 275 | if (ctx.file.root_namespace.unwrap()) |ns_index| { | ||
| 276 | const ns = ctx.comp.intern_pool.namespacePtrConst(ns_index); | ||
| 277 | try jw.write(ns.fmtJson(ctx.comp)); | ||
| 278 | } else { | ||
| 279 | try jw.write(null); | ||
| 280 | } | ||
| 281 | try jw.endObject(); | ||
| 282 | } | ||
| 283 | }; | ||
| 252 | }; | 284 | }; |
| 253 | 285 | ||
| 254 | /// A declaration is a named value which also represents the smallest unit of | 286 | /// A declaration is a named value which also represents the smallest unit of |
| ... | @@ -328,12 +360,43 @@ pub const Decl = struct { | ... | @@ -328,12 +360,43 @@ pub const Decl = struct { |
| 328 | }; | 360 | }; |
| 329 | } | 361 | } |
| 330 | 362 | ||
| 331 | pub fn deinit(decl: *Decl, gpa: Allocator) void { | 363 | pub fn fmtJson(decl: *const Decl, comp: *const Comp) JsonFormatter { |
| 332 | _ = gpa; // autofix | 364 | return .{ .decl = decl, .comp = comp }; |
| 333 | defer decl.* = undefined; | ||
| 334 | // if (decl.codegen) |*cg| cg.deinit(gpa); | ||
| 335 | } | 365 | } |
| 336 | 366 | ||
| 367 | const JsonFormatter = struct { | ||
| 368 | decl: *const Decl, | ||
| 369 | comp: *const Comp, | ||
| 370 | |||
| 371 | pub fn jsonStringify(ctx: JsonFormatter, json_writer: anytype) !void { | ||
| 372 | const decl = ctx.decl; | ||
| 373 | const comp = ctx.comp; | ||
| 374 | |||
| 375 | const jw = core.jsonWriterCast(json_writer); | ||
| 376 | try jw.beginObject(); | ||
| 377 | |||
| 378 | try jw.objectField("name"); | ||
| 379 | try jw.write(decl.name.toSlice(&comp.intern_pool)); | ||
| 380 | try jw.objectField("analysis"); | ||
| 381 | try jw.write(decl.analysis); | ||
| 382 | try jw.objectField("teg_decl_index"); | ||
| 383 | try jw.write(decl.teg_decl_index.get(&comp.intern_pool)); | ||
| 384 | try jw.objectField("value"); | ||
| 385 | if (decl.raw_value) |val| { | ||
| 386 | var buf: [8192]u8 = undefined; | ||
| 387 | try jw.print("", .{}); | ||
| 388 | try jw.stream.print("[{d}, ", .{@intFromEnum(val)}); | ||
| 389 | try std.json.encodeJsonString( | ||
| 390 | std.fmt.bufPrint(&buf, "{}", .{val.dump(&comp.intern_pool)}) catch &buf, | ||
| 391 | .{}, | ||
| 392 | jw.stream, | ||
| 393 | ); | ||
| 394 | try jw.stream.print("]", .{}); | ||
| 395 | } | ||
| 396 | try jw.endObject(); | ||
| 397 | } | ||
| 398 | }; | ||
| 399 | |||
| 337 | pub const Index = InternPool.DeclIndex; | 400 | pub const Index = InternPool.DeclIndex; |
| 338 | }; | 401 | }; |
| 339 | 402 | ||
| ... | @@ -348,8 +411,6 @@ pub const Namespace = struct { | ... | @@ -348,8 +411,6 @@ pub const Namespace = struct { |
| 348 | file_scope: *File, | 411 | file_scope: *File, |
| 349 | /// Direct children of the namespace. | 412 | /// Direct children of the namespace. |
| 350 | /// Declaration order is preserved via entry order. | 413 | /// Declaration order is preserved via entry order. |
| 351 | /// These are only declarations named directly by the AST; anonymous | ||
| 352 | /// declarations are not stored here. | ||
| 353 | decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{}, | 414 | decls: std.ArrayHashMapUnmanaged(Decl.Index, void, DeclContext, true) = .{}, |
| 354 | 415 | ||
| 355 | pub const DeclContext = struct { | 416 | pub const DeclContext = struct { |
| ... | @@ -400,6 +461,34 @@ pub const Namespace = struct { | ... | @@ -400,6 +461,34 @@ pub const Namespace = struct { |
| 400 | return ns.decls.getKeyAdapted(name, Namespace.DeclNameAdapter{ .comp = comp }); | 461 | return ns.decls.getKeyAdapted(name, Namespace.DeclNameAdapter{ .comp = comp }); |
| 401 | } | 462 | } |
| 402 | 463 | ||
| 464 | pub fn fmtJson(ns: *const Namespace, comp: *const Comp) JsonFormatter { | ||
| 465 | return .{ .ns = ns, .comp = comp }; | ||
| 466 | } | ||
| 467 | |||
| 468 | const JsonFormatter = struct { | ||
| 469 | ns: *const Namespace, | ||
| 470 | comp: *const Comp, | ||
| 471 | |||
| 472 | pub fn jsonStringify(ctx: JsonFormatter, json_writer: anytype) !void { | ||
| 473 | const ns = ctx.ns; | ||
| 474 | const comp = ctx.comp; | ||
| 475 | |||
| 476 | const jw = core.jsonWriterCast(json_writer); | ||
| 477 | try jw.beginObject(); | ||
| 478 | // try jw.objectField("parent"); | ||
| 479 | // try if (ns.parent.unwrap()) |p| jw.write(@intFromEnum(p)) else jw.write(null); | ||
| 480 | try jw.objectField("decls"); | ||
| 481 | try jw.beginObject(); | ||
| 482 | for (ns.decls.keys()) |decl_index| { | ||
| 483 | const decl = comp.intern_pool.declPtrConst(decl_index); | ||
| 484 | try jw.objectField(decl.name.toSlice(&comp.intern_pool)); | ||
| 485 | try jw.write(decl.fmtJson(comp)); | ||
| 486 | } | ||
| 487 | try jw.endObject(); | ||
| 488 | try jw.endObject(); | ||
| 489 | } | ||
| 490 | }; | ||
| 491 | |||
| 403 | pub const Index = InternPool.NamespaceIndex; | 492 | pub const Index = InternPool.NamespaceIndex; |
| 404 | }; | 493 | }; |
| 405 | 494 | ||
| ... | @@ -408,10 +497,13 @@ pub const Namespace = struct { | ... | @@ -408,10 +497,13 @@ pub const Namespace = struct { |
| 408 | pub fn indexTegModule(comp: *Comp, file: *File, module_index: Teg.Inst.Index) !Namespace.Index { | 497 | pub fn indexTegModule(comp: *Comp, file: *File, module_index: Teg.Inst.Index) !Namespace.Index { |
| 409 | const teg = file.teg.?; | 498 | const teg = file.teg.?; |
| 410 | 499 | ||
| 500 | assert(file.root_namespace == .none); | ||
| 501 | |||
| 411 | const ns = try comp.intern_pool.createNamespace(comp.gpa, .{ | 502 | const ns = try comp.intern_pool.createNamespace(comp.gpa, .{ |
| 412 | .parent = .none, | 503 | .parent = .none, |
| 413 | .file_scope = file, | 504 | .file_scope = file, |
| 414 | }); | 505 | }); |
| 506 | file.root_namespace = ns.toOptional(); | ||
| 415 | const ns_ptr = comp.intern_pool.namespacePtr(ns); | 507 | const ns_ptr = comp.intern_pool.namespacePtr(ns); |
| 416 | errdefer comp.intern_pool.destroyNamespace(comp.gpa, ns); | 508 | errdefer comp.intern_pool.destroyNamespace(comp.gpa, ns); |
| 417 | 509 | ||
| ... | @@ -450,6 +542,8 @@ const Options = struct { | ... | @@ -450,6 +542,8 @@ const Options = struct { |
| 450 | dump_ir: bool = false, | 542 | dump_ir: bool = false, |
| 451 | }; | 543 | }; |
| 452 | 544 | ||
| 545 | /// The compiler backend is stored separately from the compilation, and | ||
| 546 | /// interaction is done via this static dispatch contract. | ||
| 453 | pub const Backend = union(enum) { | 547 | pub const Backend = union(enum) { |
| 454 | js: *@import("js/Js.zig"), | 548 | js: *@import("js/Js.zig"), |
| 455 | 549 | ||
| ... | @@ -485,6 +579,23 @@ pub const Backend = union(enum) { | ... | @@ -485,6 +579,23 @@ pub const Backend = union(enum) { |
| 485 | pub const Tag = std.meta.FieldEnum(Backend); | 579 | pub const Tag = std.meta.FieldEnum(Backend); |
| 486 | }; | 580 | }; |
| 487 | 581 | ||
| 582 | pub fn jsonStringify(comp: *const Comp, json_writer: anytype) !void { | ||
| 583 | const jw = core.jsonWriterCast(json_writer); | ||
| 584 | |||
| 585 | try jw.beginObject(); | ||
| 586 | try jw.objectField("files"); | ||
| 587 | try jw.beginObject(); | ||
| 588 | var it = comp.files.valueIterator(); | ||
| 589 | while (it.next()) |entry| { | ||
| 590 | try jw.objectField(entry.*.file_path); | ||
| 591 | try jw.write(entry.*.fmtJson(comp)); | ||
| 592 | } | ||
| 593 | try jw.endObject(); | ||
| 594 | try jw.objectField("intern_pool"); | ||
| 595 | try jw.write(comp.intern_pool); | ||
| 596 | try jw.endObject(); | ||
| 597 | } | ||
| 598 | |||
| 488 | const Comp = @This(); | 599 | const Comp = @This(); |
| 489 | 600 | ||
| 490 | const std = @import("std"); | 601 | const std = @import("std"); |
| ... | @@ -493,15 +604,16 @@ const assert = std.debug.assert; | ... | @@ -493,15 +604,16 @@ const assert = std.debug.assert; |
| 493 | const Stat = std.Build.Cache.File.Stat; | 604 | const Stat = std.Build.Cache.File.Stat; |
| 494 | const log = std.log.scoped(.comp); | 605 | const log = std.log.scoped(.comp); |
| 495 | 606 | ||
| 496 | const InternPool = @import("InternPool.zig"); | 607 | const core = @import("mod.zig"); |
| 497 | 608 | const InternPool = core.InternPool; | |
| 498 | const Ast = @import("Ast.zig"); | 609 | |
| 499 | const Air = @import("Air.zig"); | 610 | const Ast = core.Ast; |
| 500 | const Teg = @import("Teg.zig"); | 611 | const Air = core.Air; |
| 501 | const Cache = @import("Cache.zig"); | 612 | const Teg = core.Teg; |
| 502 | const Sema = @import("Sema.zig"); | 613 | const Cache = core.Cache; |
| 503 | const Transform = @import("Transform.zig"); | 614 | const Sema = core.Sema; |
| 504 | const Report = @import("Report.zig"); | 615 | const Transform = core.Transform; |
| 505 | const Parse = @import("Parse.zig"); | 616 | const Report = core.Report; |
| 617 | const Parse = core.Parse; | ||
| 506 | 618 | ||
| 507 | const tracer = @import("tracer"); | 619 | const tracer = @import("tracer"); |
src/core/InternPool.zig+93-12| ... | @@ -714,14 +714,21 @@ pub const TrackedInst = extern struct { | ... | @@ -714,14 +714,21 @@ pub const TrackedInst = extern struct { |
| 714 | pub const Index = enum(u32) { | 714 | pub const Index = enum(u32) { |
| 715 | _, | 715 | _, |
| 716 | pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Teg.Inst.Index { | 716 | pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Teg.Inst.Index { |
| 717 | return ip.tracked_insts.keys()[@intFromEnum(i)].inst; | 717 | return i.get(ip).inst; |
| 718 | } | 718 | } |
| 719 | |||
| 720 | pub fn get(i: TrackedInst.Index, ip: *const InternPool) TrackedInst { | ||
| 721 | return ip.tracked_insts.keys()[@intFromEnum(i)]; | ||
| 722 | } | ||
| 723 | |||
| 719 | pub fn toOptional(i: TrackedInst.Index) Optional { | 724 | pub fn toOptional(i: TrackedInst.Index) Optional { |
| 720 | return @enumFromInt(@intFromEnum(i)); | 725 | return @enumFromInt(@intFromEnum(i)); |
| 721 | } | 726 | } |
| 727 | |||
| 722 | pub const Optional = enum(u32) { | 728 | pub const Optional = enum(u32) { |
| 723 | none = std.math.maxInt(u32), | 729 | none = std.math.maxInt(u32), |
| 724 | _, | 730 | _, |
| 731 | |||
| 725 | pub fn unwrap(opt: Optional) ?TrackedInst.Index { | 732 | pub fn unwrap(opt: Optional) ?TrackedInst.Index { |
| 726 | return switch (opt) { | 733 | return switch (opt) { |
| 727 | .none => null, | 734 | .none => null, |
| ... | @@ -730,6 +737,16 @@ pub const TrackedInst = extern struct { | ... | @@ -730,6 +737,16 @@ pub const TrackedInst = extern struct { |
| 730 | } | 737 | } |
| 731 | }; | 738 | }; |
| 732 | }; | 739 | }; |
| 740 | |||
| 741 | pub fn jsonStringify(i: *const TrackedInst, json_writer: anytype) !void { | ||
| 742 | const jw = core.jsonWriterCast(json_writer); | ||
| 743 | try jw.beginObject(); | ||
| 744 | try jw.objectField("path_digest"); | ||
| 745 | try jw.write(std.fmt.bytesToHex(i.path_digest, .lower)); | ||
| 746 | try jw.objectField("inst"); | ||
| 747 | try jw.write(@intFromEnum(i.inst)); | ||
| 748 | try jw.endObject(); | ||
| 749 | } | ||
| 733 | }; | 750 | }; |
| 734 | 751 | ||
| 735 | pub const DeclIndex = enum(u32) { | 752 | pub const DeclIndex = enum(u32) { |
| ... | @@ -757,7 +774,7 @@ pub const DeclIndex = enum(u32) { | ... | @@ -757,7 +774,7 @@ pub const DeclIndex = enum(u32) { |
| 757 | pub const NamespaceIndex = enum(u32) { | 774 | pub const NamespaceIndex = enum(u32) { |
| 758 | _, | 775 | _, |
| 759 | 776 | ||
| 760 | pub fn toOptional(i: DeclIndex) Optional { | 777 | pub fn toOptional(i: NamespaceIndex) Optional { |
| 761 | return @enumFromInt(@intFromEnum(i)); | 778 | return @enumFromInt(@intFromEnum(i)); |
| 762 | } | 779 | } |
| 763 | 780 | ||
| ... | @@ -1096,11 +1113,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { | ... | @@ -1096,11 +1113,6 @@ pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 1096 | // ip.limbs.deinit(gpa); | 1113 | // ip.limbs.deinit(gpa); |
| 1097 | ip.string_bytes.deinit(gpa); | 1114 | ip.string_bytes.deinit(gpa); |
| 1098 | 1115 | ||
| 1099 | var decls = ip.allocated_decls.iterator(0); | ||
| 1100 | while (decls.next()) |decl| { | ||
| 1101 | decl.deinit(gpa); | ||
| 1102 | } | ||
| 1103 | |||
| 1104 | ip.allocated_decls.deinit(gpa); | 1116 | ip.allocated_decls.deinit(gpa); |
| 1105 | ip.decls_free_list.deinit(gpa); | 1117 | ip.decls_free_list.deinit(gpa); |
| 1106 | 1118 | ||
| ... | @@ -1346,11 +1358,12 @@ fn getOrPutTrailingString( | ... | @@ -1346,11 +1358,12 @@ fn getOrPutTrailingString( |
| 1346 | return @enumFromInt(str_index); | 1358 | return @enumFromInt(str_index); |
| 1347 | }, | 1359 | }, |
| 1348 | } | 1360 | } |
| 1349 | const gop = try ip.string_table.getOrPutContextAdapted(gpa, key, std.hash_map.StringIndexAdapter{ | 1361 | const gop = try ip.string_table.getOrPutContextAdapted( |
| 1350 | .bytes = string_bytes, | 1362 | gpa, |
| 1351 | }, std.hash_map.StringIndexContext{ | 1363 | key, |
| 1352 | .bytes = string_bytes, | 1364 | std.hash_map.StringIndexAdapter{ .bytes = string_bytes }, |
| 1353 | }); | 1365 | std.hash_map.StringIndexContext{ .bytes = string_bytes }, |
| 1366 | ); | ||
| 1354 | if (gop.found_existing) { | 1367 | if (gop.found_existing) { |
| 1355 | string_bytes.shrinkRetainingCapacity(str_index); | 1368 | string_bytes.shrinkRetainingCapacity(str_index); |
| 1356 | return @enumFromInt(gop.key_ptr.*); | 1369 | return @enumFromInt(gop.key_ptr.*); |
| ... | @@ -1445,6 +1458,74 @@ pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: NamespaceIndex) | ... | @@ -1445,6 +1458,74 @@ pub fn destroyNamespace(ip: *InternPool, gpa: Allocator, index: NamespaceIndex) |
| 1445 | }; | 1458 | }; |
| 1446 | } | 1459 | } |
| 1447 | 1460 | ||
| 1461 | pub fn jsonStringify(ip: *const InternPool, json_writer: anytype) !void { | ||
| 1462 | const jw = core.jsonWriterCast(json_writer); | ||
| 1463 | try jw.beginObject(); | ||
| 1464 | { | ||
| 1465 | try jw.objectField("values"); | ||
| 1466 | try jw.beginArray(); | ||
| 1467 | const hashes: []u32 = ip.map.entries.items(.hash); | ||
| 1468 | const values = ip.items.slice(); | ||
| 1469 | for ( | ||
| 1470 | @as([]Tag, values.items(.tag)), | ||
| 1471 | @as([]EncodedData, values.items(.data)), | ||
| 1472 | hashes, | ||
| 1473 | 0.., | ||
| 1474 | ) |tag, encoded_data, hash, i| { | ||
| 1475 | if (tag == .removed) { | ||
| 1476 | try jw.write(null); | ||
| 1477 | continue; | ||
| 1478 | } | ||
| 1479 | try jw.beginObject(); | ||
| 1480 | try jw.objectField("pretty"); | ||
| 1481 | { | ||
| 1482 | var buf: [8192]u8 = undefined; | ||
| 1483 | try jw.print("", .{}); | ||
| 1484 | try jw.stream.print("[{d}, ", .{i}); | ||
| 1485 | try std.json.encodeJsonString(std.fmt.bufPrint( | ||
| 1486 | &buf, | ||
| 1487 | "{}", | ||
| 1488 | .{@as(Value, @enumFromInt(i)).dump(ip)}, | ||
| 1489 | ) catch &buf, .{}, jw.stream); | ||
| 1490 | try jw.stream.print("]", .{}); | ||
| 1491 | } | ||
| 1492 | try jw.objectField("tag"); | ||
| 1493 | try jw.write(@tagName(tag)); | ||
| 1494 | switch (tag) { | ||
| 1495 | .removed => unreachable, | ||
| 1496 | inline else => |comptime_tag| { | ||
| 1497 | const data = encoded_data.decode(comptime_tag, tag); | ||
| 1498 | _ = data; | ||
| 1499 | // try jw.objectField("data"); | ||
| 1500 | // try jw.write(data); | ||
| 1501 | }, | ||
| 1502 | } | ||
| 1503 | try jw.objectField("hash"); | ||
| 1504 | try jw.write(hash); | ||
| 1505 | try jw.endObject(); | ||
| 1506 | } | ||
| 1507 | try jw.endArray(); | ||
| 1508 | } | ||
| 1509 | { | ||
| 1510 | try jw.objectField("string_bytes"); | ||
| 1511 | try jw.write(ip.string_bytes.items); | ||
| 1512 | } | ||
| 1513 | { | ||
| 1514 | try jw.objectField("string_table"); | ||
| 1515 | try jw.beginArray(); | ||
| 1516 | var it = ip.string_table.keyIterator(); | ||
| 1517 | while (it.next()) |k| { | ||
| 1518 | try jw.write(k.*); | ||
| 1519 | } | ||
| 1520 | try jw.endArray(); | ||
| 1521 | } | ||
| 1522 | { | ||
| 1523 | try jw.objectField("tracked_insts"); | ||
| 1524 | try jw.write(ip.tracked_insts.entries.items(.key)); | ||
| 1525 | } | ||
| 1526 | try jw.endObject(); | ||
| 1527 | } | ||
| 1528 | |||
| 1448 | const InternPool = @This(); | 1529 | const InternPool = @This(); |
| 1449 | 1530 | ||
| 1450 | const std = @import("std"); | 1531 | const std = @import("std"); |
src/core/Sema.zig+9-10| ... | @@ -622,7 +622,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { | ... | @@ -622,7 +622,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 622 | const start = s.air_extra.list.items.len; | 622 | const start = s.air_extra.list.items.len; |
| 623 | try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch)); | 623 | try s.air_extra.list.appendSlice(s.gpa, @ptrCast(scratch)); |
| 624 | 624 | ||
| 625 | return s.addInstRef(.new, .{ | 625 | return s.addInstRef(.js_new, .{ |
| 626 | .base = base, | 626 | .base = base, |
| 627 | .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{ .args = .{ | 627 | .call_data = try s.air_extra.append(s.gpa, Air.Call.Data, .{ .args = .{ |
| 628 | .start = @intCast(start), | 628 | .start = @intCast(start), |
| ... | @@ -774,13 +774,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { | ... | @@ -774,13 +774,12 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 774 | 774 | ||
| 775 | // Ensure we have a valid struct to operate on | 775 | // Ensure we have a valid struct to operate on |
| 776 | const ty = try s.resolveType(in.op(.operand), node.base_type); | 776 | const ty = try s.resolveType(in.op(.operand), node.base_type); |
| 777 | const struct_type = ty.toStructType(s.ip) orelse return s.fail( | 777 | const struct_type = ty.toStructType(s.ip) orelse { |
| 778 | .struct_init_invalid_type, | 778 | return s.fail(.struct_init_invalid_type, .{ |
| 779 | .{ | ||
| 780 | .src = in.op(.operand).lazyNode(s.decl_index), | 779 | .src = in.op(.operand).lazyNode(s.decl_index), |
| 781 | .ty = ty, | 780 | .ty = ty, |
| 782 | }, | 781 | }); |
| 783 | ); | 782 | }; |
| 784 | 783 | ||
| 785 | var has_errors = false; | 784 | var has_errors = false; |
| 786 | var is_constant = true; | 785 | var is_constant = true; |
| ... | @@ -957,7 +956,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { | ... | @@ -957,7 +956,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 957 | 956 | ||
| 958 | const operand = try s.resolveValue(result.type); | 957 | const operand = try s.resolveValue(result.type); |
| 959 | const ty = operand.toType(s.ip) orelse | 958 | const ty = operand.toType(s.ip) orelse |
| 960 | return Value.opaque_type; | 959 | return Value.opaque_type.toAir(); |
| 961 | 960 | ||
| 962 | const array_type = ty.toArrayType(s.ip) orelse | 961 | const array_type = ty.toArrayType(s.ip) orelse |
| 963 | return Value.opaque_type.toAir(); | 962 | return Value.opaque_type.toAir(); |
| ... | @@ -966,11 +965,11 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { | ... | @@ -966,11 +965,11 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 966 | }, | 965 | }, |
| 967 | 966 | ||
| 968 | .result_type_tuple_field => { | 967 | .result_type_tuple_field => { |
| 969 | const result: Teg.ResultTypeTupleField = s.code.instData(.result_type_array_value, in); | 968 | const result: Teg.ResultTypeTupleField = s.code.instData(.result_type_tuple_field, in); |
| 970 | 969 | ||
| 971 | const operand = try s.resolveValue(result.type); | 970 | const operand = try s.resolveValue(result.type); |
| 972 | const ty = operand.toType(s.ip) orelse | 971 | const ty = operand.toType(s.ip) orelse |
| 973 | return Value.opaque_type; | 972 | return Value.opaque_type.toAir(); |
| 974 | 973 | ||
| 975 | _ = ty; | 974 | _ = ty; |
| 976 | 975 | ||
| ... | @@ -982,7 +981,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { | ... | @@ -982,7 +981,7 @@ fn analyzeCodeInner(s: *Sema, in: Teg.Inst.Index) Error!Air.Inst.Ref { |
| 982 | 981 | ||
| 983 | const operand = try s.resolveValue(result.type); | 982 | const operand = try s.resolveValue(result.type); |
| 984 | const ty = operand.toType(s.ip) orelse | 983 | const ty = operand.toType(s.ip) orelse |
| 985 | return Value.opaque_type; | 984 | return Value.opaque_type.toAir(); |
| 986 | 985 | ||
| 987 | const struct_type = ty.toStructType(s.ip) orelse | 986 | const struct_type = ty.toStructType(s.ip) orelse |
| 988 | return Value.opaque_type.toAir(); | 987 | return Value.opaque_type.toAir(); |
src/core/array.zig+4| ... | @@ -133,6 +133,10 @@ fn ExtraWrap(comptime kind: StoreKind) type { | ... | @@ -133,6 +133,10 @@ fn ExtraWrap(comptime kind: StoreKind) type { |
| 133 | .{ .index = @intFromEnum(index) + advance }, | 133 | .{ .index = @intFromEnum(index) + advance }, |
| 134 | }; | 134 | }; |
| 135 | } | 135 | } |
| 136 | |||
| 137 | pub fn jsonStringify(index: @This(), jw: anytype) !void { | ||
| 138 | try jw.write(@intFromEnum(index)); | ||
| 139 | } | ||
| 136 | }; | 140 | }; |
| 137 | } | 141 | } |
| 138 | }; | 142 | }; |
src/core/js/Link.zig+2-2| ... | @@ -475,8 +475,8 @@ fn printExprLevel( | ... | @@ -475,8 +475,8 @@ fn printExprLevel( |
| 475 | 475 | ||
| 476 | try writer.writeAll(")"); | 476 | try writer.writeAll(")"); |
| 477 | }, | 477 | }, |
| 478 | .new => { | 478 | .js_new => { |
| 479 | const call: Tree.Call = tree.nodeData(.new, node); | 479 | const call: Tree.Call = tree.nodeData(.js_new, node); |
| 480 | const args = call.args.get(tree); | 480 | const args = call.args.get(tree); |
| 481 | 481 | ||
| 482 | if (Level.new.needsParens(level)) | 482 | if (Level.new.needsParens(level)) |
src/core/js/NodeGen.zig+2-2| ... | @@ -273,7 +273,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void { | ... | @@ -273,7 +273,7 @@ fn codeGenInst(c: *NodeGen, inst: Air.Inst.Index) Error!void { |
| 273 | try c.markExpression(inst, node); | 273 | try c.markExpression(inst, node); |
| 274 | }, | 274 | }, |
| 275 | 275 | ||
| 276 | inline .call, .new => |tag| { | 276 | inline .call, .js_new => |tag| { |
| 277 | const data: Air.Call = c.air.instData(tag, inst); | 277 | const data: Air.Call = c.air.instData(tag, inst); |
| 278 | const call_data = data.call_data.get(c.air); | 278 | const call_data = data.call_data.get(c.air); |
| 279 | 279 | ||
| ... | @@ -653,7 +653,7 @@ fn canLowerToExpression(c: *const NodeGen, inst: Air.Inst.Ref) bool { | ... | @@ -653,7 +653,7 @@ fn canLowerToExpression(c: *const NodeGen, inst: Air.Inst.Ref) bool { |
| 653 | .index => |index| switch (c.air.instTag(index)) { | 653 | .index => |index| switch (c.air.instTag(index)) { |
| 654 | .js_global_ref, | 654 | .js_global_ref, |
| 655 | .call, | 655 | .call, |
| 656 | .new, | 656 | .js_new, |
| 657 | .arg, | 657 | .arg, |
| 658 | .field_opaque, | 658 | .field_opaque, |
| 659 | .field_struct, | 659 | .field_struct, |
src/core/js/Tree.zig+2-2| ... | @@ -41,7 +41,7 @@ pub const Tag = enum { | ... | @@ -41,7 +41,7 @@ pub const Tag = enum { |
| 41 | gt, | 41 | gt, |
| 42 | // Exprs | 42 | // Exprs |
| 43 | call, | 43 | call, |
| 44 | new, | 44 | js_new, |
| 45 | field, | 45 | field, |
| 46 | ternary, | 46 | ternary, |
| 47 | object_literal, | 47 | object_literal, |
| ... | @@ -93,7 +93,7 @@ pub const Tag = enum { | ... | @@ -93,7 +93,7 @@ pub const Tag = enum { |
| 93 | => Un, | 93 | => Un, |
| 94 | .object_literal => ObjectLiteral, | 94 | .object_literal => ObjectLiteral, |
| 95 | .array => IndexList, | 95 | .array => IndexList, |
| 96 | .call, .new => Call, | 96 | .call, .js_new => Call, |
| 97 | .field => Field, | 97 | .field => Field, |
| 98 | .stmt_if => StmtIf, | 98 | .stmt_if => StmtIf, |
| 99 | .stmt_break => StmtBreak, | 99 | .stmt_break => StmtBreak, |
src/core/main.zig+26| ... | @@ -40,6 +40,7 @@ pub fn main() !void { | ... | @@ -40,6 +40,7 @@ pub fn main() !void { |
| 40 | 40 | ||
| 41 | var exe_name: []const u8 = undefined; | 41 | var exe_name: []const u8 = undefined; |
| 42 | var dump_ir = false; | 42 | var dump_ir = false; |
| 43 | var dump_state: ?[]const u8 = null; | ||
| 43 | 44 | ||
| 44 | { | 45 | { |
| 45 | var args = try std.process.argsWithAllocator(alloc); | 46 | var args = try std.process.argsWithAllocator(alloc); |
| ... | @@ -58,6 +59,10 @@ pub fn main() !void { | ... | @@ -58,6 +59,10 @@ pub fn main() !void { |
| 58 | dump_ir = true; | 59 | dump_ir = true; |
| 59 | continue; | 60 | continue; |
| 60 | } | 61 | } |
| 62 | if (std.mem.startsWith(u8, arg, "--dump-state=")) { | ||
| 63 | dump_state = arg["--dump-state=".len..]; | ||
| 64 | continue; | ||
| 65 | } | ||
| 61 | std.debug.print("error: unknown flag '{s}'\n", .{arg}); | 66 | std.debug.print("error: unknown flag '{s}'\n", .{arg}); |
| 62 | maybe_file_path = null; | 67 | maybe_file_path = null; |
| 63 | break; | 68 | break; |
| ... | @@ -107,6 +112,13 @@ pub fn main() !void { | ... | @@ -107,6 +112,13 @@ pub fn main() !void { |
| 107 | }; | 112 | }; |
| 108 | try comp.init(); | 113 | try comp.init(); |
| 109 | defer comp.deinit(); | 114 | defer comp.deinit(); |
| 115 | |||
| 116 | defer if (dump_state) |path| { | ||
| 117 | dumpState(&comp, path) catch |err| { | ||
| 118 | std.debug.print("Failed to dump compilation state: {}", .{err}); | ||
| 119 | }; | ||
| 120 | }; | ||
| 121 | |||
| 110 | const main_file = try comp.getFile(file_path); | 122 | const main_file = try comp.getFile(file_path); |
| 111 | 123 | ||
| 112 | var fail_report: Report = undefined; | 124 | var fail_report: Report = undefined; |
| ... | @@ -141,3 +153,17 @@ pub fn main() !void { | ... | @@ -141,3 +153,17 @@ pub fn main() !void { |
| 141 | 153 | ||
| 142 | std.process.cleanExit(); | 154 | std.process.cleanExit(); |
| 143 | } | 155 | } |
| 156 | |||
| 157 | fn dumpState(comp: *const Comp, dump_path: []const u8) !void { | ||
| 158 | const file = try std.fs.cwd().createFile(dump_path, .{}); | ||
| 159 | defer file.close(); | ||
| 160 | |||
| 161 | var bufw = std.io.bufferedWriter(file.writer()); | ||
| 162 | var jw = std.json.writeStream(bufw.writer(), .{ | ||
| 163 | .whitespace = .indent_2, | ||
| 164 | }); | ||
| 165 | |||
| 166 | try comp.jsonStringify(&jw); | ||
| 167 | try bufw.writer().writeAll("\n"); | ||
| 168 | try bufw.flush(); | ||
| 169 | } |
src/core/mod.zig+13| ... | @@ -101,6 +101,19 @@ pub fn detectTTYFromWriter(writer: std.io.AnyWriter) std.io.tty.Config { | ... | @@ -101,6 +101,19 @@ pub fn detectTTYFromWriter(writer: std.io.AnyWriter) std.io.tty.Config { |
| 101 | return .no_color; | 101 | return .no_color; |
| 102 | } | 102 | } |
| 103 | 103 | ||
| 104 | /// This function is entirely because ZLS cannot infer `anytype` -> `std.json.WriteStream` | ||
| 105 | /// It should be removed once ZLS or the Zig language fixes this. | ||
| 106 | pub fn jsonWriterCast(json_writer: anytype) *std.json.WriteStream( | ||
| 107 | @TypeOf(json_writer.*).Stream, | ||
| 108 | switch (@TypeOf(json_writer.nesting_stack)) { | ||
| 109 | void => .assumed_correct, | ||
| 110 | std.BitStack => .checked_to_arbitrary_depth, | ||
| 111 | else => .{ .checked_to_fixed_depth = 256 }, | ||
| 112 | }, | ||
| 113 | ) { | ||
| 114 | return json_writer; | ||
| 115 | } | ||
| 116 | |||
| 104 | const std = @import("std"); | 117 | const std = @import("std"); |
| 105 | const assert = std.debug.assert; | 118 | const assert = std.debug.assert; |
| 106 | 119 |