22 files changed, 1761 insertions(+), 1753 deletions(-)
README.md+3-2| ... | ... | @@ -1,7 +1,8 @@ |
| 1 | 1 | # Ix |
| 2 | 2 | |
| 3 | Ix (**I**nferable E**x**pression) is a high-level, general purpose programming | |
| 4 | language. It features a mix of Rust, Zig, and JavaScript's great points. | |
| 3 | Ix (***I***nferable E***x***pression) is a high-level, general purpose | |
| 4 | programming language. It features a mix of Rust, Zig, and JavaScript's great | |
| 5 | points. | |
| 5 | 6 | |
| 6 | 7 | For a guide on how to use Ix, see the manual included in the binary |
| 7 | 8 | distribution. Additionally, the latest commit of the manual is hosted online at |
doc/architecture.md+7-7| ... | ... | @@ -34,13 +34,13 @@ compiler tests into these categories: |
| 34 | 34 | runtime, testing both the semantic analysis pass as well as the code |
| 35 | 35 | generation backend. |
| 36 | 36 | - **Transform Error Tests** (`test/transform_error`) confirm that the transform |
| 37 | pass errors are correct. A passing `Teg` fails the test. | |
| 37 | pass errors are correct. A passing `Hir` fails the test. | |
| 38 | 38 | |
| 39 | All compiler tests can be run with `zig build test`, or the test suite can be | |
| 40 | filtered using flags, see `zig build test --help` | |
| 39 | All compiler tests can be run with `./build test`, or the test suite can be | |
| 40 | filtered using flags, see `./build test -- --help` | |
| 41 | 41 | |
| 42 | To run Zig tests for an associated module, use `zig build test-{name}`, or run | |
| 43 | `zig build test-all` to run all tests in the codebase. | |
| 42 | To run Zig tests for an associated module, use `./build test-{name}`, or run | |
| 43 | `./build test-all` to run all tests in the codebase. | |
| 44 | 44 | |
| 45 | 45 | ## Core |
| 46 | 46 | |
| ... | ... | @@ -48,7 +48,7 @@ The `core` module contains most of the compiler: |
| 48 | 48 | |
| 49 | 49 | - Tokenizing and Parsing files. (`Tokenizer.zig`, `Parse.zig`, `Ast.zig`) |
| 50 | 50 | - Transform Pass, moving from Ast to an untyped intermediate representation |
| 51 | (`Transform.zig`) | |
| 51 | (`Transform.zig`, `Hir.zig`) | |
| 52 | 52 | - Semantic Analysis, resolving all types and comptime values. (`Sema.zig`) |
| 53 | 53 | - Intern Pool, storing and de-duplicating objects in a compilation. |
| 54 | 54 | (`InternPool.zig`) |
| ... | ... | @@ -56,7 +56,7 @@ The `core` module contains most of the compiler: |
| 56 | 56 | |
| 57 | 57 | Note that components like the formatter and module fetching code are not here. |
| 58 | 58 | Keeping this module as small as possible is important for keeping compile times |
| 59 | low. Using `zig build compiler -- --help` instead of the fully featured binary | |
| 59 | low. Using `./build compiler -- --help` instead of the fully featured binary | |
| 60 | 60 | will allow for faster and more focused iteration. |
| 61 | 61 | |
| 62 | 62 | ## Manual |
doc/language-manual.md+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | # Ix Programming Language |
| 2 | 2 | |
| 3 | Ix (**I**nferable E**x**pression) is a high-level programming language for | |
| 3 | Ix (***I***nferable E***x***pression) is a high-level programming language for | |
| 4 | 4 | developing web applications and games. |
| 5 | 5 | |
| 6 | 6 | Key goals of this project are: |
src/cli_compiler.zig+2-2| ... | ... | @@ -81,7 +81,7 @@ pub fn main() !u8 { |
| 81 | 81 | const main_file = try comp.getFile(file_path); |
| 82 | 82 | |
| 83 | 83 | var fail_report: Report = undefined; |
| 84 | const teg = main_file.getTeg(&comp, &fail_report) catch |err| switch (err) { | |
| 84 | const hir = main_file.getHir(&comp, &fail_report) catch |err| switch (err) { | |
| 85 | 85 | error.TransformFail => { |
| 86 | 86 | std.debug.print("Transform failed:\n", .{}); |
| 87 | 87 | try fail_report.dump(.initComp(&comp, main_file), comp.out); |
| ... | ... | @@ -97,7 +97,7 @@ pub fn main() !u8 { |
| 97 | 97 | |
| 98 | 98 | if (comp.options.dump_ir) { |
| 99 | 99 | const stderr = std.io.getStdErr().writer(); |
| 100 | try teg.dumpToWriter(stderr, null); | |
| 100 | try hir.dumpToWriter(stderr, null); | |
| 101 | 101 | } |
| 102 | 102 | |
| 103 | 103 | const entry_point = try comp.enqueueEntryModule(main_file); |
src/cli_transform.zig+5-5| ... | ... | @@ -66,7 +66,7 @@ pub fn main() !u8 { |
| 66 | 66 | } |
| 67 | 67 | |
| 68 | 68 | var teg_report: core.Report = undefined; |
| 69 | var teg = core.Transform.transform(ast, alloc, &teg_report) catch |err| switch (err) { | |
| 69 | var hir = core.Transform.transform(ast, alloc, &teg_report) catch |err| switch (err) { | |
| 70 | 70 | error.OutOfMemory => return err, |
| 71 | 71 | error.TransformFail => { |
| 72 | 72 | defer teg_report.deinit(alloc); |
| ... | ... | @@ -81,13 +81,13 @@ pub fn main() !u8 { |
| 81 | 81 | return 1; |
| 82 | 82 | }, |
| 83 | 83 | }; |
| 84 | defer teg.deinit(alloc); | |
| 84 | defer hir.deinit(alloc); | |
| 85 | 85 | |
| 86 | // const file = try std.fs.cwd().createFile("serialized.teg", .{}); | |
| 86 | // const file = try std.fs.cwd().createFile("serialized.hir", .{}); | |
| 87 | 87 | // defer file.close(); |
| 88 | // try teg.serialize(.{ .file = file }); | |
| 88 | // try hir.serialize(.{ .file = file }); | |
| 89 | 89 | |
| 90 | try teg.dumpToWriter(out.writer, out.tty); | |
| 90 | try hir.dumpToWriter(out.writer, out.tty); | |
| 91 | 91 | |
| 92 | 92 | return 0; |
| 93 | 93 | } |
src/core/Air.Dump.zig+1-1| ... | ... | @@ -1,4 +1,4 @@ |
| 1 | //! This implements a debug formatter for Teg | |
| 1 | //! This implements a debug formatter for Air | |
| 2 | 2 | air: Air, |
| 3 | 3 | ip: *const InternPool, |
| 4 | 4 | tty: std.io.tty.Config, |
src/core/Ast.zig+1-1| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | 1 | //! The Abstract Syntax Tree preserves most details of the source code, |
| 2 | 2 | //! as it is used for formatting. Before semantic analysis, this |
| 3 | //! structure is normalized into `Teg`, which removes constructs like | |
| 3 | //! structure is normalized into `Hir`, which removes constructs like | |
| 4 | 4 | //! whitespace, unneeded let bindings, and other transforms. |
| 5 | 5 | //! |
| 6 | 6 | //! `ast.nodes` contains nodes stored as three parts: |
src/core/Comp.zig+30-30| ... | ... | @@ -110,14 +110,14 @@ const Job = union(enum) { |
| 110 | 110 | |
| 111 | 111 | pub fn enqueueEntryModule(comp: *Comp, file: *File) !Decl.Index { |
| 112 | 112 | var report: Report = undefined; |
| 113 | const teg = try file.getTeg(comp, &report); | |
| 113 | const hir = try file.getHir(comp, &report); | |
| 114 | 114 | |
| 115 | 115 | // TODO, move this elsewhere. we should print all errors and warnings at once |
| 116 | if (teg.report.warnings.len > 0) { | |
| 117 | try teg.report.dump(.initComp(comp, file), comp.out); | |
| 116 | if (hir.report.warnings.len > 0) { | |
| 117 | try hir.report.dump(.initComp(comp, file), comp.out); | |
| 118 | 118 | } |
| 119 | 119 | |
| 120 | const ns = try comp.indexTegModule(file, .main_module_inst); | |
| 120 | const ns = try comp.indexHirModule(file, .main_module_inst); | |
| 121 | 121 | const main_str = try comp.intern_pool.getOrPutString(comp.gpa, "main", .no_embedded_nulls); |
| 122 | 122 | const decl_index = comp.intern_pool.namespacePtr(ns).lookupDirect(comp, main_str) orelse { |
| 123 | 123 | // TODO: add a helper function into Report to render a single error |
| ... | ... | @@ -168,12 +168,12 @@ fn runAnalysisJob(comp: *Comp, unit: InternPool.AnalysisUnit, first_blocked_sema |
| 168 | 168 | }; |
| 169 | 169 | const decl = comp.intern_pool.declPtr(decl_index); |
| 170 | 170 | const file = comp.intern_pool.namespacePtr(decl.src_namespace).file_scope; |
| 171 | const teg = file.teg orelse @panic("TODO: make sure teg is loaded to avoid annoying error set?"); | |
| 171 | const hir = file.hir orelse @panic("TODO: make sure hir is loaded to avoid annoying error set?"); | |
| 172 | 172 | |
| 173 | 173 | try sema.init( |
| 174 | 174 | comp, |
| 175 | 175 | file, |
| 176 | teg, | |
| 176 | hir, | |
| 177 | 177 | unit, |
| 178 | 178 | decl.src_namespace, |
| 179 | 179 | std.heap.ArenaAllocator.init(comp.gpa), |
| ... | ... | @@ -266,7 +266,7 @@ pub fn getFile(comp: *Comp, absolute_file_path: []const u8) !*File { |
| 266 | 266 | .root_namespace = .none, |
| 267 | 267 | .source = null, |
| 268 | 268 | .ast = null, |
| 269 | .teg = null, | |
| 269 | .hir = null, | |
| 270 | 270 | }; |
| 271 | 271 | gop.value_ptr.* = file; |
| 272 | 272 | return file; |
| ... | ... | @@ -277,7 +277,7 @@ pub const Source = struct { |
| 277 | 277 | stat: Stat, |
| 278 | 278 | }; |
| 279 | 279 | |
| 280 | /// A file in the compilation and it's associated data structures. Ast and Teg | |
| 280 | /// A file in the compilation and it's associated data structures. Ast and Hir | |
| 281 | 281 | /// are not guaranteed to be loaded, even if it's `status` says `success`. |
| 282 | 282 | pub const File = struct { |
| 283 | 283 | /// TODO: change this to a URL |
| ... | ... | @@ -287,7 +287,7 @@ pub const File = struct { |
| 287 | 287 | |
| 288 | 288 | source: ?Source, |
| 289 | 289 | ast: ?Ast, |
| 290 | teg: ?Teg, | |
| 290 | hir: ?Hir, | |
| 291 | 291 | |
| 292 | 292 | path_digest: ?Cache.BinDigest, |
| 293 | 293 | |
| ... | ... | @@ -323,7 +323,7 @@ pub const File = struct { |
| 323 | 323 | |
| 324 | 324 | // Here we do not modify stat fields because this function is the one |
| 325 | 325 | // used for error reporting. We need to keep the stat fields stale so that |
| 326 | // transformFile can know to regenerate Teg. | |
| 326 | // transformFile can know to regenerate Hir. | |
| 327 | 327 | |
| 328 | 328 | const loaded_source: Source = .{ |
| 329 | 329 | .code = source, |
| ... | ... | @@ -370,11 +370,11 @@ pub const File = struct { |
| 370 | 370 | return &(file.ast.?); |
| 371 | 371 | } |
| 372 | 372 | |
| 373 | pub const GetTegError = GetAstError || Transform.Error; | |
| 373 | pub const GetHirError = GetAstError || Transform.Error; | |
| 374 | 374 | |
| 375 | pub fn getTeg(file: *File, comp: *Comp, fail_report: *Report) GetTegError!Teg { | |
| 376 | if (file.teg) |teg| { | |
| 377 | return teg; | |
| 375 | pub fn getHir(file: *File, comp: *Comp, fail_report: *Report) GetHirError!Hir { | |
| 376 | if (file.hir) |hir| { | |
| 377 | return hir; | |
| 378 | 378 | } |
| 379 | 379 | |
| 380 | 380 | const bin_digest = hash: { |
| ... | ... | @@ -387,10 +387,10 @@ pub const File = struct { |
| 387 | 387 | }; |
| 388 | 388 | file.path_digest = bin_digest; |
| 389 | 389 | |
| 390 | const teg = try Transform.transform((try file.getAst(comp)).*, comp.gpa, fail_report); | |
| 390 | const hir = try Transform.transform((try file.getAst(comp)).*, comp.gpa, fail_report); | |
| 391 | 391 | |
| 392 | file.teg = teg; | |
| 393 | return teg; | |
| 392 | file.hir = hir; | |
| 393 | return hir; | |
| 394 | 394 | } |
| 395 | 395 | |
| 396 | 396 | pub fn unloadSource(file: *File, gpa: Allocator) void { |
| ... | ... | @@ -407,15 +407,15 @@ pub const File = struct { |
| 407 | 407 | } |
| 408 | 408 | } |
| 409 | 409 | |
| 410 | pub fn unloadTeg(file: *File, gpa: Allocator) void { | |
| 411 | if (file.teg) |*teg| { | |
| 412 | teg.deinit(gpa); | |
| 413 | file.teg = null; | |
| 410 | pub fn unloadHir(file: *File, gpa: Allocator) void { | |
| 411 | if (file.hir) |*hir| { | |
| 412 | hir.deinit(gpa); | |
| 413 | file.hir = null; | |
| 414 | 414 | } |
| 415 | 415 | } |
| 416 | 416 | |
| 417 | 417 | pub fn deinit(file: *File, gpa: Allocator) void { |
| 418 | file.unloadTeg(gpa); | |
| 418 | file.unloadHir(gpa); | |
| 419 | 419 | file.unloadAst(gpa); |
| 420 | 420 | file.unloadSource(gpa); |
| 421 | 421 | gpa.destroy(file); |
| ... | ... | @@ -476,7 +476,7 @@ pub const Decl = struct { |
| 476 | 476 | // /// This value is absolute. |
| 477 | 477 | // src_line: u32, |
| 478 | 478 | |
| 479 | /// Index of the Teg `declaration` instruction from which this `Decl` was created. | |
| 479 | /// Index of the Hir `declaration` instruction from which this `Decl` was created. | |
| 480 | 480 | teg_decl_index: InternPool.TrackedInst.Index, |
| 481 | 481 | |
| 482 | 482 | /// Represents the "shallow" analysis status. For example, for decls that are functions, |
| ... | ... | @@ -620,10 +620,10 @@ pub const Namespace = struct { |
| 620 | 620 | pub const Index = InternPool.NamespaceIndex; |
| 621 | 621 | }; |
| 622 | 622 | |
| 623 | /// Index a Teg's module scope as a namespace. This prepares `Decl` objects for | |
| 623 | /// Index a Hir's module scope as a namespace. This prepares `Decl` objects for | |
| 624 | 624 | /// every declaration, but does not begin analysis of them. |
| 625 | pub fn indexTegModule(comp: *Comp, file: *File, module_index: Teg.Inst.Index) !Namespace.Index { | |
| 626 | const teg = file.teg.?; | |
| 625 | pub fn indexHirModule(comp: *Comp, file: *File, module_index: Hir.Inst.Index) !Namespace.Index { | |
| 626 | const hir = file.hir.?; | |
| 627 | 627 | |
| 628 | 628 | assert(file.root_namespace == .none); |
| 629 | 629 | |
| ... | ... | @@ -635,12 +635,12 @@ pub fn indexTegModule(comp: *Comp, file: *File, module_index: Teg.Inst.Index) !N |
| 635 | 635 | const ns_ptr = comp.intern_pool.namespacePtr(ns); |
| 636 | 636 | errdefer comp.intern_pool.destroyNamespace(comp.gpa, ns); |
| 637 | 637 | |
| 638 | for (teg.moduleDeclarations(module_index)) |decl_index| { | |
| 639 | switch (teg.instTag(decl_index)) { | |
| 638 | for (hir.moduleDeclarations(module_index)) |decl_index| { | |
| 639 | switch (hir.instTag(decl_index)) { | |
| 640 | 640 | .declaration => { |
| 641 | 641 | const name = try comp.intern_pool.getOrPutString( |
| 642 | 642 | comp.gpa, |
| 643 | teg.declName(decl_index), | |
| 643 | hir.declName(decl_index), | |
| 644 | 644 | .no_embedded_nulls, |
| 645 | 645 | ); |
| 646 | 646 | const tracked_inst = try comp.intern_pool.trackInst(comp.gpa, file, decl_index); |
| ... | ... | @@ -736,7 +736,7 @@ const InternPool = core.InternPool; |
| 736 | 736 | |
| 737 | 737 | const Ast = core.Ast; |
| 738 | 738 | const Air = core.Air; |
| 739 | const Teg = core.Teg; | |
| 739 | const Hir = core.Hir; | |
| 740 | 740 | const Cache = core.Cache; |
| 741 | 741 | const Sema = core.Sema; |
| 742 | 742 | const Transform = core.Transform; |
src/core/Hir.Dump.zig created+522| ... | ... | @@ -0,0 +1,522 @@ |
| 1 | //! This implements a debug formatter for Hir | |
| 2 | hir: Hir, | |
| 3 | tty: ?std.io.tty.Config = null, | |
| 4 | ||
| 5 | const State = struct { | |
| 6 | arena: std.mem.Allocator, | |
| 7 | hir: *const Hir, | |
| 8 | indent: usize = 0, | |
| 9 | tty: std.io.tty.Config, | |
| 10 | visited: std.AutoHashMapUnmanaged(Hir.Inst.Index, void) = .{}, | |
| 11 | ||
| 12 | fn newline(state: State, writer: anytype) !void { | |
| 13 | try writer.writeByte('\n'); | |
| 14 | if (state.indent > 0) | |
| 15 | try writer.writeByteNTimes(' ', state.indent * 2); | |
| 16 | } | |
| 17 | ||
| 18 | fn dumpInst(s: *State, writer: anytype, inst: Hir.Inst.Index) @TypeOf(writer).Error!void { | |
| 19 | const hir = s.hir; | |
| 20 | const tty = s.tty; | |
| 21 | ||
| 22 | try writer.print("%{} = ", .{@intFromEnum(inst)}); | |
| 23 | ||
| 24 | const tag = s.hir.instTag(inst); | |
| 25 | ||
| 26 | try tty.setColor(writer, .bright_black); | |
| 27 | const node_offset = hir.instNodeOffset(inst); | |
| 28 | try writer.print("{c}{d} ", .{ | |
| 29 | @as(u8, if (node_offset >= 0) '+' else '-'), | |
| 30 | @abs(node_offset), | |
| 31 | }); | |
| 32 | try tty.setColor(writer, .reset); | |
| 33 | ||
| 34 | try tty.setColor(writer, .cyan); | |
| 35 | try writer.print("{s}", .{@tagName(tag)}); | |
| 36 | try tty.setColor(writer, .reset); | |
| 37 | ||
| 38 | if ((try s.visited.fetchPut(s.arena, inst, {})) != null) { | |
| 39 | try tty.setColor(writer, .red); | |
| 40 | try writer.writeAll(" [error: recursive tree]"); | |
| 41 | try tty.setColor(writer, .reset); | |
| 42 | return; | |
| 43 | } | |
| 44 | ||
| 45 | switch (tag) { | |
| 46 | .module => { | |
| 47 | try s.dumpInstList(writer, hir.moduleDeclarations(inst), '{', '}'); | |
| 48 | }, | |
| 49 | .declaration, .variable_declaration, .test_declaration => { | |
| 50 | const decl = hir.fullDecl(inst); | |
| 51 | ||
| 52 | try writer.writeAll(" "); | |
| 53 | const name = decl.name.slice(hir.string_bytes); | |
| 54 | if (name.len == 0) { | |
| 55 | try tty.setColor(writer, .bold); | |
| 56 | try writer.writeAll("[no name]"); | |
| 57 | } else { | |
| 58 | try tty.setColor(writer, .magenta); | |
| 59 | try writer.writeAll(name); | |
| 60 | } | |
| 61 | try tty.setColor(writer, .reset); | |
| 62 | try writer.writeAll(" ("); | |
| 63 | try writer.print("{d}", .{decl.instruction_count}); | |
| 64 | try writer.writeAll(")"); | |
| 65 | try tty.setColor(writer, .bright_black); | |
| 66 | try writer.writeAll(" ["); | |
| 67 | try writer.writeAll(&std.fmt.bytesToHex(decl.hash, .lower)); | |
| 68 | try writer.writeAll("]"); | |
| 69 | try tty.setColor(writer, .reset); | |
| 70 | try writer.writeAll(" ("); | |
| 71 | s.indent += 1; | |
| 72 | try s.newline(writer); | |
| 73 | try s.dumpRef(writer, decl.body); | |
| 74 | s.indent -= 1; | |
| 75 | try s.newline(writer); | |
| 76 | try writer.writeAll(")"); | |
| 77 | }, | |
| 78 | .func => { | |
| 79 | const func: Hir.Func = hir.instPayload(.func, inst); | |
| 80 | try writer.writeAll(" {"); | |
| 81 | s.indent += 1; | |
| 82 | try s.newline(writer); | |
| 83 | try writer.writeAll("params: "); | |
| 84 | try s.dumpOptionalRefList(writer, func.params.slice(hir), '[', ']'); | |
| 85 | try s.newline(writer); | |
| 86 | try writer.writeAll("return_type: "); | |
| 87 | if (func.return_type.unwrap()) |ret| | |
| 88 | try s.dumpRef(writer, ret) | |
| 89 | else { | |
| 90 | try tty.setColor(writer, .bright_black); | |
| 91 | try writer.writeAll("<inferred>"); | |
| 92 | try tty.setColor(writer, .reset); | |
| 93 | } | |
| 94 | try s.newline(writer); | |
| 95 | try writer.writeAll("captures: "); | |
| 96 | try s.dumpInstList2(writer, func.captures.slice(hir), '[', ']'); | |
| 97 | try s.newline(writer); | |
| 98 | try writer.writeAll("body: "); | |
| 99 | try s.dumpInst(writer, func.body); | |
| 100 | s.indent -= 1; | |
| 101 | try s.newline(writer); | |
| 102 | try writer.writeAll("}"); | |
| 103 | }, | |
| 104 | .param => { | |
| 105 | const data = hir.instData(.param, inst); | |
| 106 | try writer.writeAll("("); | |
| 107 | if (data.data == std.math.maxInt(u32)) { | |
| 108 | try tty.setColor(writer, .bright_black); | |
| 109 | try writer.writeAll("<return type>"); | |
| 110 | } else { | |
| 111 | try tty.setColor(writer, .yellow); | |
| 112 | try writer.print("{d}", .{data.data}); | |
| 113 | } | |
| 114 | try tty.setColor(writer, .reset); | |
| 115 | try writer.writeAll(")"); | |
| 116 | }, | |
| 117 | inline .block, .@"comptime" => |t| { | |
| 118 | const block = hir.instData(t, inst); | |
| 119 | const index_list = block.extra_index.get(hir); | |
| 120 | try s.dumpInstList(writer, index_list.slice(hir), '[', ']'); | |
| 121 | }, | |
| 122 | .number => { | |
| 123 | const number = hir.instData(.number, inst); | |
| 124 | const float = number.extra_index.get(hir).decode(); | |
| 125 | try tty.setColor(writer, .yellow); | |
| 126 | try writer.print(" {d}", .{float}); | |
| 127 | try tty.setColor(writer, .reset); | |
| 128 | }, | |
| 129 | inline .field, | |
| 130 | .index, | |
| 131 | .add, | |
| 132 | .sub, | |
| 133 | .mul, | |
| 134 | .div, | |
| 135 | .rem, | |
| 136 | .pow, | |
| 137 | .@"and", | |
| 138 | .@"or", | |
| 139 | .bit_and, | |
| 140 | .bit_or, | |
| 141 | .bit_xor, | |
| 142 | .shl, | |
| 143 | .shr, | |
| 144 | .eq, | |
| 145 | .ne, | |
| 146 | .lt, | |
| 147 | .le, | |
| 148 | .gt, | |
| 149 | .ge, | |
| 150 | => |comptime_tag| { | |
| 151 | const data = hir.instData(comptime_tag, inst).extra_index.get(hir); | |
| 152 | try writer.writeAll("("); | |
| 153 | try s.dumpRefMarker(writer, data.lhs); | |
| 154 | try writer.writeAll(", "); | |
| 155 | try s.dumpRefMarker(writer, data.rhs); | |
| 156 | try writer.writeAll(")"); | |
| 157 | }, | |
| 158 | .coercion => { | |
| 159 | const data = hir.instData(.coercion, inst).extra_index.get(hir); | |
| 160 | try writer.writeAll("("); | |
| 161 | try s.dumpRefMarker(writer, data.type); | |
| 162 | try writer.writeAll(", "); | |
| 163 | try s.dumpRefMarker(writer, data.operand); | |
| 164 | try writer.writeAll(")"); | |
| 165 | }, | |
| 166 | .@"break" => { | |
| 167 | const data: Hir.Break = hir.instData(.@"break", inst).extra_index.get(hir); | |
| 168 | try writer.writeAll("("); | |
| 169 | try s.dumpRefMarker(writer, data.block.toRef()); | |
| 170 | try writer.writeAll(", "); | |
| 171 | try s.dumpRefMarker(writer, data.operand); | |
| 172 | try writer.writeAll(")"); | |
| 173 | }, | |
| 174 | .store => { | |
| 175 | const data: Hir.Store = hir.instData(.store, inst).extra_index.get(hir); | |
| 176 | try writer.writeAll("("); | |
| 177 | try s.dumpRefMarker(writer, data.memory.toRef()); | |
| 178 | try writer.writeAll(", "); | |
| 179 | try s.dumpRefMarker(writer, data.operand); | |
| 180 | try writer.writeAll(")"); | |
| 181 | }, | |
| 182 | .store_field => { | |
| 183 | const data: Hir.StoreField = hir.instData(.store_field, inst).extra_index.get(hir); | |
| 184 | try writer.writeAll("("); | |
| 185 | try s.dumpRefMarker(writer, data.base); | |
| 186 | try writer.writeAll(", "); | |
| 187 | try s.dumpRefMarker(writer, data.field); | |
| 188 | try writer.writeAll(", "); | |
| 189 | try s.dumpRefMarker(writer, data.operand); | |
| 190 | try writer.writeAll(")"); | |
| 191 | }, | |
| 192 | .store_decl => { | |
| 193 | const data: Hir.StoreVarDecl = hir.instData(.store_decl, inst).extra_index.get(hir); | |
| 194 | try writer.writeAll("("); | |
| 195 | try tty.setColor(writer, .magenta); | |
| 196 | try writer.writeAll(data.var_decl.slice(hir.string_bytes)); | |
| 197 | try tty.setColor(writer, .reset); | |
| 198 | try writer.writeAll(", "); | |
| 199 | try s.dumpRefMarker(writer, data.operand); | |
| 200 | try writer.writeAll(")"); | |
| 201 | }, | |
| 202 | .string => { | |
| 203 | const data: Hir.SlicedString = hir.instData(.string, inst).extra_index.get(hir); | |
| 204 | try tty.setColor(writer, .green); | |
| 205 | try writer.writeAll(" \""); | |
| 206 | try writer.writeAll(data.slice(hir.string_bytes)); | |
| 207 | try writer.writeAll("\""); | |
| 208 | try tty.setColor(writer, .reset); | |
| 209 | }, | |
| 210 | inline .memory, | |
| 211 | .discard, | |
| 212 | .ensure_void, | |
| 213 | .negate, | |
| 214 | .bool_not, | |
| 215 | .bit_not, | |
| 216 | .@"extern", | |
| 217 | .import, | |
| 218 | .fetch, | |
| 219 | .compile_error, | |
| 220 | .type_of, | |
| 221 | .array_type, | |
| 222 | .assert, | |
| 223 | => |comptime_tag| { | |
| 224 | const data = hir.instData(comptime_tag, inst); | |
| 225 | try writer.writeAll("("); | |
| 226 | try s.dumpRefMarker(writer, data.operand); | |
| 227 | try writer.writeAll(")"); | |
| 228 | }, | |
| 229 | .call => { | |
| 230 | const call: Hir.Call = hir.instData(.call, inst).extra_index.get(hir); | |
| 231 | try writer.writeAll("("); | |
| 232 | try s.dumpRefMarker(writer, call.base); | |
| 233 | try writer.writeAll(", "); | |
| 234 | try s.dumpRefMarkerList(writer, call.args.slice(hir), '[', ']'); | |
| 235 | try writer.writeAll(")"); | |
| 236 | }, | |
| 237 | .js_new => { | |
| 238 | const call: Hir.JsNew = hir.instData(.js_new, inst).extra_index.get(hir); | |
| 239 | try writer.writeAll("("); | |
| 240 | try s.dumpRefMarker(writer, call.base); | |
| 241 | try writer.writeAll(", "); | |
| 242 | try s.dumpRefMarkerList(writer, call.args.slice(hir), '[', ']'); | |
| 243 | try writer.writeAll(")"); | |
| 244 | }, | |
| 245 | .load_decl => { | |
| 246 | const call: Hir.StrNode = hir.instData(.load_decl, inst); | |
| 247 | ||
| 248 | try tty.setColor(writer, .red); | |
| 249 | try writer.print(" {s}", .{call.string.slice(hir.string_bytes)}); | |
| 250 | try tty.setColor(writer, .reset); | |
| 251 | }, | |
| 252 | .@"if" => { | |
| 253 | const data: Hir.If = hir.instPayload(.@"if", inst); | |
| 254 | try writer.writeAll("("); | |
| 255 | try s.dumpRefMarker(writer, data.cond); | |
| 256 | try writer.writeAll(") {"); | |
| 257 | s.indent += 1; | |
| 258 | try s.newline(writer); | |
| 259 | try writer.writeAll("yes: "); | |
| 260 | try s.dumpRef(writer, data.yes); | |
| 261 | try s.newline(writer); | |
| 262 | try writer.writeAll("no: "); | |
| 263 | try s.dumpRef(writer, data.no); | |
| 264 | s.indent -= 1; | |
| 265 | try s.newline(writer); | |
| 266 | try writer.writeAll("}"); | |
| 267 | }, | |
| 268 | .struct_decl => { | |
| 269 | const data: Hir.StructDecl = hir.instPayload(.struct_decl, inst); | |
| 270 | try writer.writeAll(" {"); | |
| 271 | s.indent += 1; | |
| 272 | try s.newline(writer); | |
| 273 | for (data.keys(hir), data.types(hir), 0..) |key, value, i| { | |
| 274 | if (i != 0) | |
| 275 | try s.newline(writer); | |
| 276 | try writer.print("{s}: ", .{key.slice(hir.string_bytes)}); | |
| 277 | try s.dumpRefMarker(writer, value); | |
| 278 | } | |
| 279 | s.indent -= 1; | |
| 280 | try s.newline(writer); | |
| 281 | try writer.writeAll("}"); | |
| 282 | }, | |
| 283 | .struct_init => { | |
| 284 | const data: Hir.StructInit = hir.instPayload(.struct_init, inst); | |
| 285 | try writer.writeAll("("); | |
| 286 | try s.dumpRefMarker(writer, data.base_type); | |
| 287 | try writer.writeAll(") {"); | |
| 288 | s.indent += 1; | |
| 289 | try s.newline(writer); | |
| 290 | for (data.keys(hir), data.inits(hir), 0..) |key, value, i| { | |
| 291 | if (i != 0) | |
| 292 | try s.newline(writer); | |
| 293 | try writer.print("{s}: ", .{key.slice(hir.string_bytes)}); | |
| 294 | try s.dumpRefMarker(writer, value); | |
| 295 | } | |
| 296 | s.indent -= 1; | |
| 297 | try s.newline(writer); | |
| 298 | try writer.writeAll("}"); | |
| 299 | }, | |
| 300 | .array_init => { | |
| 301 | const data: Hir.ArrayInit = hir.instPayload(.array_init, inst); | |
| 302 | ||
| 303 | if (data.type_hint.unwrap()) |type_hint| { | |
| 304 | try writer.writeAll("("); | |
| 305 | try s.dumpRef(writer, type_hint); | |
| 306 | try writer.writeAll(", "); | |
| 307 | } | |
| 308 | ||
| 309 | try writer.writeAll("["); | |
| 310 | ||
| 311 | s.indent += 1; | |
| 312 | ||
| 313 | for (data.list.slice(hir)) |item| { | |
| 314 | try s.newline(writer); | |
| 315 | try s.dumpRefMarker(writer, item); | |
| 316 | try writer.writeAll(","); | |
| 317 | } | |
| 318 | ||
| 319 | s.indent -= 1; | |
| 320 | try s.newline(writer); | |
| 321 | ||
| 322 | try writer.writeAll("]"); | |
| 323 | ||
| 324 | if (data.type_hint != .none) | |
| 325 | try writer.writeAll(")"); | |
| 326 | }, | |
| 327 | .tuple_type => { | |
| 328 | const data: Hir.TupleType = hir.instPayload(.tuple_type, inst); | |
| 329 | ||
| 330 | try writer.writeAll("("); | |
| 331 | try s.dumpRefMarkerList(writer, data.items.slice(hir), '[', ']'); | |
| 332 | try writer.writeAll(")"); | |
| 333 | }, | |
| 334 | .tuple_init => { | |
| 335 | const data: Hir.TupleInit = hir.instPayload(.tuple_init, inst); | |
| 336 | ||
| 337 | try writer.writeAll("("); | |
| 338 | if (data.type_hint.unwrap()) |type_hint| { | |
| 339 | try s.dumpRef(writer, type_hint); | |
| 340 | try writer.writeAll(", "); | |
| 341 | } | |
| 342 | try s.dumpRefMarkerList(writer, data.items.slice(hir), '[', ']'); | |
| 343 | try writer.writeAll(")"); | |
| 344 | }, | |
| 345 | .result_type_argument => { | |
| 346 | const data: Hir.ResultTypeArgument = hir.instData(.result_type_argument, inst); | |
| 347 | ||
| 348 | try writer.writeAll("("); | |
| 349 | try s.dumpRefMarker(writer, data.call_base); | |
| 350 | try writer.print(", {d}", .{data.argument}); | |
| 351 | try writer.writeAll(")"); | |
| 352 | }, | |
| 353 | .result_type_struct_field => { | |
| 354 | const data: Hir.ResultTypeStructField = hir.instData(.result_type_struct_field, inst); | |
| 355 | ||
| 356 | try writer.writeAll("("); | |
| 357 | try s.dumpRefMarker(writer, data.type); | |
| 358 | try writer.print(", {s}", .{data.field.slice(s.hir.string_bytes)}); | |
| 359 | try writer.writeAll(")"); | |
| 360 | }, | |
| 361 | .result_type_tuple_field => { | |
| 362 | const data: Hir.ResultTypeTupleField = hir.instData(.result_type_tuple_field, inst); | |
| 363 | ||
| 364 | try writer.writeAll("("); | |
| 365 | try s.dumpRefMarker(writer, data.type); | |
| 366 | try writer.print(", {d}", .{data.item}); | |
| 367 | try writer.writeAll(")"); | |
| 368 | }, | |
| 369 | .result_type_array_value => { | |
| 370 | const data: Hir.ResultTypeArrayValue = hir.instData(.result_type_array_value, inst); | |
| 371 | ||
| 372 | try writer.writeAll("("); | |
| 373 | try s.dumpRefMarker(writer, data.type); | |
| 374 | try writer.writeAll(")"); | |
| 375 | }, | |
| 376 | } | |
| 377 | } | |
| 378 | ||
| 379 | fn dumpRef(s: *State, writer: anytype, ref: Hir.Inst.Ref) !void { | |
| 380 | switch (ref.decode()) { | |
| 381 | .index => |index| try s.dumpInst(writer, index), | |
| 382 | .value => { | |
| 383 | try s.tty.setColor(writer, .blue); | |
| 384 | try writer.print("%{s}", .{@tagName(ref)}); | |
| 385 | try s.tty.setColor(writer, .reset); | |
| 386 | }, | |
| 387 | } | |
| 388 | } | |
| 389 | ||
| 390 | fn dumpRefMarker(s: *State, writer: anytype, ref: Hir.Inst.Ref) !void { | |
| 391 | switch (ref.decode()) { | |
| 392 | .index => |index| { | |
| 393 | try s.tty.setColor(writer, .blue); | |
| 394 | try writer.print("%{d}", .{@intFromEnum(index)}); | |
| 395 | try s.tty.setColor(writer, .reset); | |
| 396 | }, | |
| 397 | .value => { | |
| 398 | try s.tty.setColor(writer, .blue); | |
| 399 | try writer.print("%{s}", .{@tagName(ref)}); | |
| 400 | try s.tty.setColor(writer, .reset); | |
| 401 | }, | |
| 402 | } | |
| 403 | } | |
| 404 | ||
| 405 | fn dumpInstList(state: *State, writer: anytype, list: []const Hir.Inst.Index, l: u8, r: u8) !void { | |
| 406 | try writer.print(" {c}", .{l}); | |
| 407 | if (list.len > 0) { | |
| 408 | state.indent += 1; | |
| 409 | ||
| 410 | for (list) |inst| { | |
| 411 | try state.newline(writer); | |
| 412 | try state.dumpInst(writer, inst); | |
| 413 | } | |
| 414 | ||
| 415 | state.indent -= 1; | |
| 416 | try state.newline(writer); | |
| 417 | } | |
| 418 | try writer.print("{c}", .{r}); | |
| 419 | } | |
| 420 | ||
| 421 | fn dumpInstList2(state: *State, writer: anytype, list: []const Hir.Inst.Index, l: u8, r: u8) !void { | |
| 422 | try writer.print(" {c}", .{l}); | |
| 423 | if (list.len > 0) { | |
| 424 | state.indent += 1; | |
| 425 | ||
| 426 | for (list) |inst| { | |
| 427 | try state.newline(writer); | |
| 428 | try state.dumpRefMarker(writer, inst.toRef()); | |
| 429 | } | |
| 430 | ||
| 431 | state.indent -= 1; | |
| 432 | try state.newline(writer); | |
| 433 | } | |
| 434 | try writer.print("{c}", .{r}); | |
| 435 | } | |
| 436 | ||
| 437 | fn dumpRefList(state: *State, writer: anytype, list: []const Hir.Inst.Ref, l: u8, r: u8) !void { | |
| 438 | try writer.print(" {c}", .{l}); | |
| 439 | if (list.len > 0) { | |
| 440 | state.indent += 1; | |
| 441 | ||
| 442 | for (list) |ref| { | |
| 443 | try state.newline(writer); | |
| 444 | try state.dumpRef(writer, ref); | |
| 445 | } | |
| 446 | ||
| 447 | state.indent -= 1; | |
| 448 | ||
| 449 | try state.newline(writer); | |
| 450 | } | |
| 451 | try writer.print("{c}", .{r}); | |
| 452 | } | |
| 453 | ||
| 454 | fn dumpOptionalRefList(state: *State, writer: anytype, list: []const Hir.Inst.Ref.Optional, l: u8, r: u8) !void { | |
| 455 | try writer.print(" {c}", .{l}); | |
| 456 | if (list.len > 0) { | |
| 457 | state.indent += 1; | |
| 458 | ||
| 459 | for (list) |optional_ref| { | |
| 460 | try state.newline(writer); | |
| 461 | if (optional_ref.unwrap()) |ref| | |
| 462 | try state.dumpRef(writer, ref) | |
| 463 | else { | |
| 464 | try state.tty.setColor(writer, .bright_black); | |
| 465 | try writer.writeAll("<inferred>"); | |
| 466 | try state.tty.setColor(writer, .reset); | |
| 467 | } | |
| 468 | } | |
| 469 | ||
| 470 | state.indent -= 1; | |
| 471 | ||
| 472 | try state.newline(writer); | |
| 473 | } | |
| 474 | try writer.print("{c}", .{r}); | |
| 475 | } | |
| 476 | ||
| 477 | fn dumpRefMarkerList(state: *State, writer: anytype, list: []const Hir.Inst.Ref, l: u8, r: u8) !void { | |
| 478 | try writer.print("{c}", .{l}); | |
| 479 | if (list.len > 0) { | |
| 480 | state.indent += 1; | |
| 481 | ||
| 482 | for (list) |ref| { | |
| 483 | try state.newline(writer); | |
| 484 | try state.dumpRefMarker(writer, ref); | |
| 485 | } | |
| 486 | ||
| 487 | state.indent -= 1; | |
| 488 | ||
| 489 | try state.newline(writer); | |
| 490 | } | |
| 491 | try writer.print("{c}", .{r}); | |
| 492 | } | |
| 493 | }; | |
| 494 | ||
| 495 | pub fn format( | |
| 496 | dump: @This(), | |
| 497 | comptime unused_fmt: []const u8, | |
| 498 | _: std.fmt.FormatOptions, | |
| 499 | writer: anytype, | |
| 500 | ) !void { | |
| 501 | comptime assert(unused_fmt.len == 0); | |
| 502 | ||
| 503 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | |
| 504 | defer arena.deinit(); | |
| 505 | ||
| 506 | const hir = dump.hir; | |
| 507 | var state = State{ | |
| 508 | .hir = &hir, | |
| 509 | .tty = dump.tty orelse detectTTYFromWriter(writer), | |
| 510 | .arena = arena.allocator(), | |
| 511 | }; | |
| 512 | try state.dumpInst(writer, .main_module_inst); | |
| 513 | try writer.writeAll("\n"); | |
| 514 | assert(state.indent == 0); | |
| 515 | } | |
| 516 | ||
| 517 | const std = @import("std"); | |
| 518 | const assert = std.debug.assert; | |
| 519 | ||
| 520 | const core = @import("mod.zig"); | |
| 521 | const Hir = core.Hir; | |
| 522 | const detectTTYFromWriter = core.detectTTYFromWriter; |
src/core/Hir.zig created+1017| ... | ... | @@ -0,0 +1,1017 @@ |
| 1 | //! High-level Intermediate Representation is an instruction list format that | |
| 2 | //! describes a source file in a manner effective for Semantic Analysis to | |
| 3 | //! process. The root instruction of every Hir is a `.module` that contains the | |
| 4 | //! root declarations. Each declaration's value contains a list of instructions. | |
| 5 | //! In contrast to the nested nature of syntax trees, Hir represents nested | |
| 6 | //! expressions as flat instruction sequences. | |
| 7 | //! | |
| 8 | //! Hir for a given file has no dependencies on it's imports, meaning it can be | |
| 9 | //! computed in parallel and cached when not changed. | |
| 10 | //! | |
| 11 | //! A helper program exists to visualize Hir: './build transform -- ./file.ix' | |
| 12 | //! Alternatively, `ix build` has the `--dump-ir` option. | |
| 13 | ||
| 14 | insts: Inst.List.Slice, | |
| 15 | string_bytes: []const u8, | |
| 16 | extra: ExtraStore = .{}, | |
| 17 | report: Report, | |
| 18 | ||
| 19 | pub const ExtraStore = dod.ExtraStore(.hir, .@"const"); | |
| 20 | pub const EncodedData = dod.EncodedData(Tag, u64); | |
| 21 | pub const ExtraIndex = ExtraStore.Index; | |
| 22 | pub const Dump = @import("Hir.Dump.zig"); | |
| 23 | ||
| 24 | pub const Tag = enum(u8) { | |
| 25 | /// Either the top level module or a `module` keyword. Contains a list of `.declarations` | |
| 26 | /// Every analyzed module gets a `Comp.Namespace` | |
| 27 | module, | |
| 28 | /// Smallest unit of re-compilation. Every analyzed declaration gets a `Comp.Decl` | |
| 29 | declaration, | |
| 30 | /// Top-level memory location | |
| 31 | variable_declaration, | |
| 32 | /// Test declaration | |
| 33 | test_declaration, | |
| 34 | /// Retrieves a declaration value via it's name. Since declarations are | |
| 35 | /// analyzed in isolation of each other, all references to instructions | |
| 36 | /// outside of the current declaration must be in the form of this. | |
| 37 | load_decl, | |
| 38 | /// Blocks are a list of instructions. The block will end with a `.break`, | |
| 39 | /// which will assign the block a return value. | |
| 40 | block, | |
| 41 | /// Ends a block (current or any parent) with a value. | |
| 42 | /// `return` expressions are lowered to this. | |
| 43 | @"break", | |
| 44 | /// Creates a memory cell in the current scope with a starting value. | |
| 45 | memory, | |
| 46 | /// Re-assign a memory cell with a new ref. | |
| 47 | store, | |
| 48 | /// Re-assign a global variable decl with a new ref. | |
| 49 | store_decl, | |
| 50 | /// Re-assign a field with a new ref | |
| 51 | store_field, | |
| 52 | /// Performs a type coercion, such as in variable declarations. | |
| 53 | /// The resulting Air Ref will be guaranteed to be the coerced type. | |
| 54 | coercion, | |
| 55 | /// Load a parameter | |
| 56 | /// if data value is maxInt(u32), the function return type is used | |
| 57 | param, | |
| 58 | /// Asserts the operand is not void. Used for discard statements. | |
| 59 | discard, | |
| 60 | /// Asserts the operand is `void`. Used for undiscarded expressions. | |
| 61 | ensure_void, | |
| 62 | ||
| 63 | /// Branch takes a boolean condition and takes either a yes or no path. | |
| 64 | @"if", | |
| 65 | /// Given a block instruction | |
| 66 | @"comptime", | |
| 67 | ||
| 68 | /// A function expression, with or without captures | |
| 69 | func, | |
| 70 | ||
| 71 | // The following instructions are used to implement `Transform.ResultType` | |
| 72 | result_type_argument, | |
| 73 | result_type_struct_field, | |
| 74 | result_type_tuple_field, | |
| 75 | result_type_array_value, | |
| 76 | ||
| 77 | /// Numeric constant. | |
| 78 | number, | |
| 79 | /// String literal constant. | |
| 80 | string, | |
| 81 | ||
| 82 | /// Constructs a unique struct type. | |
| 83 | struct_decl, | |
| 84 | /// Constructs an array type | |
| 85 | array_type, | |
| 86 | ||
| 87 | struct_init, | |
| 88 | array_init, | |
| 89 | ||
| 90 | tuple_init, | |
| 91 | tuple_type, | |
| 92 | ||
| 93 | add, | |
| 94 | sub, | |
| 95 | mul, | |
| 96 | div, | |
| 97 | rem, | |
| 98 | pow, | |
| 99 | @"and", | |
| 100 | @"or", | |
| 101 | bit_and, | |
| 102 | bit_or, | |
| 103 | bit_xor, | |
| 104 | shl, | |
| 105 | shr, | |
| 106 | eq, | |
| 107 | ne, | |
| 108 | lt, | |
| 109 | le, | |
| 110 | gt, | |
| 111 | ge, | |
| 112 | ||
| 113 | negate, | |
| 114 | bool_not, | |
| 115 | bit_not, | |
| 116 | assert, | |
| 117 | field, | |
| 118 | index, | |
| 119 | call, | |
| 120 | type_of, | |
| 121 | /// Implements the `@extern` builtin | |
| 122 | @"extern", | |
| 123 | ||
| 124 | /// Implements the `@jsNew` builtin | |
| 125 | js_new, | |
| 126 | /// Implements the `@import` builtin | |
| 127 | import, | |
| 128 | /// Implements the `@fetch` builtin | |
| 129 | fetch, | |
| 130 | /// Implements the `@compileError` builtin | |
| 131 | compile_error, | |
| 132 | ||
| 133 | pub fn Data(comptime tag: Tag) type { | |
| 134 | return switch (tag) { | |
| 135 | .module, .block, .@"comptime" => PlNode(IndexList), | |
| 136 | ||
| 137 | .declaration, | |
| 138 | .variable_declaration, | |
| 139 | .test_declaration, | |
| 140 | => PlNode(Decl), | |
| 141 | ||
| 142 | .coercion => PlNode(Coercion), | |
| 143 | .@"break" => PlNode(Break), | |
| 144 | .number => PlNode(Float), | |
| 145 | .string => PlNode(SlicedString), | |
| 146 | .call => PlNode(Call), | |
| 147 | .@"if" => PlNode(If), | |
| 148 | .store => PlNode(Store), | |
| 149 | .store_decl => PlNode(StoreVarDecl), | |
| 150 | .store_field => PlNode(StoreField), | |
| 151 | .js_new => PlNode(JsNew), | |
| 152 | .struct_decl => PlNode(StructDecl), | |
| 153 | .struct_init => PlNode(StructInit), | |
| 154 | .array_init => PlNode(ArrayInit), | |
| 155 | .tuple_type => PlNode(TupleType), | |
| 156 | .tuple_init => PlNode(TupleInit), | |
| 157 | .func => PlNode(Func), | |
| 158 | ||
| 159 | .load_decl => StrNode, | |
| 160 | .param => DataNode, | |
| 161 | ||
| 162 | .result_type_argument => ResultTypeArgument, | |
| 163 | .result_type_struct_field => ResultTypeStructField, | |
| 164 | .result_type_tuple_field => ResultTypeTupleField, | |
| 165 | .result_type_array_value => ResultTypeArrayValue, | |
| 166 | ||
| 167 | // One operand instructions | |
| 168 | .memory, | |
| 169 | .discard, | |
| 170 | .ensure_void, | |
| 171 | .negate, | |
| 172 | .bool_not, | |
| 173 | .bit_not, | |
| 174 | .@"extern", | |
| 175 | .import, | |
| 176 | .fetch, | |
| 177 | .compile_error, | |
| 178 | .type_of, | |
| 179 | .array_type, | |
| 180 | .assert, | |
| 181 | => RefNode, | |
| 182 | ||
| 183 | // Two operand instructions | |
| 184 | .field, | |
| 185 | .index, | |
| 186 | .add, | |
| 187 | .sub, | |
| 188 | .mul, | |
| 189 | .div, | |
| 190 | .rem, | |
| 191 | .pow, | |
| 192 | .@"and", | |
| 193 | .@"or", | |
| 194 | .bit_and, | |
| 195 | .bit_or, | |
| 196 | .bit_xor, | |
| 197 | .shl, | |
| 198 | .shr, | |
| 199 | .eq, | |
| 200 | .ne, | |
| 201 | .lt, | |
| 202 | .le, | |
| 203 | .gt, | |
| 204 | .ge, | |
| 205 | => PlNode(Bin), | |
| 206 | }; | |
| 207 | } | |
| 208 | ||
| 209 | pub fn airTag(comptime tag: Tag) Air.Inst.Tag { | |
| 210 | return @field(Air.Inst.Tag, @tagName(tag)); | |
| 211 | } | |
| 212 | }; | |
| 213 | ||
| 214 | pub fn PlNode(comptime Payload: type) type { | |
| 215 | return struct { | |
| 216 | pub const T = Payload; | |
| 217 | ||
| 218 | src_node: NodeOffset, | |
| 219 | extra_index: ExtraIndex(Payload), | |
| 220 | }; | |
| 221 | } | |
| 222 | ||
| 223 | pub const RefNode = struct { | |
| 224 | src_node: NodeOffset, | |
| 225 | operand: Inst.Ref, | |
| 226 | }; | |
| 227 | ||
| 228 | pub const StrNode = struct { | |
| 229 | src_node: NodeOffset, | |
| 230 | string: NullTerminatedString, | |
| 231 | }; | |
| 232 | ||
| 233 | pub const DataNode = struct { | |
| 234 | src_node: NodeOffset, | |
| 235 | data: u32, | |
| 236 | }; | |
| 237 | ||
| 238 | pub const Inst = struct { | |
| 239 | pub const List = std.MultiArrayList(Inst); | |
| 240 | ||
| 241 | tag: Tag, | |
| 242 | data: EncodedData, | |
| 243 | ||
| 244 | /// The position of a Hir instruction within the `Hir` instructions array. | |
| 245 | pub const Index = enum(u32) { | |
| 246 | /// Hir is structured so that the outermost "main" struct of any file | |
| 247 | /// is always at index 0. | |
| 248 | main_module_inst = 0, | |
| 249 | _, | |
| 250 | ||
| 251 | pub const static_len = @intFromEnum(Ref.empty_tuple) + 1; | |
| 252 | ||
| 253 | pub fn toRef(i: Index) Inst.Ref { | |
| 254 | return @enumFromInt(static_len + @intFromEnum(i)); | |
| 255 | } | |
| 256 | ||
| 257 | pub fn toOptional(i: Index) Optional { | |
| 258 | return @enumFromInt(@intFromEnum(i)); | |
| 259 | } | |
| 260 | ||
| 261 | pub fn op(i: Index, operand: Report.Operand) InstOp { | |
| 262 | return .{ .index = i, .op = operand }; | |
| 263 | } | |
| 264 | ||
| 265 | pub const Optional = enum(u32) { | |
| 266 | none = std.math.maxInt(u32), | |
| 267 | _, | |
| 268 | ||
| 269 | pub fn unwrap(oi: Optional) ?Index { | |
| 270 | return if (oi == .none) null else @enumFromInt(@intFromEnum(oi)); | |
| 271 | } | |
| 272 | }; | |
| 273 | }; | |
| 274 | ||
| 275 | /// A reference to an instruction, or to a static InternPool value. | |
| 276 | /// | |
| 277 | /// If the integer tag value is < InternPool.static_len, then it | |
| 278 | /// corresponds to a Value. Otherwise, it is an instruction index. | |
| 279 | pub const Ref = enum(u32) { | |
| 280 | opaque_type, | |
| 281 | bool_type, | |
| 282 | int32_type, | |
| 283 | float_type, | |
| 284 | string_type, | |
| 285 | never_type, | |
| 286 | type_type, | |
| 287 | numeric_literal_type, | |
| 288 | numeric_literal_array_type, | |
| 289 | never_array_type, | |
| 290 | empty_tuple_type, | |
| 291 | ||
| 292 | void, | |
| 293 | bool_true, | |
| 294 | bool_false, | |
| 295 | int32_zero, | |
| 296 | float_zero, | |
| 297 | nan, | |
| 298 | empty_string, | |
| 299 | empty_array, | |
| 300 | empty_tuple, | |
| 301 | _, | |
| 302 | ||
| 303 | pub const Decoded = union(enum) { | |
| 304 | value: InternPool.Value, | |
| 305 | index: Hir.Inst.Index, | |
| 306 | }; | |
| 307 | ||
| 308 | pub fn decode(ref: Ref) Decoded { | |
| 309 | const ref_int = @intFromEnum(ref); | |
| 310 | return if (ref_int >= Index.static_len) | |
| 311 | .{ .index = @enumFromInt(ref_int - Index.static_len) } | |
| 312 | else | |
| 313 | .{ .value = @enumFromInt(ref_int) }; | |
| 314 | } | |
| 315 | ||
| 316 | pub fn index(ref: Ref) ?Index { | |
| 317 | const ref_int = @intFromEnum(ref); | |
| 318 | if (ref_int >= Index.static_len) { | |
| 319 | return @enumFromInt(ref_int - Index.static_len); | |
| 320 | } else { | |
| 321 | return null; | |
| 322 | } | |
| 323 | } | |
| 324 | ||
| 325 | pub fn value(inst: Ref) ?InternPool.Value { | |
| 326 | const ref_int = @intFromEnum(inst); | |
| 327 | ||
| 328 | // TODO: is this > or >= | |
| 329 | if (ref_int > Index.static_len) | |
| 330 | return null; | |
| 331 | ||
| 332 | return @enumFromInt(ref_int); | |
| 333 | } | |
| 334 | ||
| 335 | pub fn toOptional(ref: Ref) Optional { | |
| 336 | return @enumFromInt(@intFromEnum(ref)); | |
| 337 | } | |
| 338 | ||
| 339 | pub const Optional = enum(u32) { | |
| 340 | none = std.math.maxInt(u32), | |
| 341 | _, | |
| 342 | ||
| 343 | pub fn unwrap(opt: Optional) ?Ref { | |
| 344 | return if (opt != .none) @enumFromInt(@intFromEnum(opt)) else null; | |
| 345 | } | |
| 346 | }; | |
| 347 | }; | |
| 348 | }; | |
| 349 | ||
| 350 | pub const Bin = struct { | |
| 351 | lhs: Inst.Ref, | |
| 352 | rhs: Inst.Ref, | |
| 353 | }; | |
| 354 | ||
| 355 | pub const Store = struct { | |
| 356 | memory: Inst.Index, | |
| 357 | operand: Inst.Ref, | |
| 358 | }; | |
| 359 | ||
| 360 | pub const StoreVarDecl = struct { | |
| 361 | var_decl: NullTerminatedString, | |
| 362 | operand: Inst.Ref, | |
| 363 | }; | |
| 364 | ||
| 365 | pub const StoreField = struct { | |
| 366 | base: Inst.Ref, | |
| 367 | field: Inst.Ref, | |
| 368 | operand: Inst.Ref, | |
| 369 | }; | |
| 370 | ||
| 371 | pub const Coercion = struct { | |
| 372 | type: Inst.Ref, | |
| 373 | operand: Inst.Ref, | |
| 374 | }; | |
| 375 | ||
| 376 | pub const Break = struct { | |
| 377 | block: Inst.Index, | |
| 378 | operand: Inst.Ref, | |
| 379 | }; | |
| 380 | ||
| 381 | pub const Call = struct { | |
| 382 | base: Inst.Ref, | |
| 383 | args: RefList, | |
| 384 | }; | |
| 385 | ||
| 386 | pub const If = struct { | |
| 387 | cond: Inst.Ref, | |
| 388 | yes: Inst.Ref, | |
| 389 | no: Inst.Ref, | |
| 390 | }; | |
| 391 | ||
| 392 | pub const JsNew = struct { | |
| 393 | base: Inst.Ref, | |
| 394 | args: RefList, | |
| 395 | }; | |
| 396 | ||
| 397 | /// Index into extra which contains `field_len * 2` u32s. The first half | |
| 398 | /// are the keys (NullTerminatedString) and the second half are field types | |
| 399 | /// (Ref). This basically is like a specialized MultiArrayList. | |
| 400 | pub const StructDecl = struct { | |
| 401 | payload_index: u32, | |
| 402 | field_len: u32, | |
| 403 | ||
| 404 | pub fn keys(decl: StructDecl, hir: *const Hir) []const NullTerminatedString { | |
| 405 | return @ptrCast( | |
| 406 | hir.extra.list.items[decl.payload_index..][0..decl.field_len], | |
| 407 | ); | |
| 408 | } | |
| 409 | ||
| 410 | pub fn types(decl: StructDecl, hir: *const Hir) []const Inst.Ref { | |
| 411 | return @ptrCast( | |
| 412 | hir.extra.list.items[decl.payload_index + decl.field_len ..][0..decl.field_len], | |
| 413 | ); | |
| 414 | } | |
| 415 | }; | |
| 416 | ||
| 417 | /// This memory is laid out with the same strategy described in StructDecl | |
| 418 | pub const StructInit = struct { | |
| 419 | base_type: Inst.Ref, | |
| 420 | payload_index: u32, | |
| 421 | field_len: u32, | |
| 422 | ||
| 423 | pub fn keys(decl: StructInit, hir: *const Hir) []const NullTerminatedString { | |
| 424 | return @ptrCast( | |
| 425 | hir.extra.list.items[decl.payload_index..][0..decl.field_len], | |
| 426 | ); | |
| 427 | } | |
| 428 | ||
| 429 | pub fn inits(decl: StructInit, hir: *const Hir) []const Inst.Ref { | |
| 430 | return @ptrCast( | |
| 431 | hir.extra.list.items[decl.payload_index + decl.field_len ..][0..decl.field_len], | |
| 432 | ); | |
| 433 | } | |
| 434 | }; | |
| 435 | ||
| 436 | pub const ArrayInit = struct { | |
| 437 | /// Optionally provide a result type for more reliable type coercion. | |
| 438 | /// If specified, this must be an array type. Otherwise, the first | |
| 439 | /// element's type is used. | |
| 440 | type_hint: Inst.Ref.Optional, | |
| 441 | /// The items in the array | |
| 442 | list: RefList, | |
| 443 | }; | |
| 444 | ||
| 445 | pub const TupleType = struct { | |
| 446 | /// The items in the tuple | |
| 447 | items: RefList, | |
| 448 | }; | |
| 449 | ||
| 450 | pub const TupleInit = struct { | |
| 451 | /// Optionally provide a result type for more reliable type coercion. | |
| 452 | /// If specified, this must be an array type. Otherwise, the first | |
| 453 | /// element's type is used. | |
| 454 | type_hint: Inst.Ref.Optional, | |
| 455 | /// The items in the tuple | |
| 456 | items: RefList, | |
| 457 | }; | |
| 458 | ||
| 459 | pub const Decl = struct { | |
| 460 | name: NullTerminatedString, | |
| 461 | hash: Cache.BinDigest, | |
| 462 | instruction_count: u32, | |
| 463 | body: Inst.Ref, | |
| 464 | }; | |
| 465 | ||
| 466 | pub const Func = struct { | |
| 467 | params: OptionalRefList, | |
| 468 | return_type: Inst.Ref.Optional, | |
| 469 | body: Inst.Index, | |
| 470 | captures: IndexList, | |
| 471 | instruction_count: u32, | |
| 472 | }; | |
| 473 | ||
| 474 | pub const ResultTypeArgument = struct { | |
| 475 | /// The VALUE that is going to be called. | |
| 476 | call_base: Inst.Ref, | |
| 477 | /// Which argument | |
| 478 | argument: u32, | |
| 479 | }; | |
| 480 | ||
| 481 | pub const ResultTypeStructField = struct { | |
| 482 | /// The type of the struct itself, | |
| 483 | type: Inst.Ref, | |
| 484 | /// Which field | |
| 485 | field: NullTerminatedString, | |
| 486 | }; | |
| 487 | ||
| 488 | pub const ResultTypeTupleField = struct { | |
| 489 | /// The type of the tuple itself, | |
| 490 | type: Inst.Ref, | |
| 491 | /// Which item | |
| 492 | item: u32, | |
| 493 | }; | |
| 494 | ||
| 495 | pub const ResultTypeArrayValue = struct { | |
| 496 | /// The type of the array itself, | |
| 497 | type: Inst.Ref, | |
| 498 | unused: u32 = 0, | |
| 499 | }; | |
| 500 | ||
| 501 | // TODO: make this an enum | |
| 502 | const NodeOffset = i32; | |
| 503 | ||
| 504 | // TODO: remove InstOp. LazyNode should not have a decl | |
| 505 | pub const InstOp = struct { | |
| 506 | index: Inst.Index, | |
| 507 | op: Report.Operand, | |
| 508 | ||
| 509 | pub fn lazyNode(inst: InstOp, decl: Comp.Decl.Index) LazyNode { | |
| 510 | return .{ | |
| 511 | .inst = inst.index, | |
| 512 | .operand = inst.op, | |
| 513 | .decl = decl, | |
| 514 | }; | |
| 515 | } | |
| 516 | }; | |
| 517 | ||
| 518 | pub const NullTerminatedString = enum(u32) { | |
| 519 | empty = 0, | |
| 520 | _, | |
| 521 | ||
| 522 | pub fn slice(str: NullTerminatedString, string_bytes: []const u8) [:0]const u8 { | |
| 523 | if (str == .empty) return ""; | |
| 524 | const sub = string_bytes[@intFromEnum(str)..]; | |
| 525 | const i = mem.indexOfScalar(u8, sub, 0) orelse unreachable; | |
| 526 | ||
| 527 | return sub[0..i :0]; | |
| 528 | } | |
| 529 | }; | |
| 530 | ||
| 531 | pub const SlicedString = struct { | |
| 532 | start: u32, | |
| 533 | len: u32, | |
| 534 | ||
| 535 | pub fn slice(str: SlicedString, string_bytes: []const u8) []const u8 { | |
| 536 | return string_bytes[str.start..][0..str.len]; | |
| 537 | } | |
| 538 | }; | |
| 539 | ||
| 540 | // TODO: Make the next three structs using a generic comptime thing | |
| 541 | ||
| 542 | pub const RefList = struct { | |
| 543 | start: u32, | |
| 544 | len: u32, | |
| 545 | ||
| 546 | pub fn slice(self: RefList, hir: *const Hir) []const Inst.Ref { | |
| 547 | return @ptrCast(hir.extra.list.items[self.start..][0..self.len]); | |
| 548 | } | |
| 549 | }; | |
| 550 | ||
| 551 | pub const OptionalRefList = struct { | |
| 552 | start: u32, | |
| 553 | len: u32, | |
| 554 | ||
| 555 | pub fn slice(self: OptionalRefList, hir: *const Hir) []const Inst.Ref.Optional { | |
| 556 | return @ptrCast(hir.extra.list.items[self.start..][0..self.len]); | |
| 557 | } | |
| 558 | }; | |
| 559 | ||
| 560 | pub const IndexList = struct { | |
| 561 | start: u32, | |
| 562 | len: u32, | |
| 563 | ||
| 564 | pub fn slice(self: IndexList, hir: *const Hir) []const Inst.Index { | |
| 565 | return @ptrCast(hir.extra.list.items[self.start..][0..self.len]); | |
| 566 | } | |
| 567 | }; | |
| 568 | ||
| 569 | pub const NullTermStringList = struct { | |
| 570 | start: u32, | |
| 571 | len: u32, | |
| 572 | ||
| 573 | pub fn slice(self: IndexList, hir: *const Hir) []const NullTerminatedString { | |
| 574 | return @ptrCast(hir.extra.list.items[self.start..][0..self.len]); | |
| 575 | } | |
| 576 | }; | |
| 577 | ||
| 578 | pub fn deinit(hir: *Hir, gpa: std.mem.Allocator) void { | |
| 579 | gpa.free(hir.string_bytes); | |
| 580 | hir.extra.deinit(gpa); | |
| 581 | hir.insts.deinit(gpa); | |
| 582 | hir.report.deinit(gpa); | |
| 583 | hir.* = undefined; | |
| 584 | } | |
| 585 | ||
| 586 | pub fn instTag(hir: *const Hir, index: Inst.Index) Hir.Tag { | |
| 587 | return hir.insts.items(.tag)[@intFromEnum(index)]; | |
| 588 | } | |
| 589 | ||
| 590 | pub fn instEncodedData(hir: *const Hir, index: Inst.Index) EncodedData { | |
| 591 | return hir.insts.items(.data)[@intFromEnum(index)]; | |
| 592 | } | |
| 593 | ||
| 594 | pub fn instData(hir: *const Hir, comptime tag: Hir.Tag, index: Inst.Index) tag.Data() { | |
| 595 | return hir.instEncodedData(index).decode(tag, hir.instTag(index)); | |
| 596 | } | |
| 597 | ||
| 598 | pub fn instDataUnsafe(hir: *const Hir, comptime T: type, index: Inst.Index) T { | |
| 599 | return hir.instEncodedData(index).decodeUnsafe(T, hir.instTag(index)); | |
| 600 | } | |
| 601 | ||
| 602 | pub fn instPayload(hir: *const Hir, comptime tag: Hir.Tag, index: Inst.Index) tag.Data().T { | |
| 603 | return hir.instData(tag, index).extra_index.get(hir); | |
| 604 | } | |
| 605 | ||
| 606 | pub fn instNodeOffset(hir: *const Hir, index: Inst.Index) i32 { | |
| 607 | return switch (hir.instTag(index)) { | |
| 608 | // these nodes never get errors, but Hir.Dump will print these regardless | |
| 609 | // TODO: | |
| 610 | .declaration, | |
| 611 | .result_type_argument, | |
| 612 | .result_type_struct_field, | |
| 613 | .result_type_tuple_field, | |
| 614 | .result_type_array_value, | |
| 615 | => 0, | |
| 616 | ||
| 617 | inline else => |tag| hir.instData(tag, index).src_node, | |
| 618 | }; | |
| 619 | } | |
| 620 | ||
| 621 | pub fn blockInstructions(hir: *const Hir, index: Inst.Index) []const Inst.Index { | |
| 622 | return hir.instData(.block, index).extra_index.get(hir).slice(hir); | |
| 623 | } | |
| 624 | ||
| 625 | pub fn fullFuncDecl(hir: *const Hir, index: Inst.Index) struct { Hir.Decl, Hir.DeclFn } { | |
| 626 | const decl, var trail = hir.instData(.declaration, index).extra_index.getTrail(hir); | |
| 627 | assert(decl.kind == .function); | |
| 628 | const decl_fn = trail.read(&hir.extra, Hir.DeclFn); | |
| 629 | return .{ decl, decl_fn }; | |
| 630 | } | |
| 631 | ||
| 632 | pub fn fullDecl(hir: *const Hir, index: Inst.Index) Decl { | |
| 633 | const decl = hir.instEncodedData(index).decodeUnsafe(PlNode(Decl), hir.instTag(index)).extra_index.get(hir); | |
| 634 | return .{ | |
| 635 | .name = decl.name, | |
| 636 | .hash = decl.hash, | |
| 637 | .instruction_count = decl.instruction_count, | |
| 638 | .body = decl.body, | |
| 639 | }; | |
| 640 | } | |
| 641 | ||
| 642 | pub fn declData(hir: *const Hir, index: Inst.Index) Hir.Decl { | |
| 643 | return hir.instDataUnsafe(PlNode(Decl), index).extra_index.get(hir); | |
| 644 | } | |
| 645 | ||
| 646 | pub fn moduleDeclarations(hir: *const Hir, module_index: Inst.Index) []const Inst.Index { | |
| 647 | const module = hir.instData(.module, module_index); | |
| 648 | const module_data: IndexList = module.extra_index.get(hir); | |
| 649 | const slice = module_data.slice(hir); | |
| 650 | if (core.runtime_safety) { | |
| 651 | for (slice) |item| { | |
| 652 | switch (hir.instTag(item)) { | |
| 653 | .declaration, .variable_declaration, .test_declaration => {}, | |
| 654 | else => { | |
| 655 | std.debug.panic("\ngot unknown tag {s}\n", .{@tagName(hir.instTag(item))}); | |
| 656 | }, | |
| 657 | } | |
| 658 | } | |
| 659 | } | |
| 660 | return slice; | |
| 661 | } | |
| 662 | ||
| 663 | pub fn rootFunction(hir: *const Hir) Inst.Index { | |
| 664 | const decls = hir.moduleDeclarations(.main_module_inst); | |
| 665 | const root_fn = decls[decls.len - 1]; | |
| 666 | assert(hir.declName(root_fn).len == 0); | |
| 667 | return root_fn; | |
| 668 | } | |
| 669 | ||
| 670 | pub fn declName(hir: *const Hir, decl_index: Inst.Index) []const u8 { | |
| 671 | const decl = hir.instDataUnsafe(PlNode(Decl), decl_index); | |
| 672 | const decl_data: Decl = decl.extra_index.get(hir); | |
| 673 | return decl_data.name.slice(hir.string_bytes); | |
| 674 | } | |
| 675 | ||
| 676 | pub fn dumpToWriter(hir: Hir, writer: anytype, tty: ?std.io.tty.Config) !void { | |
| 677 | try writer.print("{}", .{Dump{ .hir = hir, .tty = tty }}); | |
| 678 | } | |
| 679 | ||
| 680 | /// Used for generating decl hashes | |
| 681 | fn isolatedRefValue(decl_index: Inst.Index, ref_to_hash: Inst.Ref) i32 { | |
| 682 | return switch (ref_to_hash.decode()) { | |
| 683 | .value => |value| -@as(i32, @intCast(@intFromEnum(value))), | |
| 684 | .index => |index| @intCast(@intFromEnum(index) - @intFromEnum(decl_index)), | |
| 685 | }; | |
| 686 | } | |
| 687 | ||
| 688 | /// Used for generating decl hashes | |
| 689 | fn isolatedIndexValue(decl_index: Inst.Index, index_to_hash: Inst.Index) u32 { | |
| 690 | return @intFromEnum(index_to_hash) - @intFromEnum(decl_index); | |
| 691 | } | |
| 692 | ||
| 693 | pub fn writeToHasher( | |
| 694 | hir: *const Hir, | |
| 695 | hasher: *HashHelper, | |
| 696 | tag_list: []Tag, | |
| 697 | data_list: []EncodedData, | |
| 698 | decl_index: Inst.Index, | |
| 699 | ) void { | |
| 700 | // Add all of the tags | |
| 701 | hasher.addBytes(std.mem.sliceAsBytes(tag_list)); | |
| 702 | ||
| 703 | // Add all of the data | |
| 704 | for (tag_list, data_list) |tag, data| { | |
| 705 | ||
| 706 | // This should roughly line up with Hir.Tag.Data | |
| 707 | switch (tag) { | |
| 708 | // PlNode(IndexList), | |
| 709 | .module, | |
| 710 | .block, | |
| 711 | .@"comptime", | |
| 712 | => { | |
| 713 | const pl_node = data.decodeUnsafe(PlNode(IndexList), tag); | |
| 714 | hasher.add(pl_node.src_node); | |
| 715 | writeIndexListToHasher(hasher, pl_node.extra_index.get(hir).slice(hir), decl_index); | |
| 716 | }, | |
| 717 | ||
| 718 | // PlNode | |
| 719 | inline .declaration, | |
| 720 | .variable_declaration, | |
| 721 | .test_declaration, | |
| 722 | .coercion, | |
| 723 | .@"break", | |
| 724 | .number, | |
| 725 | .string, | |
| 726 | .call, | |
| 727 | .@"if", | |
| 728 | .store, | |
| 729 | .js_new, | |
| 730 | .struct_decl, | |
| 731 | .struct_init, | |
| 732 | .array_init, | |
| 733 | .tuple_init, | |
| 734 | .tuple_type, | |
| 735 | .func, | |
| 736 | .store_decl, | |
| 737 | .store_field, | |
| 738 | => |pl_node_tag| { | |
| 739 | const pl_node = data.decode(pl_node_tag, tag); | |
| 740 | hasher.add(pl_node.src_node); | |
| 741 | hir.writePlNodeInnerToHasher(hasher, pl_node_tag.Data().T, pl_node.extra_index.get(hir), decl_index); | |
| 742 | }, | |
| 743 | // StrNode | |
| 744 | .load_decl => { | |
| 745 | const str_node = data.decodeUnsafe(StrNode, tag); | |
| 746 | hasher.add(str_node.src_node); | |
| 747 | hasher.addBytes(str_node.string.slice(hir.string_bytes)); | |
| 748 | }, | |
| 749 | // DataNode | |
| 750 | .param => { | |
| 751 | const data_node = data.decodeUnsafe(DataNode, tag); | |
| 752 | hasher.add(data_node.src_node); | |
| 753 | hasher.add(data_node.data); | |
| 754 | }, | |
| 755 | // RefNode | |
| 756 | .memory, | |
| 757 | .discard, | |
| 758 | .ensure_void, | |
| 759 | .negate, | |
| 760 | .bool_not, | |
| 761 | .bit_not, | |
| 762 | .@"extern", | |
| 763 | .import, | |
| 764 | .fetch, | |
| 765 | .compile_error, | |
| 766 | .type_of, | |
| 767 | .array_type, | |
| 768 | .assert, | |
| 769 | => { | |
| 770 | const ref_node = data.decodeUnsafe(RefNode, tag); | |
| 771 | hasher.add(ref_node.src_node); | |
| 772 | hasher.add(isolatedRefValue(decl_index, ref_node.operand)); | |
| 773 | }, | |
| 774 | // PlNode(Bin) | |
| 775 | .field, | |
| 776 | .index, | |
| 777 | .add, | |
| 778 | .sub, | |
| 779 | .mul, | |
| 780 | .div, | |
| 781 | .rem, | |
| 782 | .pow, | |
| 783 | .@"and", | |
| 784 | .@"or", | |
| 785 | .bit_and, | |
| 786 | .bit_or, | |
| 787 | .bit_xor, | |
| 788 | .shl, | |
| 789 | .shr, | |
| 790 | .eq, | |
| 791 | .ne, | |
| 792 | .lt, | |
| 793 | .le, | |
| 794 | .gt, | |
| 795 | .ge, | |
| 796 | => { | |
| 797 | const pl_node = data.decodeUnsafe(PlNode(Bin), tag); | |
| 798 | const bin = pl_node.extra_index.get(hir); | |
| 799 | hasher.add(isolatedRefValue(decl_index, bin.lhs)); | |
| 800 | hasher.add(isolatedRefValue(decl_index, bin.rhs)); | |
| 801 | }, | |
| 802 | // Result Types | |
| 803 | .result_type_argument => { | |
| 804 | const arg = data.decodeUnsafe(ResultTypeArgument, tag); | |
| 805 | hasher.add(isolatedRefValue(decl_index, arg.call_base)); | |
| 806 | hasher.add(arg.argument); | |
| 807 | }, | |
| 808 | .result_type_struct_field => { | |
| 809 | const struct_field = data.decodeUnsafe(ResultTypeStructField, tag); | |
| 810 | hasher.add(isolatedRefValue(decl_index, struct_field.type)); | |
| 811 | hasher.addBytes(struct_field.field.slice(hir.string_bytes)); | |
| 812 | }, | |
| 813 | .result_type_tuple_field => { | |
| 814 | const tuple_field = data.decodeUnsafe(ResultTypeTupleField, tag); | |
| 815 | hasher.add(isolatedRefValue(decl_index, tuple_field.type)); | |
| 816 | hasher.add(tuple_field.item); | |
| 817 | }, | |
| 818 | .result_type_array_value => { | |
| 819 | const array_value = data.decodeUnsafe(ResultTypeArrayValue, tag); | |
| 820 | hasher.add(isolatedRefValue(decl_index, array_value.type)); | |
| 821 | }, | |
| 822 | } | |
| 823 | } | |
| 824 | } | |
| 825 | ||
| 826 | fn writeIndexListToHasher( | |
| 827 | hasher: *HashHelper, | |
| 828 | index_list: []const Inst.Index, | |
| 829 | decl_index: Inst.Index, | |
| 830 | ) void { | |
| 831 | hasher.add(index_list.len); | |
| 832 | for (index_list) |idx| { | |
| 833 | hasher.add(isolatedIndexValue(decl_index, idx)); | |
| 834 | } | |
| 835 | } | |
| 836 | ||
| 837 | fn writeRefListToHasher( | |
| 838 | hasher: *HashHelper, | |
| 839 | decl_index: Inst.Index, | |
| 840 | index_list: []const Inst.Ref, | |
| 841 | ) void { | |
| 842 | hasher.add(index_list.len); | |
| 843 | for (index_list) |idx| { | |
| 844 | hasher.add(isolatedRefValue(decl_index, idx)); | |
| 845 | } | |
| 846 | } | |
| 847 | ||
| 848 | fn writePlNodeInnerToHasher( | |
| 849 | hir: *const Hir, | |
| 850 | hasher: *HashHelper, | |
| 851 | comptime T: type, | |
| 852 | data: T, | |
| 853 | decl_index: Inst.Index, | |
| 854 | ) void { | |
| 855 | switch (T) { | |
| 856 | Decl => { | |
| 857 | hasher.addBytes(&data.hash); | |
| 858 | hasher.addBytes(data.name.slice(hir.string_bytes)); | |
| 859 | }, | |
| 860 | Float => { | |
| 861 | const as_bytes: [2]u32 = .{ | |
| 862 | data.low, | |
| 863 | data.high, | |
| 864 | }; | |
| 865 | hasher.add(@as(u64, @bitCast(as_bytes))); | |
| 866 | }, | |
| 867 | SlicedString => { | |
| 868 | hasher.addBytes(data.slice(hir.string_bytes)); | |
| 869 | }, | |
| 870 | Coercion => { | |
| 871 | hasher.add(isolatedRefValue(decl_index, data.type)); | |
| 872 | hasher.add(isolatedRefValue(decl_index, data.operand)); | |
| 873 | }, | |
| 874 | Break => { | |
| 875 | hasher.add(isolatedIndexValue(decl_index, data.block)); | |
| 876 | hasher.add(isolatedRefValue(decl_index, data.operand)); | |
| 877 | }, | |
| 878 | Call => { | |
| 879 | hasher.add(isolatedRefValue(decl_index, data.base)); | |
| 880 | writeRefListToHasher(hasher, decl_index, data.args.slice(hir)); | |
| 881 | }, | |
| 882 | If => { | |
| 883 | hasher.add(isolatedRefValue(decl_index, data.cond)); | |
| 884 | hasher.add(isolatedRefValue(decl_index, data.yes)); | |
| 885 | hasher.add(isolatedRefValue(decl_index, data.no)); | |
| 886 | }, | |
| 887 | Store => { | |
| 888 | hasher.add(isolatedIndexValue(decl_index, data.memory)); | |
| 889 | hasher.add(isolatedRefValue(decl_index, data.operand)); | |
| 890 | }, | |
| 891 | StoreField => { | |
| 892 | hasher.add(isolatedRefValue(decl_index, data.base)); | |
| 893 | hasher.add(isolatedRefValue(decl_index, data.field)); | |
| 894 | hasher.add(isolatedRefValue(decl_index, data.operand)); | |
| 895 | }, | |
| 896 | StoreVarDecl => { | |
| 897 | hasher.addBytes(data.var_decl.slice(hir.string_bytes)); | |
| 898 | hasher.add(isolatedRefValue(decl_index, data.operand)); | |
| 899 | }, | |
| 900 | JsNew => { | |
| 901 | hasher.add(isolatedRefValue(decl_index, data.base)); | |
| 902 | writeRefListToHasher(hasher, decl_index, data.args.slice(hir)); | |
| 903 | }, | |
| 904 | StructDecl => { | |
| 905 | hasher.add(data.field_len); | |
| 906 | for (data.keys(hir), data.types(hir)) |key, ty| { | |
| 907 | hasher.addBytes(key.slice(hir.string_bytes)); | |
| 908 | hasher.add(isolatedRefValue(decl_index, ty)); | |
| 909 | } | |
| 910 | }, | |
| 911 | StructInit => { | |
| 912 | hasher.add(isolatedRefValue(decl_index, data.base_type)); | |
| 913 | hasher.add(data.field_len); | |
| 914 | for (data.keys(hir), data.inits(hir)) |key, init| { | |
| 915 | hasher.addBytes(key.slice(hir.string_bytes)); | |
| 916 | hasher.add(isolatedRefValue(decl_index, init)); | |
| 917 | } | |
| 918 | }, | |
| 919 | ArrayInit => { | |
| 920 | if (data.type_hint.unwrap()) |type_hint| | |
| 921 | hasher.add(isolatedRefValue(decl_index, type_hint)) | |
| 922 | else | |
| 923 | hasher.add(@as(i32, std.math.maxInt(i32))); | |
| 924 | writeRefListToHasher(hasher, decl_index, data.list.slice(hir)); | |
| 925 | }, | |
| 926 | Func => { | |
| 927 | for (data.params.slice(hir)) |optional| { | |
| 928 | if (optional.unwrap()) |item| | |
| 929 | hasher.add(isolatedRefValue(decl_index, item)); | |
| 930 | } | |
| 931 | ||
| 932 | if (data.return_type.unwrap()) |type_hint| | |
| 933 | hasher.add(isolatedRefValue(decl_index, type_hint)) | |
| 934 | else | |
| 935 | hasher.add(@as(i32, std.math.maxInt(i32))); | |
| 936 | ||
| 937 | hasher.add(isolatedIndexValue(decl_index, data.body)); | |
| 938 | hasher.add(data.instruction_count); | |
| 939 | }, | |
| 940 | TupleType => { | |
| 941 | hasher.add(data.items.len); | |
| 942 | for (data.items.slice(hir)) |item| { | |
| 943 | hasher.add(isolatedRefValue(decl_index, item)); | |
| 944 | } | |
| 945 | }, | |
| 946 | TupleInit => { | |
| 947 | if (data.type_hint.unwrap()) |type_hint| | |
| 948 | hasher.add(isolatedRefValue(decl_index, type_hint)) | |
| 949 | else | |
| 950 | hasher.add(@as(i32, std.math.maxInt(i32))); | |
| 951 | writeRefListToHasher(hasher, decl_index, data.items.slice(hir)); | |
| 952 | }, | |
| 953 | else => @compileError("hash not implemented for " ++ @typeName(T)), | |
| 954 | } | |
| 955 | } | |
| 956 | ||
| 957 | pub const SerializedHeader = extern struct { | |
| 958 | const version = @import("config").version_string ++ "\x00"; | |
| 959 | ||
| 960 | instruction_len: u32, | |
| 961 | string_bytes: u32, | |
| 962 | extra_len: u32, | |
| 963 | report_err_len: u32, | |
| 964 | report_warn_len: u32, | |
| 965 | }; | |
| 966 | ||
| 967 | pub fn serialize(hir: Hir, target: core.SerializeTarget) !void { | |
| 968 | const header: SerializedHeader = .{ | |
| 969 | .instruction_len = @intCast(hir.insts.len), | |
| 970 | .string_bytes = @intCast(hir.string_bytes.len), | |
| 971 | .extra_len = @intCast(hir.extra.list.items.len), | |
| 972 | .report_err_len = @intCast(hir.report.errors.len), | |
| 973 | .report_warn_len = @intCast(hir.report.warnings.len), | |
| 974 | }; | |
| 975 | ||
| 976 | var iovecs = [_]std.posix.iovec_const{ | |
| 977 | core.iovecConst(SerializedHeader.version), | |
| 978 | core.iovecConst(std.mem.asBytes(&header)), | |
| 979 | core.iovecConst(std.mem.sliceAsBytes(hir.insts.items(.tag))), | |
| 980 | core.iovecConst(std.mem.sliceAsBytes(hir.insts.items(.data))), | |
| 981 | core.iovecConst(hir.string_bytes), | |
| 982 | core.iovecConst(std.mem.sliceAsBytes(hir.extra.list.items)), | |
| 983 | core.iovecConst(std.mem.sliceAsBytes(hir.report.errors)), | |
| 984 | core.iovecConst(std.mem.sliceAsBytes(hir.report.warnings)), | |
| 985 | }; | |
| 986 | try target.writev(&iovecs); | |
| 987 | } | |
| 988 | ||
| 989 | const Hir = @This(); | |
| 990 | ||
| 991 | const std = @import("std"); | |
| 992 | const mem = std.mem; | |
| 993 | const assert = std.debug.assert; | |
| 994 | const HashHelper = std.Build.Cache.HashHelper; | |
| 995 | ||
| 996 | const core = @import("mod.zig"); | |
| 997 | const Cache = core.Cache; | |
| 998 | ||
| 999 | const Ast = core.Ast; | |
| 1000 | const Unused = Ast.Unused; | |
| 1001 | const NodeIndex = Ast.NodeIndex; | |
| 1002 | const TokenIndex = Ast.TokenIndex; | |
| 1003 | const OptionalNodeIndex = Ast.OptionalNodeIndex; | |
| 1004 | const OptionalTokenIndex = Ast.OptionalTokenIndex; | |
| 1005 | const OptionalExtraIndex = Ast.OptionalExtraIndex; | |
| 1006 | ||
| 1007 | const dod = core.array; | |
| 1008 | const Float = dod.Float; | |
| 1009 | ||
| 1010 | const InternPool = core.InternPool; | |
| 1011 | ||
| 1012 | const Air = core.Air; | |
| 1013 | ||
| 1014 | const Comp = core.Comp; | |
| 1015 | ||
| 1016 | const Report = core.Report; | |
| 1017 | const LazyNode = Report.LazyNode; |
src/core/InternPool.zig+6-6| ... | ... | @@ -638,7 +638,7 @@ pub const ExtraIndex = ExtraStore.Index; |
| 638 | 638 | /// This is specified with an integer literal and a corresponding comptime |
| 639 | 639 | /// assert below to break an unfortunate and arguably incorrect dependency loop |
| 640 | 640 | /// when compiling. |
| 641 | pub const static_len = Teg.Inst.Index.static_len; | |
| 641 | pub const static_len = Hir.Inst.Index.static_len; | |
| 642 | 642 | comptime { |
| 643 | 643 | // @compileLog(static_len, static_keys.len); |
| 644 | 644 | assert(static_len == static_keys.len); |
| ... | ... | @@ -805,16 +805,16 @@ pub const NullTerminatedString = enum(u32) { |
| 805 | 805 | |
| 806 | 806 | pub const TrackedInst = extern struct { |
| 807 | 807 | path_digest: Cache.BinDigest, |
| 808 | inst: Teg.Inst.Index, | |
| 808 | inst: Hir.Inst.Index, | |
| 809 | 809 | |
| 810 | 810 | comptime { |
| 811 | 811 | // The fields should be tightly packed. See also serialization logic in `Compilation.saveState`. |
| 812 | assert(@sizeOf(@This()) == Cache.bin_digest_len + @sizeOf(Teg.Inst.Index)); | |
| 812 | assert(@sizeOf(@This()) == Cache.bin_digest_len + @sizeOf(Hir.Inst.Index)); | |
| 813 | 813 | } |
| 814 | 814 | |
| 815 | 815 | pub const Index = enum(u32) { |
| 816 | 816 | _, |
| 817 | pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Teg.Inst.Index { | |
| 817 | pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Hir.Inst.Index { | |
| 818 | 818 | return i.get(ip).inst; |
| 819 | 819 | } |
| 820 | 820 | |
| ... | ... | @@ -1659,7 +1659,7 @@ fn getOrPutTrailingString( |
| 1659 | 1659 | } |
| 1660 | 1660 | } |
| 1661 | 1661 | |
| 1662 | pub fn trackInst(ip: *InternPool, gpa: Allocator, file: *Comp.File, inst: Teg.Inst.Index) Allocator.Error!TrackedInst.Index { | |
| 1662 | pub fn trackInst(ip: *InternPool, gpa: Allocator, file: *Comp.File, inst: Hir.Inst.Index) Allocator.Error!TrackedInst.Index { | |
| 1663 | 1663 | const t = tracer.trace(@src()); |
| 1664 | 1664 | defer t.end(); |
| 1665 | 1665 | |
| ... | ... | @@ -1869,7 +1869,7 @@ const assert = std.debug.assert; |
| 1869 | 1869 | const core = @import("mod.zig"); |
| 1870 | 1870 | const Comp = core.Comp; |
| 1871 | 1871 | const Cache = core.Cache; |
| 1872 | const Teg = core.Teg; | |
| 1872 | const Hir = core.Hir; | |
| 1873 | 1873 | const Air = core.Air; |
| 1874 | 1874 | const dod = core.array; |
| 1875 | 1875 | const Float = dod.Float; |
src/core/Report.zig+8-8| ... | ... | @@ -1093,7 +1093,7 @@ pub const MsgContext = struct { |
| 1093 | 1093 | pub const LazyNode = struct { |
| 1094 | 1094 | // TODO: remove this, it should be inferable off of the analysis unit that belongs to the report |
| 1095 | 1095 | decl: Comp.Decl.Index, |
| 1096 | inst: Teg.Inst.Index, | |
| 1096 | inst: Hir.Inst.Index, | |
| 1097 | 1097 | operand: Operand, |
| 1098 | 1098 | |
| 1099 | 1099 | pub fn get(lazy: LazyNode, ctx: *MsgContext) !NodeIndex { |
| ... | ... | @@ -1111,15 +1111,15 @@ pub const LazyNode = struct { |
| 1111 | 1111 | @panic("TODO: LazyNode.get when the decl is in a nested namespace"); |
| 1112 | 1112 | } |
| 1113 | 1113 | |
| 1114 | const teg = &(ctx.file.?.teg orelse | |
| 1114 | const hir = &(ctx.file.?.hir orelse | |
| 1115 | 1115 | // this will be required once incremental compilation hits |
| 1116 | @panic("TODO: teg was unloaded")); | |
| 1116 | @panic("TODO: hir was unloaded")); | |
| 1117 | 1117 | |
| 1118 | 1118 | const decl_inst = decl.teg_decl_index; |
| 1119 | 1119 | |
| 1120 | const teg_decl = teg.instData(.declaration, decl_inst.resolve(ctx.ip())); | |
| 1120 | const teg_decl = hir.instData(.declaration, decl_inst.resolve(ctx.ip())); | |
| 1121 | 1121 | |
| 1122 | const node_offset = teg.instNodeOffset(lazy.inst); | |
| 1122 | const node_offset = hir.instNodeOffset(lazy.inst); | |
| 1123 | 1123 | |
| 1124 | 1124 | const base_node: NodeIndex = @intCast(teg_decl.src_node + node_offset); |
| 1125 | 1125 | if (lazy.operand == .main_node) |
| ... | ... | @@ -1129,7 +1129,7 @@ pub const LazyNode = struct { |
| 1129 | 1129 | |
| 1130 | 1130 | const node_tag = ctx.ast.nodeTag(base_node); |
| 1131 | 1131 | |
| 1132 | switch (teg.instTag(lazy.inst)) { | |
| 1132 | switch (hir.instTag(lazy.inst)) { | |
| 1133 | 1133 | .coercion => switch (node_tag) { |
| 1134 | 1134 | .var_decl => switch (lazy.operand) { |
| 1135 | 1135 | .lhs => return data.var_decl.type.unwrap().?, |
| ... | ... | @@ -1213,7 +1213,7 @@ pub const LazyNode = struct { |
| 1213 | 1213 | } |
| 1214 | 1214 | |
| 1215 | 1215 | std.debug.print("TODO: operand lookup: .{s} + .{s} + {}\n", .{ |
| 1216 | @tagName(teg.instTag(lazy.inst)), | |
| 1216 | @tagName(hir.instTag(lazy.inst)), | |
| 1217 | 1217 | @tagName(ctx.ast.nodeTag(base_node)), |
| 1218 | 1218 | lazy.operand, |
| 1219 | 1219 | }); |
| ... | ... | @@ -1467,7 +1467,7 @@ const TokenIndex = Ast.TokenIndex; |
| 1467 | 1467 | const NodeIndex = Ast.NodeIndex; |
| 1468 | 1468 | const Location = Ast.Location; |
| 1469 | 1469 | |
| 1470 | const Teg = core.Teg; | |
| 1470 | const Hir = core.Hir; | |
| 1471 | 1471 | |
| 1472 | 1472 | const Comp = core.Comp; |
| 1473 | 1473 | const File = Comp.File; |
src/core/Sema.zig+91-95| ... | ... | @@ -1,13 +1,9 @@ |
| 1 | //! Semantic Analysis converts `Teg` | |
| 1 | //! Semantic Analysis converts `Hir` to `Air` by stepping over every instruction | |
| 2 | //! and evaluating comptime values or emitting runtime instructions. | |
| 2 | 3 | //! |
| 3 | //! Designed as a nonrecursive state machine which can be paused when an | |
| 4 | //! unfinished dependency is encountered, allowing the thread to work | |
| 5 | //! on other analysis jobs. | |
| 6 | //! | |
| 7 | //! Sema's responsibilities include | |
| 8 | //! - Operation validation and reporting of most compile errors. | |
| 9 | //! - Evaluation of `comptime` code. | |
| 10 | //! - Declaring dependencies on other analysis units. | |
| 4 | //! Designed as a nonrecursive state machine, `Sema` can be paused when an | |
| 5 | //! unfinished dependency is encountered, allowing the thread to work on other | |
| 6 | //! analysis jobs. | |
| 11 | 7 | |
| 12 | 8 | comp: *Comp, |
| 13 | 9 | ip: *InternPool, |
| ... | ... | @@ -20,13 +16,13 @@ owner: AnalysisUnit, |
| 20 | 16 | /// The namespace index that is used for declaration lookups |
| 21 | 17 | ns_index: Namespace.Index, |
| 22 | 18 | /// Non-owning copy |
| 23 | teg: Teg, | |
| 24 | /// The file that .teg is from | |
| 19 | hir: Hir, | |
| 20 | /// The file that .hir is from | |
| 25 | 21 | file: *File, |
| 26 | 22 | |
| 27 | 23 | /// All errors and warnings from this decl |
| 28 | 24 | report: Report.Builder, |
| 29 | /// Map of `Teg` instructions to their resulting `Air` Ref | |
| 25 | /// Map of `Hir` instructions to their resulting `Air` Ref | |
| 30 | 26 | inst_map: InstMap, |
| 31 | 27 | |
| 32 | 28 | /// `null` when not analyzing function bodies |
| ... | ... | @@ -63,7 +59,7 @@ pub fn init( |
| 63 | 59 | s: *Sema, |
| 64 | 60 | comp: *Comp, |
| 65 | 61 | file: *File, |
| 66 | teg: Teg, | |
| 62 | hir: Hir, | |
| 67 | 63 | owner: AnalysisUnit, |
| 68 | 64 | ns_index: Namespace.Index, |
| 69 | 65 | arena_state: std.heap.ArenaAllocator, |
| ... | ... | @@ -82,7 +78,7 @@ pub fn init( |
| 82 | 78 | .arena_state = arena_state, |
| 83 | 79 | .owner = owner, |
| 84 | 80 | .ns_index = ns_index, |
| 85 | .teg = teg, | |
| 81 | .hir = hir, | |
| 86 | 82 | .file = file, |
| 87 | 83 | |
| 88 | 84 | .report = .init(comp.gpa), |
| ... | ... | @@ -102,12 +98,12 @@ pub fn init( |
| 102 | 98 | const first_instruction, const count = switch (owner.unwrap()) { |
| 103 | 99 | .decl => |decl| data: { |
| 104 | 100 | const decl_inst = s.ip.declPtr(decl).teg_decl_index.resolve(s.ip); |
| 105 | const teg_decl: Teg.Decl = teg.instPayload(.declaration, decl_inst); | |
| 101 | const teg_decl: Hir.Decl = hir.instPayload(.declaration, decl_inst); | |
| 106 | 102 | break :data .{ decl_inst, teg_decl.instruction_count }; |
| 107 | 103 | }, |
| 108 | 104 | .func => |value| data: { |
| 109 | 105 | const func_inst = value.toKey(s.ip).func.teg_body_inst.get(s.ip); |
| 110 | const func: Teg.Func = teg.instPayload(.func, func_inst.inst); | |
| 106 | const func: Hir.Func = hir.instPayload(.func, func_inst.inst); | |
| 111 | 107 | break :data .{ func.body, func.instruction_count }; |
| 112 | 108 | }, |
| 113 | 109 | }; |
| ... | ... | @@ -115,7 +111,7 @@ pub fn init( |
| 115 | 111 | s.inst_map = try .init(s.arena(), first_instruction, count); |
| 116 | 112 | |
| 117 | 113 | const block_index = switch (owner.unwrap()) { |
| 118 | .decl => switch (s.teg.declData(first_instruction).body.decode()) { | |
| 114 | .decl => switch (s.hir.declData(first_instruction).body.decode()) { | |
| 119 | 115 | .index => |index| index, |
| 120 | 116 | .value => unreachable, // Sema must not be created for a static value |
| 121 | 117 | }, |
| ... | ... | @@ -165,11 +161,11 @@ const AnalysisMode = enum { |
| 165 | 161 | }; |
| 166 | 162 | |
| 167 | 163 | const Frame = struct { |
| 168 | ip: [*]const Teg.Inst.Index, | |
| 164 | ip: [*]const Hir.Inst.Index, | |
| 169 | 165 | instructions_left: if (runtime_safety) usize else void, |
| 170 | 166 | |
| 171 | 167 | mode: AnalysisMode, |
| 172 | block_index: Teg.Inst.Index, | |
| 168 | block_index: Hir.Inst.Index, | |
| 173 | 169 | mark_index: u32, |
| 174 | 170 | data: Data, |
| 175 | 171 | |
| ... | ... | @@ -192,15 +188,15 @@ const Frame = struct { |
| 192 | 188 | argument: u16, |
| 193 | 189 | }; |
| 194 | 190 | |
| 195 | fn initFromBlock(s: *Sema, block_index: Teg.Inst.Index, mode: AnalysisMode, data: Data) Frame { | |
| 196 | switch (s.teg.instTag(block_index)) { | |
| 191 | fn initFromBlock(s: *Sema, block_index: Hir.Inst.Index, mode: AnalysisMode, data: Data) Frame { | |
| 192 | switch (s.hir.instTag(block_index)) { | |
| 197 | 193 | else => unreachable, // not a block |
| 198 | 194 | .block, .@"comptime" => {}, |
| 199 | 195 | } |
| 200 | const list = s.teg.instEncodedData(block_index) | |
| 201 | .decodeUnsafe(Teg.PlNode(Teg.IndexList), s.teg.instTag(block_index)) | |
| 202 | .extra_index.get(&s.teg) | |
| 203 | .slice(&s.teg); | |
| 196 | const list = s.hir.instEncodedData(block_index) | |
| 197 | .decodeUnsafe(Hir.PlNode(Hir.IndexList), s.hir.instTag(block_index)) | |
| 198 | .extra_index.get(&s.hir) | |
| 199 | .slice(&s.hir); | |
| 204 | 200 | return .{ |
| 205 | 201 | .ip = list[0..].ptr, |
| 206 | 202 | .instructions_left = if (runtime_safety) list.len, |
| ... | ... | @@ -211,12 +207,12 @@ const Frame = struct { |
| 211 | 207 | }; |
| 212 | 208 | } |
| 213 | 209 | |
| 214 | fn currentIndex(frame: *const Frame) Teg.Inst.Index { | |
| 210 | fn currentIndex(frame: *const Frame) Hir.Inst.Index { | |
| 215 | 211 | // validate the pointer is correct |
| 216 | 212 | if (runtime_safety) { |
| 217 | 213 | const s: *const Sema = @fieldParentPtr("frame", frame); |
| 218 | 214 | assert(s.magic == .valid); |
| 219 | const extra = s.teg.extra.list.items; | |
| 215 | const extra = s.hir.extra.list.items; | |
| 220 | 216 | assert(@intFromPtr(frame.ip) > @intFromPtr(extra.ptr) and |
| 221 | 217 | @intFromPtr(frame.ip) <= @intFromPtr(&extra.ptr[extra.len - 1])); |
| 222 | 218 | } |
| ... | ... | @@ -224,22 +220,22 @@ const Frame = struct { |
| 224 | 220 | return frame.ip[0]; |
| 225 | 221 | } |
| 226 | 222 | |
| 227 | fn currentTag(frame: *const Frame) Teg.Tag { | |
| 223 | fn currentTag(frame: *const Frame) Hir.Tag { | |
| 228 | 224 | const s: *const Sema = @fieldParentPtr("frame", frame); |
| 229 | 225 | assert(s.magic == .valid); |
| 230 | return s.teg.instTag(frame.currentIndex()); | |
| 226 | return s.hir.instTag(frame.currentIndex()); | |
| 231 | 227 | } |
| 232 | 228 | |
| 233 | fn currentData(frame: *const Frame, comptime tag: Teg.Tag) tag.Data() { | |
| 229 | fn currentData(frame: *const Frame, comptime tag: Hir.Tag) tag.Data() { | |
| 234 | 230 | const s: *const Sema = @fieldParentPtr("frame", frame); |
| 235 | 231 | assert(s.magic == .valid); |
| 236 | return s.teg.instData(tag, frame.currentIndex()); | |
| 232 | return s.hir.instData(tag, frame.currentIndex()); | |
| 237 | 233 | } |
| 238 | 234 | |
| 239 | fn currentPayload(frame: *const Frame, comptime tag: Teg.Tag) tag.Data().T { | |
| 235 | fn currentPayload(frame: *const Frame, comptime tag: Hir.Tag) tag.Data().T { | |
| 240 | 236 | const s: *const Sema = @fieldParentPtr("frame", frame); |
| 241 | 237 | assert(s.magic == .valid); |
| 242 | return s.teg.instPayload(tag, frame.currentIndex()); | |
| 238 | return s.hir.instPayload(tag, frame.currentIndex()); | |
| 243 | 239 | } |
| 244 | 240 | |
| 245 | 241 | fn advance(frame: *Frame) void { |
| ... | ... | @@ -282,10 +278,10 @@ const Function = struct { |
| 282 | 278 | /// instructions it has. |
| 283 | 279 | const InstMap = struct { |
| 284 | 280 | items: []Air.Inst.Ref.Optional, |
| 285 | start: Teg.Inst.Index, | |
| 281 | start: Hir.Inst.Index, | |
| 286 | 282 | debug_traces: if (runtime_safety) []StoredTrace else void, |
| 287 | 283 | |
| 288 | pub fn init(allocator: Allocator, inst_start: Teg.Inst.Index, inst_len: u32) !InstMap { | |
| 284 | pub fn init(allocator: Allocator, inst_start: Hir.Inst.Index, inst_len: u32) !InstMap { | |
| 289 | 285 | const insts = try allocator.alloc(Air.Inst.Ref.Optional, inst_len); |
| 290 | 286 | errdefer allocator.free(insts); |
| 291 | 287 | |
| ... | ... | @@ -309,7 +305,7 @@ const InstMap = struct { |
| 309 | 305 | map.* = undefined; |
| 310 | 306 | } |
| 311 | 307 | |
| 312 | pub fn getOrNull(map: *const InstMap, teg_code: Teg.Inst.Index) ?Air.Inst.Ref { | |
| 308 | pub fn getOrNull(map: *const InstMap, teg_code: Hir.Inst.Index) ?Air.Inst.Ref { | |
| 313 | 309 | const source_i = @intFromEnum(teg_code); |
| 314 | 310 | const start_i = @intFromEnum(map.start); |
| 315 | 311 | if (assertFailed(source_i >= start_i and source_i <= start_i + map.items.len)) { |
| ... | ... | @@ -322,7 +318,7 @@ const InstMap = struct { |
| 322 | 318 | return map.items[source_i - start_i].unwrap(); |
| 323 | 319 | } |
| 324 | 320 | |
| 325 | pub fn get(map: *const InstMap, teg_code: Teg.Inst.Index) Air.Inst.Ref { | |
| 321 | pub fn get(map: *const InstMap, teg_code: Hir.Inst.Index) Air.Inst.Ref { | |
| 326 | 322 | return map.getOrNull(teg_code) orelse { |
| 327 | 323 | if (runtime_safety) { |
| 328 | 324 | std.debug.panic("did not analyze %{d}", .{@intFromEnum(teg_code)}); |
| ... | ... | @@ -331,7 +327,7 @@ const InstMap = struct { |
| 331 | 327 | }; |
| 332 | 328 | } |
| 333 | 329 | |
| 334 | pub fn add(map: *InstMap, from: Teg.Inst.Index, to: Air.Inst.Ref) void { | |
| 330 | pub fn add(map: *InstMap, from: Hir.Inst.Index, to: Air.Inst.Ref) void { | |
| 335 | 331 | const source_i = @intFromEnum(from); |
| 336 | 332 | const start_i = @intFromEnum(map.start); |
| 337 | 333 | if (assertFailed(source_i >= start_i and source_i <= start_i + map.items.len)) { |
| ... | ... | @@ -371,7 +367,7 @@ const DoMark = enum { |
| 371 | 367 | marked, |
| 372 | 368 | }; |
| 373 | 369 | |
| 374 | fn getRef(s: *Sema, teg_ref: Teg.Inst.Ref, mark: DoMark) Air.Inst.Ref { | |
| 370 | fn getRef(s: *Sema, teg_ref: Hir.Inst.Ref, mark: DoMark) Air.Inst.Ref { | |
| 375 | 371 | switch (teg_ref.decode()) { |
| 376 | 372 | .value => |value| return value.toAir(), |
| 377 | 373 | .index => |index| { |
| ... | ... | @@ -389,7 +385,7 @@ fn getRef(s: *Sema, teg_ref: Teg.Inst.Ref, mark: DoMark) Air.Inst.Ref { |
| 389 | 385 | } |
| 390 | 386 | } |
| 391 | 387 | |
| 392 | fn getValue(s: *Sema, src: LazyNode, teg_ref: Teg.Inst.Ref) !Value { | |
| 388 | fn getValue(s: *Sema, src: LazyNode, teg_ref: Hir.Inst.Ref) !Value { | |
| 393 | 389 | switch (teg_ref.decode()) { |
| 394 | 390 | .value => |value| return value, |
| 395 | 391 | .index => |index| { |
| ... | ... | @@ -399,17 +395,17 @@ fn getValue(s: *Sema, src: LazyNode, teg_ref: Teg.Inst.Ref) !Value { |
| 399 | 395 | } |
| 400 | 396 | } |
| 401 | 397 | |
| 402 | fn getCoercedValue(s: *Sema, src: LazyNode, teg_ref: Teg.Inst.Ref, ty: Type) !Value { | |
| 398 | fn getCoercedValue(s: *Sema, src: LazyNode, teg_ref: Hir.Inst.Ref, ty: Type) !Value { | |
| 403 | 399 | const any = try s.getValue(src, teg_ref); |
| 404 | 400 | return try s.coerceValue(src, any, ty); |
| 405 | 401 | } |
| 406 | 402 | |
| 407 | fn getCoercedRef(s: *Sema, src: LazyNode, teg_ref: Teg.Inst.Ref, ty: Type, mark: DoMark) !Air.Inst.Ref { | |
| 403 | fn getCoercedRef(s: *Sema, src: LazyNode, teg_ref: Hir.Inst.Ref, ty: Type, mark: DoMark) !Air.Inst.Ref { | |
| 408 | 404 | const any = s.getRef(teg_ref, mark); |
| 409 | 405 | return try s.coerceRef(src, any, ty); |
| 410 | 406 | } |
| 411 | 407 | |
| 412 | fn getType(s: *Sema, src: LazyNode, teg_ref: Teg.Inst.Ref) !Type { | |
| 408 | fn getType(s: *Sema, src: LazyNode, teg_ref: Hir.Inst.Ref) !Type { | |
| 413 | 409 | return (try s.getCoercedValue(src, teg_ref, .type)).toTypeUnsafe(s.ip); |
| 414 | 410 | } |
| 415 | 411 | |
| ... | ... | @@ -491,7 +487,7 @@ const InstructionKind = enum { |
| 491 | 487 | control_flow, |
| 492 | 488 | pop_control_flow, |
| 493 | 489 | |
| 494 | pub inline fn fromTag(tag: Teg.Tag) InstructionKind { | |
| 490 | pub inline fn fromTag(tag: Hir.Tag) InstructionKind { | |
| 495 | 491 | return switch (tag) { |
| 496 | 492 | // these push new frames, and frame end will assign its value |
| 497 | 493 | .func, |
| ... | ... | @@ -523,7 +519,7 @@ const InstructionKind = enum { |
| 523 | 519 | |
| 524 | 520 | const PopControlFlowState = enum { stop, @"continue" }; |
| 525 | 521 | |
| 526 | fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag).Result() { | |
| 522 | fn stepInner(s: *Sema, comptime tag: Hir.Tag) Error!InstructionKind.fromTag(tag).Result() { | |
| 527 | 523 | switch (tag) { |
| 528 | 524 | .block => unreachable, // frame must already be pushed |
| 529 | 525 | .declaration, |
| ... | ... | @@ -534,7 +530,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 534 | 530 | // TODO: pre-evaluate `.param` nodes, since they are always at the start of a function. |
| 535 | 531 | // this way we can avoid repeating the non-trivial call into InternPool |
| 536 | 532 | .param => { |
| 537 | const param: Teg.DataNode = s.frame.currentData(.param); | |
| 533 | const param: Hir.DataNode = s.frame.currentData(.param); | |
| 538 | 534 | assert(s.frame.mode == .run_time); // never emitted in a comptime block |
| 539 | 535 | assert(s.owner.kind == .func); // only emitted in function body |
| 540 | 536 | const proto = s.owner.unwrap().func.toKey(s.ip).func.ty.toUnresolvedFunctionPrototype(s.ip).?; |
| ... | ... | @@ -550,8 +546,8 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 550 | 546 | } |
| 551 | 547 | }, |
| 552 | 548 | .string => { |
| 553 | const string: Teg.SlicedString = s.frame.currentPayload(.string); | |
| 554 | return s.makeValueAir(.{ .string = string.slice(s.teg.string_bytes) }); | |
| 549 | const string: Hir.SlicedString = s.frame.currentPayload(.string); | |
| 550 | return s.makeValueAir(.{ .string = string.slice(s.hir.string_bytes) }); | |
| 555 | 551 | }, |
| 556 | 552 | .number => { |
| 557 | 553 | const number: store.Float = s.frame.currentPayload(.number); |
| ... | ... | @@ -565,7 +561,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 565 | 561 | .gt, |
| 566 | 562 | .eq, |
| 567 | 563 | => { |
| 568 | const bin: Teg.Bin = s.frame.currentPayload(tag); | |
| 564 | const bin: Hir.Bin = s.frame.currentPayload(tag); | |
| 569 | 565 | const op = @field(BinaryOp, @tagName(tag)); |
| 570 | 566 | |
| 571 | 567 | const lhs = s.getRef(bin.lhs, .marked); |
| ... | ... | @@ -600,7 +596,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 600 | 596 | }); |
| 601 | 597 | }, |
| 602 | 598 | .negate => { |
| 603 | const un: Teg.RefNode = s.frame.currentData(.negate); | |
| 599 | const un: Hir.RefNode = s.frame.currentData(.negate); | |
| 604 | 600 | |
| 605 | 601 | const operand = s.getRef(un.operand, .marked); |
| 606 | 602 | |
| ... | ... | @@ -622,7 +618,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 622 | 618 | return s.addRef(.negate, .{ .operand = operand }); |
| 623 | 619 | }, |
| 624 | 620 | .bool_not => { |
| 625 | const un: Teg.RefNode = s.frame.currentData(.bool_not); | |
| 621 | const un: Hir.RefNode = s.frame.currentData(.bool_not); | |
| 626 | 622 | |
| 627 | 623 | const operand = try s.getCoercedRef(s.lazyNode(.operand), un.operand, .bool, .marked); |
| 628 | 624 | |
| ... | ... | @@ -639,7 +635,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 639 | 635 | return s.addRef(.bool_not, .{ .operand = operand }); |
| 640 | 636 | }, |
| 641 | 637 | .struct_decl => { |
| 642 | const node: Teg.StructDecl = s.frame.currentPayload(.struct_decl); | |
| 638 | const node: Hir.StructDecl = s.frame.currentPayload(.struct_decl); | |
| 643 | 639 | |
| 644 | 640 | const scratch = try s.scratch.reserveMulti( |
| 645 | 641 | s.arena(), |
| ... | ... | @@ -649,12 +645,12 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 649 | 645 | defer scratch.deinit(); |
| 650 | 646 | |
| 651 | 647 | // Fill the first half with keys |
| 652 | for (scratch.items(.keys), node.keys(&s.teg)) |*dest, src| { | |
| 653 | dest.* = try s.ip.getOrPutString(s.gpa, src.slice(s.teg.string_bytes), .no_embedded_nulls); | |
| 648 | for (scratch.items(.keys), node.keys(&s.hir)) |*dest, src| { | |
| 649 | dest.* = try s.ip.getOrPutString(s.gpa, src.slice(s.hir.string_bytes), .no_embedded_nulls); | |
| 654 | 650 | } |
| 655 | 651 | |
| 656 | 652 | // Fill the second half with coerced values. |
| 657 | for (node.types(&s.teg), 0..) |ty, i| { | |
| 653 | for (node.types(&s.hir), 0..) |ty, i| { | |
| 658 | 654 | scratch.at(.types, i).* = try s.getType(s.lazyNode(.argument(@intCast(i))), ty); |
| 659 | 655 | } |
| 660 | 656 | |
| ... | ... | @@ -688,7 +684,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 688 | 684 | } }); |
| 689 | 685 | }, |
| 690 | 686 | .field => { |
| 691 | const field: Teg.Bin = s.frame.currentPayload(.field); | |
| 687 | const field: Hir.Bin = s.frame.currentPayload(.field); | |
| 692 | 688 | const lhs = s.getRef(field.lhs, .marked); |
| 693 | 689 | const lhs_type = s.typeOfRef(lhs); |
| 694 | 690 | |
| ... | ... | @@ -733,7 +729,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 733 | 729 | }); |
| 734 | 730 | }, |
| 735 | 731 | .call => { |
| 736 | const call: Teg.Call = s.frame.currentPayload(.call); | |
| 732 | const call: Hir.Call = s.frame.currentPayload(.call); | |
| 737 | 733 | const base = s.getRef(call.base, .marked); |
| 738 | 734 | const base_type = s.typeOfRef(base); |
| 739 | 735 | |
| ... | ... | @@ -759,7 +755,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 759 | 755 | } |
| 760 | 756 | |
| 761 | 757 | // validate function args |
| 762 | for (proto.param_types, call.args.slice(&s.teg), 0..) |param, arg, i| { | |
| 758 | for (proto.param_types, call.args.slice(&s.hir), 0..) |param, arg, i| { | |
| 763 | 759 | const ref = s.getRef(arg, .marked); |
| 764 | 760 | const coerced = try s.coerceRef( |
| 765 | 761 | s.lazyNode(.argument(@intCast(i))), |
| ... | ... | @@ -769,7 +765,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 769 | 765 | scratch[i] = coerced; |
| 770 | 766 | } |
| 771 | 767 | } else { |
| 772 | for (call.args.slice(&s.teg), 0..) |arg, i| { | |
| 768 | for (call.args.slice(&s.hir), 0..) |arg, i| { | |
| 773 | 769 | const ref = try s.ensureValueDefinedRepresentation( |
| 774 | 770 | s.lazyNode(.argument(@intCast(i))), |
| 775 | 771 | s.getRef(arg, .marked), |
| ... | ... | @@ -792,7 +788,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 792 | 788 | }); |
| 793 | 789 | }, |
| 794 | 790 | .array_init => { |
| 795 | const node: Teg.ArrayInit = s.frame.currentPayload(.array_init); | |
| 791 | const node: Hir.ArrayInit = s.frame.currentPayload(.array_init); | |
| 796 | 792 | |
| 797 | 793 | assert(node.list.len > 0 or node.type_hint.unwrap() != null); |
| 798 | 794 | |
| ... | ... | @@ -806,7 +802,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 806 | 802 | |
| 807 | 803 | var is_constant = true; |
| 808 | 804 | |
| 809 | for (node.list.slice(&s.teg), 0..) |item_teg_ref, i| { | |
| 805 | for (node.list.slice(&s.hir), 0..) |item_teg_ref, i| { | |
| 810 | 806 | const item = s.getRef(item_teg_ref, .marked); |
| 811 | 807 | const coerced = if (item_type) |ty| |
| 812 | 808 | try s.coerceRef(s.lazyNode(.argument(@intCast(i))), item, ty) |
| ... | ... | @@ -862,8 +858,8 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 862 | 858 | }); |
| 863 | 859 | }, |
| 864 | 860 | .store => { |
| 865 | const data: Teg.Store = s.frame.currentPayload(.store); | |
| 866 | assert(s.teg.instTag(data.memory) == .memory); // corrupt store instruction | |
| 861 | const data: Hir.Store = s.frame.currentPayload(.store); | |
| 862 | assert(s.hir.instTag(data.memory) == .memory); // corrupt store instruction | |
| 867 | 863 | |
| 868 | 864 | try s.ensureAtRuntime(s.lazyNode(.main_node)); // TODO |
| 869 | 865 | |
| ... | ... | @@ -885,7 +881,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 885 | 881 | }, |
| 886 | 882 | |
| 887 | 883 | .js_new => { |
| 888 | const call: Teg.JsNew = s.frame.currentPayload(.js_new); | |
| 884 | const call: Hir.JsNew = s.frame.currentPayload(.js_new); | |
| 889 | 885 | |
| 890 | 886 | try s.ensureAtRuntime(s.lazyNode(.main_node)); |
| 891 | 887 | |
| ... | ... | @@ -893,7 +889,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 893 | 889 | |
| 894 | 890 | const scratch = try s.arena().alloc(Air.Inst.Ref, call.args.len); |
| 895 | 891 | defer s.arena().free(scratch); |
| 896 | for (call.args.slice(&s.teg), 0..) |arg, i| { | |
| 892 | for (call.args.slice(&s.hir), 0..) |arg, i| { | |
| 897 | 893 | const ref = try s.ensureValueDefinedRepresentation( |
| 898 | 894 | s.lazyNode(.argument(@intCast(i))), |
| 899 | 895 | s.getRef(arg, .marked), |
| ... | ... | @@ -924,7 +920,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 924 | 920 | }, |
| 925 | 921 | |
| 926 | 922 | .func => { |
| 927 | const data: Teg.Func = s.frame.currentPayload(.func); | |
| 923 | const data: Hir.Func = s.frame.currentPayload(.func); | |
| 928 | 924 | const reserve = try s.scratch.reserveMulti( |
| 929 | 925 | s.arena(), |
| 930 | 926 | .{ .params = Type, .captures = Air.Inst.Ref }, |
| ... | ... | @@ -937,7 +933,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 937 | 933 | defer handled_reserve.assertUnlocked(); |
| 938 | 934 | errdefer handled_reserve.unlock(); |
| 939 | 935 | |
| 940 | for (data.params.slice(&s.teg), 0..) |param, i| { | |
| 936 | for (data.params.slice(&s.hir), 0..) |param, i| { | |
| 941 | 937 | const src = s.lazyNode(.argument(@intCast(i))); |
| 942 | 938 | |
| 943 | 939 | const known = param.unwrap() orelse @panic("TODO: inferred param sets"); |
| ... | ... | @@ -991,7 +987,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 991 | 987 | }, |
| 992 | 988 | |
| 993 | 989 | .@"break" => { |
| 994 | const brk: Teg.Break = s.frame.currentPayload(.@"break"); | |
| 990 | const brk: Hir.Break = s.frame.currentPayload(.@"break"); | |
| 995 | 991 | const operand = s.getRef(brk.operand, .marked); |
| 996 | 992 | |
| 997 | 993 | assert(s.frame.block_index == brk.block); |
| ... | ... | @@ -1036,7 +1032,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1036 | 1032 | s.frame.advance(); |
| 1037 | 1033 | }, |
| 1038 | 1034 | .@"if" => { |
| 1039 | const if_data: Teg.If = s.frame.currentPayload(.@"if"); | |
| 1035 | const if_data: Hir.If = s.frame.currentPayload(.@"if"); | |
| 1040 | 1036 | |
| 1041 | 1037 | switch (data.conditional) { |
| 1042 | 1038 | .comptime_condition => { |
| ... | ... | @@ -1093,7 +1089,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1093 | 1089 | s.frame.advance(); |
| 1094 | 1090 | }, |
| 1095 | 1091 | .func => { |
| 1096 | const func_data: Teg.Func = s.frame.currentPayload(.func); | |
| 1092 | const func_data: Hir.Func = s.frame.currentPayload(.func); | |
| 1097 | 1093 | |
| 1098 | 1094 | const reserve: FunctionReserve = .fromIndex( |
| 1099 | 1095 | &s.scratch, |
| ... | ... | @@ -1104,7 +1100,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1104 | 1100 | const return_type = switch (data.func) { |
| 1105 | 1101 | .argument => |arg_num| ret: { |
| 1106 | 1102 | for ( |
| 1107 | func_data.params.slice(&s.teg)[arg_num + 1 ..], | |
| 1103 | func_data.params.slice(&s.hir)[arg_num + 1 ..], | |
| 1108 | 1104 | reserve.items(.params)[arg_num + 1 ..], |
| 1109 | 1105 | arg_num + 1.., |
| 1110 | 1106 | ) |param, *dst, i| { |
| ... | ... | @@ -1172,10 +1168,10 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1172 | 1168 | }, |
| 1173 | 1169 | |
| 1174 | 1170 | .load_decl => { |
| 1175 | const request: Teg.StrNode = s.frame.currentData(.load_decl); | |
| 1171 | const request: Hir.StrNode = s.frame.currentData(.load_decl); | |
| 1176 | 1172 | const decl_name = try s.ip.getOrPutString( |
| 1177 | 1173 | s.gpa, |
| 1178 | request.string.slice(s.teg.string_bytes), | |
| 1174 | request.string.slice(s.hir.string_bytes), | |
| 1179 | 1175 | .no_embedded_nulls, |
| 1180 | 1176 | ); |
| 1181 | 1177 | const decl_index = s.lookupDecl(decl_name); |
| ... | ... | @@ -1183,13 +1179,13 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1183 | 1179 | }, |
| 1184 | 1180 | |
| 1185 | 1181 | .coercion => { |
| 1186 | const as: Teg.Coercion = s.frame.currentPayload(.coercion); | |
| 1182 | const as: Hir.Coercion = s.frame.currentPayload(.coercion); | |
| 1187 | 1183 | const coerce_to = try s.getType(s.lazyNode(.operand), as.type); |
| 1188 | 1184 | return try s.getCoercedRef(s.lazyNode(.operand), as.operand, coerce_to, .marked); |
| 1189 | 1185 | }, |
| 1190 | 1186 | |
| 1191 | 1187 | .compile_error => { |
| 1192 | const node: Teg.RefNode = s.frame.currentData(.compile_error); | |
| 1188 | const node: Hir.RefNode = s.frame.currentData(.compile_error); | |
| 1193 | 1189 | const value = try s.getCoercedValue(s.lazyNode(.operand), node.operand, .string); |
| 1194 | 1190 | const str = value.asString(s.ip).toSlice(s.ip); |
| 1195 | 1191 | return s.fail(.user_compile_error, .{ |
| ... | ... | @@ -1199,7 +1195,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1199 | 1195 | }, |
| 1200 | 1196 | |
| 1201 | 1197 | .@"if" => { |
| 1202 | const data: Teg.If = s.frame.currentPayload(.@"if"); | |
| 1198 | const data: Hir.If = s.frame.currentPayload(.@"if"); | |
| 1203 | 1199 | |
| 1204 | 1200 | const condition = try s.getCoercedRef(s.lazyNode(.operand), data.cond, .bool, .marked); |
| 1205 | 1201 | switch (condition.decode()) { |
| ... | ... | @@ -1270,7 +1266,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1270 | 1266 | }, |
| 1271 | 1267 | |
| 1272 | 1268 | .struct_init => { |
| 1273 | const node: Teg.StructInit = s.frame.currentPayload(.struct_init); | |
| 1269 | const node: Hir.StructInit = s.frame.currentPayload(.struct_init); | |
| 1274 | 1270 | |
| 1275 | 1271 | // Ensure we have a valid struct to operate on |
| 1276 | 1272 | const ty = try s.getType(s.lazyNode(.operand), node.base_type); |
| ... | ... | @@ -1295,9 +1291,9 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1295 | 1291 | // The ordering of `storage` is defined by the struct's type, which |
| 1296 | 1292 | // may be different than the instantiation. The fields are visited in |
| 1297 | 1293 | // order of the instantiation. |
| 1298 | for (node.keys(&s.teg), node.inits(&s.teg), 0..) |init_key, init_value, i| { | |
| 1294 | for (node.keys(&s.hir), node.inits(&s.hir), 0..) |init_key, init_value, i| { | |
| 1299 | 1295 | const found_index = index: for (struct_type.field_keys, 0..) |decl_key, j| { |
| 1300 | if (decl_key.eqlSlice(init_key.slice(s.teg.string_bytes), s.ip)) | |
| 1296 | if (decl_key.eqlSlice(init_key.slice(s.hir.string_bytes), s.ip)) | |
| 1301 | 1297 | break :index j; |
| 1302 | 1298 | } else { |
| 1303 | 1299 | has_errors = true; |
| ... | ... | @@ -1374,18 +1370,18 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1374 | 1370 | }, |
| 1375 | 1371 | |
| 1376 | 1372 | .array_type => { |
| 1377 | const un: Teg.RefNode = s.frame.currentData(.array_type); | |
| 1373 | const un: Hir.RefNode = s.frame.currentData(.array_type); | |
| 1378 | 1374 | const operand = try s.getType(s.lazyNode(.operand), un.operand); |
| 1379 | 1375 | return s.makeValueAir(.{ .array_type = .{ .item_type = operand } }); |
| 1380 | 1376 | }, |
| 1381 | 1377 | |
| 1382 | 1378 | .tuple_type => { |
| 1383 | const data: Teg.TupleType = s.frame.currentPayload(.tuple_type); | |
| 1379 | const data: Hir.TupleType = s.frame.currentPayload(.tuple_type); | |
| 1384 | 1380 | |
| 1385 | 1381 | const scratch = try s.scratch.reserve(s.arena(), Type, data.items.len); |
| 1386 | 1382 | defer scratch.deinit(); |
| 1387 | 1383 | |
| 1388 | for (data.items.slice(&s.teg), scratch.slice(), 0..) |src, *dst, i| { | |
| 1384 | for (data.items.slice(&s.hir), scratch.slice(), 0..) |src, *dst, i| { | |
| 1389 | 1385 | dst.* = try s.getType(s.lazyNode(.argument(@intCast(i))), src); |
| 1390 | 1386 | } |
| 1391 | 1387 | |
| ... | ... | @@ -1393,7 +1389,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1393 | 1389 | }, |
| 1394 | 1390 | |
| 1395 | 1391 | .tuple_init => { |
| 1396 | const data: Teg.TupleInit = s.frame.currentPayload(.tuple_init); | |
| 1392 | const data: Hir.TupleInit = s.frame.currentPayload(.tuple_init); | |
| 1397 | 1393 | |
| 1398 | 1394 | _ = data.type_hint; // TODO: use type hint |
| 1399 | 1395 | |
| ... | ... | @@ -1401,7 +1397,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1401 | 1397 | defer scratch.deinit(); |
| 1402 | 1398 | |
| 1403 | 1399 | var is_const = true; |
| 1404 | for (data.items.slice(&s.teg), scratch.slice()) |src, *dst| { | |
| 1400 | for (data.items.slice(&s.hir), scratch.slice()) |src, *dst| { | |
| 1405 | 1401 | const result = s.getRef(src, .marked); |
| 1406 | 1402 | dst.* = result; |
| 1407 | 1403 | if (result.kind == .index) is_const = false; |
| ... | ... | @@ -1447,7 +1443,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1447 | 1443 | }, |
| 1448 | 1444 | |
| 1449 | 1445 | .result_type_argument => { |
| 1450 | const result: Teg.ResultTypeArgument = s.frame.currentData(.result_type_argument); | |
| 1446 | const result: Hir.ResultTypeArgument = s.frame.currentData(.result_type_argument); | |
| 1451 | 1447 | |
| 1452 | 1448 | const operand = s.getRef(result.call_base, .no_mark); |
| 1453 | 1449 | const ty = s.typeOfRef(operand); |
| ... | ... | @@ -1462,7 +1458,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1462 | 1458 | }, |
| 1463 | 1459 | |
| 1464 | 1460 | .result_type_array_value => { |
| 1465 | const result: Teg.ResultTypeArrayValue = s.frame.currentData(.result_type_array_value); | |
| 1461 | const result: Hir.ResultTypeArrayValue = s.frame.currentData(.result_type_array_value); | |
| 1466 | 1462 | |
| 1467 | 1463 | const operand = try s.getValue(s.lazyNode(.main_node), result.type); |
| 1468 | 1464 | const ty = operand.toType(s.ip) orelse |
| ... | ... | @@ -1475,7 +1471,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1475 | 1471 | }, |
| 1476 | 1472 | |
| 1477 | 1473 | .result_type_tuple_field => { |
| 1478 | const result: Teg.ResultTypeTupleField = s.frame.currentData(.result_type_tuple_field); | |
| 1474 | const result: Hir.ResultTypeTupleField = s.frame.currentData(.result_type_tuple_field); | |
| 1479 | 1475 | |
| 1480 | 1476 | const operand = try s.getValue(s.lazyNode(.main_node), result.type); |
| 1481 | 1477 | const ty = operand.toType(s.ip) orelse |
| ... | ... | @@ -1487,7 +1483,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1487 | 1483 | }, |
| 1488 | 1484 | |
| 1489 | 1485 | .result_type_struct_field => { |
| 1490 | const result: Teg.ResultTypeStructField = s.frame.currentData(.result_type_struct_field); | |
| 1486 | const result: Hir.ResultTypeStructField = s.frame.currentData(.result_type_struct_field); | |
| 1491 | 1487 | |
| 1492 | 1488 | const operand = try s.getValue(s.lazyNode(.main_node), result.type); |
| 1493 | 1489 | const ty = operand.toType(s.ip) orelse |
| ... | ... | @@ -1496,7 +1492,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1496 | 1492 | const struct_type = ty.toStructType(s.ip) orelse |
| 1497 | 1493 | return Value.opaque_type.toAir(); |
| 1498 | 1494 | |
| 1499 | const to_match = result.field.slice(s.teg.string_bytes); | |
| 1495 | const to_match = result.field.slice(s.hir.string_bytes); | |
| 1500 | 1496 | for (struct_type.field_keys, struct_type.field_types) |k, v| { |
| 1501 | 1497 | if (k.eqlSlice(to_match, s.ip)) { |
| 1502 | 1498 | return v.value().toAir(); |
| ... | ... | @@ -1512,7 +1508,7 @@ fn stepInner(s: *Sema, comptime tag: Teg.Tag) Error!InstructionKind.fromTag(tag) |
| 1512 | 1508 | |
| 1513 | 1509 | fn emitRuntimeBlock( |
| 1514 | 1510 | s: *Sema, |
| 1515 | from: Teg.Inst.Index, | |
| 1511 | from: Hir.Inst.Index, | |
| 1516 | 1512 | break_operand: Air.Inst.Ref, |
| 1517 | 1513 | mark: core.U32Stack.Mark, |
| 1518 | 1514 | ) !void { |
| ... | ... | @@ -1553,7 +1549,7 @@ const BinaryOp = enum { |
| 1553 | 1549 | eq, |
| 1554 | 1550 | }; |
| 1555 | 1551 | |
| 1556 | fn binTypeResolution(s: *Sema, src: Teg.Inst.Index, op: BinaryOp, lhs: Type, rhs: Type) !Type { | |
| 1552 | fn binTypeResolution(s: *Sema, src: Hir.Inst.Index, op: BinaryOp, lhs: Type, rhs: Type) !Type { | |
| 1557 | 1553 | if (lhs == .@"opaque") { |
| 1558 | 1554 | return if (rhs == .numeric_literal) .float else rhs; |
| 1559 | 1555 | } |
| ... | ... | @@ -2084,7 +2080,7 @@ fn fieldAccessStruct( |
| 2084 | 2080 | lhs: Air.Inst.Ref, |
| 2085 | 2081 | lhs_type: Type, |
| 2086 | 2082 | struct_type: InternPool.Key.StructType, |
| 2087 | field: Teg.Inst.Ref, | |
| 2083 | field: Hir.Inst.Ref, | |
| 2088 | 2084 | ) !Air.Inst.Ref { |
| 2089 | 2085 | const rhs = try s.getCoercedValue(s.lazyNode(.rhs), field, .string); |
| 2090 | 2086 | const string = rhs.asString(s.ip); |
| ... | ... | @@ -2125,7 +2121,7 @@ fn fieldAccessStruct( |
| 2125 | 2121 | } |
| 2126 | 2122 | } |
| 2127 | 2123 | |
| 2128 | fn fieldAccessArray(s: *Sema, lhs: Air.Inst.Ref, lhs_type: Type, rhs_teg: Teg.Inst.Ref) !Air.Inst.Ref { | |
| 2124 | fn fieldAccessArray(s: *Sema, lhs: Air.Inst.Ref, lhs_type: Type, rhs_teg: Hir.Inst.Ref) !Air.Inst.Ref { | |
| 2129 | 2125 | const rhs = s.getRef(rhs_teg, .marked); |
| 2130 | 2126 | |
| 2131 | 2127 | switch (s.typeOfRef(rhs)) { |
| ... | ... | @@ -2176,7 +2172,7 @@ fn fieldAccessTuple( |
| 2176 | 2172 | lhs: Air.Inst.Ref, |
| 2177 | 2173 | lhs_type: Type, |
| 2178 | 2174 | tuple_type: InternPool.Key.TupleType, |
| 2179 | field: Teg.Inst.Ref, | |
| 2175 | field: Hir.Inst.Ref, | |
| 2180 | 2176 | ) !Air.Inst.Ref { |
| 2181 | 2177 | const index_value = try s.getCoercedValue(s.lazyNode(.rhs), field, .int32); |
| 2182 | 2178 | const index_signed = index_value.toInt32(s.ip) orelse unreachable; |
| ... | ... | @@ -2387,7 +2383,7 @@ const File = Comp.File; |
| 2387 | 2383 | const Decl = Comp.Decl; |
| 2388 | 2384 | const Namespace = Comp.Namespace; |
| 2389 | 2385 | |
| 2390 | const Teg = core.Teg; | |
| 2386 | const Hir = core.Hir; | |
| 2391 | 2387 | |
| 2392 | 2388 | const Air = core.Air; |
| 2393 | 2389 | const Ast = core.Ast; |
src/core/StoredTrace.zig+3-3| ... | ... | @@ -1,6 +1,6 @@ |
| 1 | //! A variant of std.builtin.StackTrace that stores its data within itself | |
| 2 | //! instead of being a pointer. This allows capturing the stack trace and | |
| 3 | //! saving it for later printing. | |
| 1 | //! A variant of `std.builtin.StackTrace` that stores its data within itself | |
| 2 | //! instead of being a pointer. This allows storing captured stack traces | |
| 3 | //! for later printing. | |
| 4 | 4 | |
| 5 | 5 | data: [31]usize, |
| 6 | 6 | index: usize, |
src/core/Teg.Dump.zig deleted-522| ... | ... | @@ -1,522 +0,0 @@ |
| 1 | //! This implements a debug formatter for Teg | |
| 2 | teg: Teg, | |
| 3 | tty: ?std.io.tty.Config = null, | |
| 4 | ||
| 5 | const State = struct { | |
| 6 | arena: std.mem.Allocator, | |
| 7 | teg: *const Teg, | |
| 8 | indent: usize = 0, | |
| 9 | tty: std.io.tty.Config, | |
| 10 | visited: std.AutoHashMapUnmanaged(Teg.Inst.Index, void) = .{}, | |
| 11 | ||
| 12 | fn newline(state: State, writer: anytype) !void { | |
| 13 | try writer.writeByte('\n'); | |
| 14 | if (state.indent > 0) | |
| 15 | try writer.writeByteNTimes(' ', state.indent * 2); | |
| 16 | } | |
| 17 | ||
| 18 | fn dumpInst(s: *State, writer: anytype, inst: Teg.Inst.Index) @TypeOf(writer).Error!void { | |
| 19 | const teg = s.teg; | |
| 20 | const tty = s.tty; | |
| 21 | ||
| 22 | try writer.print("%{} = ", .{@intFromEnum(inst)}); | |
| 23 | ||
| 24 | const tag = s.teg.instTag(inst); | |
| 25 | ||
| 26 | try tty.setColor(writer, .bright_black); | |
| 27 | const node_offset = teg.instNodeOffset(inst); | |
| 28 | try writer.print("{c}{d} ", .{ | |
| 29 | @as(u8, if (node_offset >= 0) '+' else '-'), | |
| 30 | @abs(node_offset), | |
| 31 | }); | |
| 32 | try tty.setColor(writer, .reset); | |
| 33 | ||
| 34 | try tty.setColor(writer, .cyan); | |
| 35 | try writer.print("{s}", .{@tagName(tag)}); | |
| 36 | try tty.setColor(writer, .reset); | |
| 37 | ||
| 38 | if ((try s.visited.fetchPut(s.arena, inst, {})) != null) { | |
| 39 | try tty.setColor(writer, .red); | |
| 40 | try writer.writeAll(" [error: recursive tree]"); | |
| 41 | try tty.setColor(writer, .reset); | |
| 42 | return; | |
| 43 | } | |
| 44 | ||
| 45 | switch (tag) { | |
| 46 | .module => { | |
| 47 | try s.dumpInstList(writer, teg.moduleDeclarations(inst), '{', '}'); | |
| 48 | }, | |
| 49 | .declaration, .variable_declaration, .test_declaration => { | |
| 50 | const decl = teg.fullDecl(inst); | |
| 51 | ||
| 52 | try writer.writeAll(" "); | |
| 53 | const name = decl.name.slice(teg.string_bytes); | |
| 54 | if (name.len == 0) { | |
| 55 | try tty.setColor(writer, .bold); | |
| 56 | try writer.writeAll("[no name]"); | |
| 57 | } else { | |
| 58 | try tty.setColor(writer, .magenta); | |
| 59 | try writer.writeAll(name); | |
| 60 | } | |
| 61 | try tty.setColor(writer, .reset); | |
| 62 | try writer.writeAll(" ("); | |
| 63 | try writer.print("{d}", .{decl.instruction_count}); | |
| 64 | try writer.writeAll(")"); | |
| 65 | try tty.setColor(writer, .bright_black); | |
| 66 | try writer.writeAll(" ["); | |
| 67 | try writer.writeAll(&std.fmt.bytesToHex(decl.hash, .lower)); | |
| 68 | try writer.writeAll("]"); | |
| 69 | try tty.setColor(writer, .reset); | |
| 70 | try writer.writeAll(" ("); | |
| 71 | s.indent += 1; | |
| 72 | try s.newline(writer); | |
| 73 | try s.dumpRef(writer, decl.body); | |
| 74 | s.indent -= 1; | |
| 75 | try s.newline(writer); | |
| 76 | try writer.writeAll(")"); | |
| 77 | }, | |
| 78 | .func => { | |
| 79 | const func: Teg.Func = teg.instPayload(.func, inst); | |
| 80 | try writer.writeAll(" {"); | |
| 81 | s.indent += 1; | |
| 82 | try s.newline(writer); | |
| 83 | try writer.writeAll("params: "); | |
| 84 | try s.dumpOptionalRefList(writer, func.params.slice(teg), '[', ']'); | |
| 85 | try s.newline(writer); | |
| 86 | try writer.writeAll("return_type: "); | |
| 87 | if (func.return_type.unwrap()) |ret| | |
| 88 | try s.dumpRef(writer, ret) | |
| 89 | else { | |
| 90 | try tty.setColor(writer, .bright_black); | |
| 91 | try writer.writeAll("<inferred>"); | |
| 92 | try tty.setColor(writer, .reset); | |
| 93 | } | |
| 94 | try s.newline(writer); | |
| 95 | try writer.writeAll("captures: "); | |
| 96 | try s.dumpInstList2(writer, func.captures.slice(teg), '[', ']'); | |
| 97 | try s.newline(writer); | |
| 98 | try writer.writeAll("body: "); | |
| 99 | try s.dumpInst(writer, func.body); | |
| 100 | s.indent -= 1; | |
| 101 | try s.newline(writer); | |
| 102 | try writer.writeAll("}"); | |
| 103 | }, | |
| 104 | .param => { | |
| 105 | const data = teg.instData(.param, inst); | |
| 106 | try writer.writeAll("("); | |
| 107 | if (data.data == std.math.maxInt(u32)) { | |
| 108 | try tty.setColor(writer, .bright_black); | |
| 109 | try writer.writeAll("<return type>"); | |
| 110 | } else { | |
| 111 | try tty.setColor(writer, .yellow); | |
| 112 | try writer.print("{d}", .{data.data}); | |
| 113 | } | |
| 114 | try tty.setColor(writer, .reset); | |
| 115 | try writer.writeAll(")"); | |
| 116 | }, | |
| 117 | inline .block, .@"comptime" => |t| { | |
| 118 | const block = teg.instData(t, inst); | |
| 119 | const index_list = block.extra_index.get(teg); | |
| 120 | try s.dumpInstList(writer, index_list.slice(teg), '[', ']'); | |
| 121 | }, | |
| 122 | .number => { | |
| 123 | const number = teg.instData(.number, inst); | |
| 124 | const float = number.extra_index.get(teg).decode(); | |
| 125 | try tty.setColor(writer, .yellow); | |
| 126 | try writer.print(" {d}", .{float}); | |
| 127 | try tty.setColor(writer, .reset); | |
| 128 | }, | |
| 129 | inline .field, | |
| 130 | .index, | |
| 131 | .add, | |
| 132 | .sub, | |
| 133 | .mul, | |
| 134 | .div, | |
| 135 | .rem, | |
| 136 | .pow, | |
| 137 | .@"and", | |
| 138 | .@"or", | |
| 139 | .bit_and, | |
| 140 | .bit_or, | |
| 141 | .bit_xor, | |
| 142 | .shl, | |
| 143 | .shr, | |
| 144 | .eq, | |
| 145 | .ne, | |
| 146 | .lt, | |
| 147 | .le, | |
| 148 | .gt, | |
| 149 | .ge, | |
| 150 | => |comptime_tag| { | |
| 151 | const data = teg.instData(comptime_tag, inst).extra_index.get(teg); | |
| 152 | try writer.writeAll("("); | |
| 153 | try s.dumpRefMarker(writer, data.lhs); | |
| 154 | try writer.writeAll(", "); | |
| 155 | try s.dumpRefMarker(writer, data.rhs); | |
| 156 | try writer.writeAll(")"); | |
| 157 | }, | |
| 158 | .coercion => { | |
| 159 | const data = teg.instData(.coercion, inst).extra_index.get(teg); | |
| 160 | try writer.writeAll("("); | |
| 161 | try s.dumpRefMarker(writer, data.type); | |
| 162 | try writer.writeAll(", "); | |
| 163 | try s.dumpRefMarker(writer, data.operand); | |
| 164 | try writer.writeAll(")"); | |
| 165 | }, | |
| 166 | .@"break" => { | |
| 167 | const data: Teg.Break = teg.instData(.@"break", inst).extra_index.get(teg); | |
| 168 | try writer.writeAll("("); | |
| 169 | try s.dumpRefMarker(writer, data.block.toRef()); | |
| 170 | try writer.writeAll(", "); | |
| 171 | try s.dumpRefMarker(writer, data.operand); | |
| 172 | try writer.writeAll(")"); | |
| 173 | }, | |
| 174 | .store => { | |
| 175 | const data: Teg.Store = teg.instData(.store, inst).extra_index.get(teg); | |
| 176 | try writer.writeAll("("); | |
| 177 | try s.dumpRefMarker(writer, data.memory.toRef()); | |
| 178 | try writer.writeAll(", "); | |
| 179 | try s.dumpRefMarker(writer, data.operand); | |
| 180 | try writer.writeAll(")"); | |
| 181 | }, | |
| 182 | .store_field => { | |
| 183 | const data: Teg.StoreField = teg.instData(.store_field, inst).extra_index.get(teg); | |
| 184 | try writer.writeAll("("); | |
| 185 | try s.dumpRefMarker(writer, data.base); | |
| 186 | try writer.writeAll(", "); | |
| 187 | try s.dumpRefMarker(writer, data.field); | |
| 188 | try writer.writeAll(", "); | |
| 189 | try s.dumpRefMarker(writer, data.operand); | |
| 190 | try writer.writeAll(")"); | |
| 191 | }, | |
| 192 | .store_decl => { | |
| 193 | const data: Teg.StoreVarDecl = teg.instData(.store_decl, inst).extra_index.get(teg); | |
| 194 | try writer.writeAll("("); | |
| 195 | try tty.setColor(writer, .magenta); | |
| 196 | try writer.writeAll(data.var_decl.slice(teg.string_bytes)); | |
| 197 | try tty.setColor(writer, .reset); | |
| 198 | try writer.writeAll(", "); | |
| 199 | try s.dumpRefMarker(writer, data.operand); | |
| 200 | try writer.writeAll(")"); | |
| 201 | }, | |
| 202 | .string => { | |
| 203 | const data: Teg.SlicedString = teg.instData(.string, inst).extra_index.get(teg); | |
| 204 | try tty.setColor(writer, .green); | |
| 205 | try writer.writeAll(" \""); | |
| 206 | try writer.writeAll(data.slice(teg.string_bytes)); | |
| 207 | try writer.writeAll("\""); | |
| 208 | try tty.setColor(writer, .reset); | |
| 209 | }, | |
| 210 | inline .memory, | |
| 211 | .discard, | |
| 212 | .ensure_void, | |
| 213 | .negate, | |
| 214 | .bool_not, | |
| 215 | .bit_not, | |
| 216 | .@"extern", | |
| 217 | .import, | |
| 218 | .fetch, | |
| 219 | .compile_error, | |
| 220 | .type_of, | |
| 221 | .array_type, | |
| 222 | .assert, | |
| 223 | => |comptime_tag| { | |
| 224 | const data = teg.instData(comptime_tag, inst); | |
| 225 | try writer.writeAll("("); | |
| 226 | try s.dumpRefMarker(writer, data.operand); | |
| 227 | try writer.writeAll(")"); | |
| 228 | }, | |
| 229 | .call => { | |
| 230 | const call: Teg.Call = teg.instData(.call, inst).extra_index.get(teg); | |
| 231 | try writer.writeAll("("); | |
| 232 | try s.dumpRefMarker(writer, call.base); | |
| 233 | try writer.writeAll(", "); | |
| 234 | try s.dumpRefMarkerList(writer, call.args.slice(teg), '[', ']'); | |
| 235 | try writer.writeAll(")"); | |
| 236 | }, | |
| 237 | .js_new => { | |
| 238 | const call: Teg.JsNew = teg.instData(.js_new, inst).extra_index.get(teg); | |
| 239 | try writer.writeAll("("); | |
| 240 | try s.dumpRefMarker(writer, call.base); | |
| 241 | try writer.writeAll(", "); | |
| 242 | try s.dumpRefMarkerList(writer, call.args.slice(teg), '[', ']'); | |
| 243 | try writer.writeAll(")"); | |
| 244 | }, | |
| 245 | .load_decl => { | |
| 246 | const call: Teg.StrNode = teg.instData(.load_decl, inst); | |
| 247 | ||
| 248 | try tty.setColor(writer, .red); | |
| 249 | try writer.print(" {s}", .{call.string.slice(teg.string_bytes)}); | |
| 250 | try tty.setColor(writer, .reset); | |
| 251 | }, | |
| 252 | .@"if" => { | |
| 253 | const data: Teg.If = teg.instPayload(.@"if", inst); | |
| 254 | try writer.writeAll("("); | |
| 255 | try s.dumpRefMarker(writer, data.cond); | |
| 256 | try writer.writeAll(") {"); | |
| 257 | s.indent += 1; | |
| 258 | try s.newline(writer); | |
| 259 | try writer.writeAll("yes: "); | |
| 260 | try s.dumpRef(writer, data.yes); | |
| 261 | try s.newline(writer); | |
| 262 | try writer.writeAll("no: "); | |
| 263 | try s.dumpRef(writer, data.no); | |
| 264 | s.indent -= 1; | |
| 265 | try s.newline(writer); | |
| 266 | try writer.writeAll("}"); | |
| 267 | }, | |
| 268 | .struct_decl => { | |
| 269 | const data: Teg.StructDecl = teg.instPayload(.struct_decl, inst); | |
| 270 | try writer.writeAll(" {"); | |
| 271 | s.indent += 1; | |
| 272 | try s.newline(writer); | |
| 273 | for (data.keys(teg), data.types(teg), 0..) |key, value, i| { | |
| 274 | if (i != 0) | |
| 275 | try s.newline(writer); | |
| 276 | try writer.print("{s}: ", .{key.slice(teg.string_bytes)}); | |
| 277 | try s.dumpRefMarker(writer, value); | |
| 278 | } | |
| 279 | s.indent -= 1; | |
| 280 | try s.newline(writer); | |
| 281 | try writer.writeAll("}"); | |
| 282 | }, | |
| 283 | .struct_init => { | |
| 284 | const data: Teg.StructInit = teg.instPayload(.struct_init, inst); | |
| 285 | try writer.writeAll("("); | |
| 286 | try s.dumpRefMarker(writer, data.base_type); | |
| 287 | try writer.writeAll(") {"); | |
| 288 | s.indent += 1; | |
| 289 | try s.newline(writer); | |
| 290 | for (data.keys(teg), data.inits(teg), 0..) |key, value, i| { | |
| 291 | if (i != 0) | |
| 292 | try s.newline(writer); | |
| 293 | try writer.print("{s}: ", .{key.slice(teg.string_bytes)}); | |
| 294 | try s.dumpRefMarker(writer, value); | |
| 295 | } | |
| 296 | s.indent -= 1; | |
| 297 | try s.newline(writer); | |
| 298 | try writer.writeAll("}"); | |
| 299 | }, | |
| 300 | .array_init => { | |
| 301 | const data: Teg.ArrayInit = teg.instPayload(.array_init, inst); | |
| 302 | ||
| 303 | if (data.type_hint.unwrap()) |type_hint| { | |
| 304 | try writer.writeAll("("); | |
| 305 | try s.dumpRef(writer, type_hint); | |
| 306 | try writer.writeAll(", "); | |
| 307 | } | |
| 308 | ||
| 309 | try writer.writeAll("["); | |
| 310 | ||
| 311 | s.indent += 1; | |
| 312 | ||
| 313 | for (data.list.slice(teg)) |item| { | |
| 314 | try s.newline(writer); | |
| 315 | try s.dumpRefMarker(writer, item); | |
| 316 | try writer.writeAll(","); | |
| 317 | } | |
| 318 | ||
| 319 | s.indent -= 1; | |
| 320 | try s.newline(writer); | |
| 321 | ||
| 322 | try writer.writeAll("]"); | |
| 323 | ||
| 324 | if (data.type_hint != .none) | |
| 325 | try writer.writeAll(")"); | |
| 326 | }, | |
| 327 | .tuple_type => { | |
| 328 | const data: Teg.TupleType = teg.instPayload(.tuple_type, inst); | |
| 329 | ||
| 330 | try writer.writeAll("("); | |
| 331 | try s.dumpRefMarkerList(writer, data.items.slice(teg), '[', ']'); | |
| 332 | try writer.writeAll(")"); | |
| 333 | }, | |
| 334 | .tuple_init => { | |
| 335 | const data: Teg.TupleInit = teg.instPayload(.tuple_init, inst); | |
| 336 | ||
| 337 | try writer.writeAll("("); | |
| 338 | if (data.type_hint.unwrap()) |type_hint| { | |
| 339 | try s.dumpRef(writer, type_hint); | |
| 340 | try writer.writeAll(", "); | |
| 341 | } | |
| 342 | try s.dumpRefMarkerList(writer, data.items.slice(teg), '[', ']'); | |
| 343 | try writer.writeAll(")"); | |
| 344 | }, | |
| 345 | .result_type_argument => { | |
| 346 | const data: Teg.ResultTypeArgument = teg.instData(.result_type_argument, inst); | |
| 347 | ||
| 348 | try writer.writeAll("("); | |
| 349 | try s.dumpRefMarker(writer, data.call_base); | |
| 350 | try writer.print(", {d}", .{data.argument}); | |
| 351 | try writer.writeAll(")"); | |
| 352 | }, | |
| 353 | .result_type_struct_field => { | |
| 354 | const data: Teg.ResultTypeStructField = teg.instData(.result_type_struct_field, inst); | |
| 355 | ||
| 356 | try writer.writeAll("("); | |
| 357 | try s.dumpRefMarker(writer, data.type); | |
| 358 | try writer.print(", {s}", .{data.field.slice(s.teg.string_bytes)}); | |
| 359 | try writer.writeAll(")"); | |
| 360 | }, | |
| 361 | .result_type_tuple_field => { | |
| 362 | const data: Teg.ResultTypeTupleField = teg.instData(.result_type_tuple_field, inst); | |
| 363 | ||
| 364 | try writer.writeAll("("); | |
| 365 | try s.dumpRefMarker(writer, data.type); | |
| 366 | try writer.print(", {d}", .{data.item}); | |
| 367 | try writer.writeAll(")"); | |
| 368 | }, | |
| 369 | .result_type_array_value => { | |
| 370 | const data: Teg.ResultTypeArrayValue = teg.instData(.result_type_array_value, inst); | |
| 371 | ||
| 372 | try writer.writeAll("("); | |
| 373 | try s.dumpRefMarker(writer, data.type); | |
| 374 | try writer.writeAll(")"); | |
| 375 | }, | |
| 376 | } | |
| 377 | } | |
| 378 | ||
| 379 | fn dumpRef(s: *State, writer: anytype, ref: Teg.Inst.Ref) !void { | |
| 380 | switch (ref.decode()) { | |
| 381 | .index => |index| try s.dumpInst(writer, index), | |
| 382 | .value => { | |
| 383 | try s.tty.setColor(writer, .blue); | |
| 384 | try writer.print("%{s}", .{@tagName(ref)}); | |
| 385 | try s.tty.setColor(writer, .reset); | |
| 386 | }, | |
| 387 | } | |
| 388 | } | |
| 389 | ||
| 390 | fn dumpRefMarker(s: *State, writer: anytype, ref: Teg.Inst.Ref) !void { | |
| 391 | switch (ref.decode()) { | |
| 392 | .index => |index| { | |
| 393 | try s.tty.setColor(writer, .blue); | |
| 394 | try writer.print("%{d}", .{@intFromEnum(index)}); | |
| 395 | try s.tty.setColor(writer, .reset); | |
| 396 | }, | |
| 397 | .value => { | |
| 398 | try s.tty.setColor(writer, .blue); | |
| 399 | try writer.print("%{s}", .{@tagName(ref)}); | |
| 400 | try s.tty.setColor(writer, .reset); | |
| 401 | }, | |
| 402 | } | |
| 403 | } | |
| 404 | ||
| 405 | fn dumpInstList(state: *State, writer: anytype, list: []const Teg.Inst.Index, l: u8, r: u8) !void { | |
| 406 | try writer.print(" {c}", .{l}); | |
| 407 | if (list.len > 0) { | |
| 408 | state.indent += 1; | |
| 409 | ||
| 410 | for (list) |inst| { | |
| 411 | try state.newline(writer); | |
| 412 | try state.dumpInst(writer, inst); | |
| 413 | } | |
| 414 | ||
| 415 | state.indent -= 1; | |
| 416 | try state.newline(writer); | |
| 417 | } | |
| 418 | try writer.print("{c}", .{r}); | |
| 419 | } | |
| 420 | ||
| 421 | fn dumpInstList2(state: *State, writer: anytype, list: []const Teg.Inst.Index, l: u8, r: u8) !void { | |
| 422 | try writer.print(" {c}", .{l}); | |
| 423 | if (list.len > 0) { | |
| 424 | state.indent += 1; | |
| 425 | ||
| 426 | for (list) |inst| { | |
| 427 | try state.newline(writer); | |
| 428 | try state.dumpRefMarker(writer, inst.toRef()); | |
| 429 | } | |
| 430 | ||
| 431 | state.indent -= 1; | |
| 432 | try state.newline(writer); | |
| 433 | } | |
| 434 | try writer.print("{c}", .{r}); | |
| 435 | } | |
| 436 | ||
| 437 | fn dumpRefList(state: *State, writer: anytype, list: []const Teg.Inst.Ref, l: u8, r: u8) !void { | |
| 438 | try writer.print(" {c}", .{l}); | |
| 439 | if (list.len > 0) { | |
| 440 | state.indent += 1; | |
| 441 | ||
| 442 | for (list) |ref| { | |
| 443 | try state.newline(writer); | |
| 444 | try state.dumpRef(writer, ref); | |
| 445 | } | |
| 446 | ||
| 447 | state.indent -= 1; | |
| 448 | ||
| 449 | try state.newline(writer); | |
| 450 | } | |
| 451 | try writer.print("{c}", .{r}); | |
| 452 | } | |
| 453 | ||
| 454 | fn dumpOptionalRefList(state: *State, writer: anytype, list: []const Teg.Inst.Ref.Optional, l: u8, r: u8) !void { | |
| 455 | try writer.print(" {c}", .{l}); | |
| 456 | if (list.len > 0) { | |
| 457 | state.indent += 1; | |
| 458 | ||
| 459 | for (list) |optional_ref| { | |
| 460 | try state.newline(writer); | |
| 461 | if (optional_ref.unwrap()) |ref| | |
| 462 | try state.dumpRef(writer, ref) | |
| 463 | else { | |
| 464 | try state.tty.setColor(writer, .bright_black); | |
| 465 | try writer.writeAll("<inferred>"); | |
| 466 | try state.tty.setColor(writer, .reset); | |
| 467 | } | |
| 468 | } | |
| 469 | ||
| 470 | state.indent -= 1; | |
| 471 | ||
| 472 | try state.newline(writer); | |
| 473 | } | |
| 474 | try writer.print("{c}", .{r}); | |
| 475 | } | |
| 476 | ||
| 477 | fn dumpRefMarkerList(state: *State, writer: anytype, list: []const Teg.Inst.Ref, l: u8, r: u8) !void { | |
| 478 | try writer.print("{c}", .{l}); | |
| 479 | if (list.len > 0) { | |
| 480 | state.indent += 1; | |
| 481 | ||
| 482 | for (list) |ref| { | |
| 483 | try state.newline(writer); | |
| 484 | try state.dumpRefMarker(writer, ref); | |
| 485 | } | |
| 486 | ||
| 487 | state.indent -= 1; | |
| 488 | ||
| 489 | try state.newline(writer); | |
| 490 | } | |
| 491 | try writer.print("{c}", .{r}); | |
| 492 | } | |
| 493 | }; | |
| 494 | ||
| 495 | pub fn format( | |
| 496 | dump: @This(), | |
| 497 | comptime unused_fmt: []const u8, | |
| 498 | _: std.fmt.FormatOptions, | |
| 499 | writer: anytype, | |
| 500 | ) !void { | |
| 501 | comptime assert(unused_fmt.len == 0); | |
| 502 | ||
| 503 | var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator); | |
| 504 | defer arena.deinit(); | |
| 505 | ||
| 506 | const teg = dump.teg; | |
| 507 | var state = State{ | |
| 508 | .teg = &teg, | |
| 509 | .tty = dump.tty orelse detectTTYFromWriter(writer), | |
| 510 | .arena = arena.allocator(), | |
| 511 | }; | |
| 512 | try state.dumpInst(writer, .main_module_inst); | |
| 513 | try writer.writeAll("\n"); | |
| 514 | assert(state.indent == 0); | |
| 515 | } | |
| 516 | ||
| 517 | const std = @import("std"); | |
| 518 | const assert = std.debug.assert; | |
| 519 | ||
| 520 | const core = @import("mod.zig"); | |
| 521 | const Teg = core.Teg; | |
| 522 | const detectTTYFromWriter = core.detectTTYFromWriter; |
src/core/Teg.zig deleted-1006| ... | ... | @@ -1,1006 +0,0 @@ |
| 1 | //! TODO: rename this to EIR (expression intermediate representation) | |
| 2 | ||
| 3 | insts: Inst.List.Slice, | |
| 4 | string_bytes: []const u8, | |
| 5 | extra: ExtraStore = .{}, | |
| 6 | report: Report, | |
| 7 | ||
| 8 | pub const ExtraStore = dod.ExtraStore(.teg, .@"const"); | |
| 9 | pub const EncodedData = dod.EncodedData(Tag, u64); | |
| 10 | pub const ExtraIndex = ExtraStore.Index; | |
| 11 | pub const Dump = @import("Teg.Dump.zig"); | |
| 12 | ||
| 13 | pub const Tag = enum(u8) { | |
| 14 | /// Either the top level module or a `module` keyword. Contains a list of `.declarations` | |
| 15 | /// Every analyzed module gets a `Comp.Namespace` | |
| 16 | module, | |
| 17 | /// Smallest unit of re-compilation. Every analyzed declaration gets a `Comp.Decl` | |
| 18 | declaration, | |
| 19 | /// Top-level memory location | |
| 20 | variable_declaration, | |
| 21 | /// Test declaration | |
| 22 | test_declaration, | |
| 23 | /// Retrieves a declaration value via it's name. Since declarations are | |
| 24 | /// analyzed in isolation of each other, all references to instructions | |
| 25 | /// outside of the current declaration must be in the form of this. | |
| 26 | load_decl, | |
| 27 | /// Blocks are a list of instructions. The block will end with a `.break`, | |
| 28 | /// which will assign the block a return value. | |
| 29 | block, | |
| 30 | /// Ends a block (current or any parent) with a value. | |
| 31 | /// `return` expressions are lowered to this. | |
| 32 | @"break", | |
| 33 | /// Creates a memory cell in the current scope with a starting value. | |
| 34 | memory, | |
| 35 | /// Re-assign a memory cell with a new ref. | |
| 36 | store, | |
| 37 | /// Re-assign a global variable decl with a new ref. | |
| 38 | store_decl, | |
| 39 | /// Re-assign a field with a new ref | |
| 40 | store_field, | |
| 41 | /// Performs a type coercion, such as in variable declarations. | |
| 42 | /// The resulting Air Ref will be guaranteed to be the coerced type. | |
| 43 | coercion, | |
| 44 | /// Load a parameter | |
| 45 | /// if data value is maxInt(u32), the function return type is used | |
| 46 | param, | |
| 47 | /// Asserts the operand is not void. Used for discard statements. | |
| 48 | discard, | |
| 49 | /// Asserts the operand is `void`. Used for undiscarded expressions. | |
| 50 | ensure_void, | |
| 51 | ||
| 52 | /// Branch takes a boolean condition and takes either a yes or no path. | |
| 53 | @"if", | |
| 54 | /// Given a block instruction | |
| 55 | @"comptime", | |
| 56 | ||
| 57 | /// A function expression, with or without captures | |
| 58 | func, | |
| 59 | ||
| 60 | // The following instructions are used to implement `Transform.ResultType` | |
| 61 | result_type_argument, | |
| 62 | result_type_struct_field, | |
| 63 | result_type_tuple_field, | |
| 64 | result_type_array_value, | |
| 65 | ||
| 66 | /// Numeric constant. | |
| 67 | number, | |
| 68 | /// String literal constant. | |
| 69 | string, | |
| 70 | ||
| 71 | /// Constructs a unique struct type. | |
| 72 | struct_decl, | |
| 73 | /// Constructs an array type | |
| 74 | array_type, | |
| 75 | ||
| 76 | struct_init, | |
| 77 | array_init, | |
| 78 | ||
| 79 | tuple_init, | |
| 80 | tuple_type, | |
| 81 | ||
| 82 | add, | |
| 83 | sub, | |
| 84 | mul, | |
| 85 | div, | |
| 86 | rem, | |
| 87 | pow, | |
| 88 | @"and", | |
| 89 | @"or", | |
| 90 | bit_and, | |
| 91 | bit_or, | |
| 92 | bit_xor, | |
| 93 | shl, | |
| 94 | shr, | |
| 95 | eq, | |
| 96 | ne, | |
| 97 | lt, | |
| 98 | le, | |
| 99 | gt, | |
| 100 | ge, | |
| 101 | ||
| 102 | negate, | |
| 103 | bool_not, | |
| 104 | bit_not, | |
| 105 | assert, | |
| 106 | field, | |
| 107 | index, | |
| 108 | call, | |
| 109 | type_of, | |
| 110 | /// Implements the `@extern` builtin | |
| 111 | @"extern", | |
| 112 | ||
| 113 | /// Implements the `@jsNew` builtin | |
| 114 | js_new, | |
| 115 | /// Implements the `@import` builtin | |
| 116 | import, | |
| 117 | /// Implements the `@fetch` builtin | |
| 118 | fetch, | |
| 119 | /// Implements the `@compileError` builtin | |
| 120 | compile_error, | |
| 121 | ||
| 122 | pub fn Data(comptime tag: Tag) type { | |
| 123 | return switch (tag) { | |
| 124 | .module, .block, .@"comptime" => PlNode(IndexList), | |
| 125 | ||
| 126 | .declaration, | |
| 127 | .variable_declaration, | |
| 128 | .test_declaration, | |
| 129 | => PlNode(Decl), | |
| 130 | ||
| 131 | .coercion => PlNode(Coercion), | |
| 132 | .@"break" => PlNode(Break), | |
| 133 | .number => PlNode(Float), | |
| 134 | .string => PlNode(SlicedString), | |
| 135 | .call => PlNode(Call), | |
| 136 | .@"if" => PlNode(If), | |
| 137 | .store => PlNode(Store), | |
| 138 | .store_decl => PlNode(StoreVarDecl), | |
| 139 | .store_field => PlNode(StoreField), | |
| 140 | .js_new => PlNode(JsNew), | |
| 141 | .struct_decl => PlNode(StructDecl), | |
| 142 | .struct_init => PlNode(StructInit), | |
| 143 | .array_init => PlNode(ArrayInit), | |
| 144 | .tuple_type => PlNode(TupleType), | |
| 145 | .tuple_init => PlNode(TupleInit), | |
| 146 | .func => PlNode(Func), | |
| 147 | ||
| 148 | .load_decl => StrNode, | |
| 149 | .param => DataNode, | |
| 150 | ||
| 151 | .result_type_argument => ResultTypeArgument, | |
| 152 | .result_type_struct_field => ResultTypeStructField, | |
| 153 | .result_type_tuple_field => ResultTypeTupleField, | |
| 154 | .result_type_array_value => ResultTypeArrayValue, | |
| 155 | ||
| 156 | // One operand instructions | |
| 157 | .memory, | |
| 158 | .discard, | |
| 159 | .ensure_void, | |
| 160 | .negate, | |
| 161 | .bool_not, | |
| 162 | .bit_not, | |
| 163 | .@"extern", | |
| 164 | .import, | |
| 165 | .fetch, | |
| 166 | .compile_error, | |
| 167 | .type_of, | |
| 168 | .array_type, | |
| 169 | .assert, | |
| 170 | => RefNode, | |
| 171 | ||
| 172 | // Two operand instructions | |
| 173 | .field, | |
| 174 | .index, | |
| 175 | .add, | |
| 176 | .sub, | |
| 177 | .mul, | |
| 178 | .div, | |
| 179 | .rem, | |
| 180 | .pow, | |
| 181 | .@"and", | |
| 182 | .@"or", | |
| 183 | .bit_and, | |
| 184 | .bit_or, | |
| 185 | .bit_xor, | |
| 186 | .shl, | |
| 187 | .shr, | |
| 188 | .eq, | |
| 189 | .ne, | |
| 190 | .lt, | |
| 191 | .le, | |
| 192 | .gt, | |
| 193 | .ge, | |
| 194 | => PlNode(Bin), | |
| 195 | }; | |
| 196 | } | |
| 197 | ||
| 198 | pub fn airTag(comptime tag: Tag) Air.Inst.Tag { | |
| 199 | return @field(Air.Inst.Tag, @tagName(tag)); | |
| 200 | } | |
| 201 | }; | |
| 202 | ||
| 203 | pub fn PlNode(comptime Payload: type) type { | |
| 204 | return struct { | |
| 205 | pub const T = Payload; | |
| 206 | ||
| 207 | src_node: NodeOffset, | |
| 208 | extra_index: ExtraIndex(Payload), | |
| 209 | }; | |
| 210 | } | |
| 211 | ||
| 212 | pub const RefNode = struct { | |
| 213 | src_node: NodeOffset, | |
| 214 | operand: Inst.Ref, | |
| 215 | }; | |
| 216 | ||
| 217 | pub const StrNode = struct { | |
| 218 | src_node: NodeOffset, | |
| 219 | string: NullTerminatedString, | |
| 220 | }; | |
| 221 | ||
| 222 | pub const DataNode = struct { | |
| 223 | src_node: NodeOffset, | |
| 224 | data: u32, | |
| 225 | }; | |
| 226 | ||
| 227 | pub const Inst = struct { | |
| 228 | pub const List = std.MultiArrayList(Inst); | |
| 229 | ||
| 230 | tag: Tag, | |
| 231 | data: EncodedData, | |
| 232 | ||
| 233 | /// The position of a Teg instruction within the `Teg` instructions array. | |
| 234 | pub const Index = enum(u32) { | |
| 235 | /// Teg is structured so that the outermost "main" struct of any file | |
| 236 | /// is always at index 0. | |
| 237 | main_module_inst = 0, | |
| 238 | _, | |
| 239 | ||
| 240 | pub const static_len = @intFromEnum(Ref.empty_tuple) + 1; | |
| 241 | ||
| 242 | pub fn toRef(i: Index) Inst.Ref { | |
| 243 | return @enumFromInt(static_len + @intFromEnum(i)); | |
| 244 | } | |
| 245 | ||
| 246 | pub fn toOptional(i: Index) Optional { | |
| 247 | return @enumFromInt(@intFromEnum(i)); | |
| 248 | } | |
| 249 | ||
| 250 | pub fn op(i: Index, operand: Report.Operand) InstOp { | |
| 251 | return .{ .index = i, .op = operand }; | |
| 252 | } | |
| 253 | ||
| 254 | pub const Optional = enum(u32) { | |
| 255 | none = std.math.maxInt(u32), | |
| 256 | _, | |
| 257 | ||
| 258 | pub fn unwrap(oi: Optional) ?Index { | |
| 259 | return if (oi == .none) null else @enumFromInt(@intFromEnum(oi)); | |
| 260 | } | |
| 261 | }; | |
| 262 | }; | |
| 263 | ||
| 264 | /// A reference to an instruction, or to a static InternPool value. | |
| 265 | /// | |
| 266 | /// If the integer tag value is < InternPool.static_len, then it | |
| 267 | /// corresponds to a Value. Otherwise, it is an instruction index. | |
| 268 | pub const Ref = enum(u32) { | |
| 269 | opaque_type, | |
| 270 | bool_type, | |
| 271 | int32_type, | |
| 272 | float_type, | |
| 273 | string_type, | |
| 274 | never_type, | |
| 275 | type_type, | |
| 276 | numeric_literal_type, | |
| 277 | numeric_literal_array_type, | |
| 278 | never_array_type, | |
| 279 | empty_tuple_type, | |
| 280 | ||
| 281 | void, | |
| 282 | bool_true, | |
| 283 | bool_false, | |
| 284 | int32_zero, | |
| 285 | float_zero, | |
| 286 | nan, | |
| 287 | empty_string, | |
| 288 | empty_array, | |
| 289 | empty_tuple, | |
| 290 | _, | |
| 291 | ||
| 292 | pub const Decoded = union(enum) { | |
| 293 | value: InternPool.Value, | |
| 294 | index: Teg.Inst.Index, | |
| 295 | }; | |
| 296 | ||
| 297 | pub fn decode(ref: Ref) Decoded { | |
| 298 | const ref_int = @intFromEnum(ref); | |
| 299 | return if (ref_int >= Index.static_len) | |
| 300 | .{ .index = @enumFromInt(ref_int - Index.static_len) } | |
| 301 | else | |
| 302 | .{ .value = @enumFromInt(ref_int) }; | |
| 303 | } | |
| 304 | ||
| 305 | pub fn index(ref: Ref) ?Index { | |
| 306 | const ref_int = @intFromEnum(ref); | |
| 307 | if (ref_int >= Index.static_len) { | |
| 308 | return @enumFromInt(ref_int - Index.static_len); | |
| 309 | } else { | |
| 310 | return null; | |
| 311 | } | |
| 312 | } | |
| 313 | ||
| 314 | pub fn value(inst: Ref) ?InternPool.Value { | |
| 315 | const ref_int = @intFromEnum(inst); | |
| 316 | ||
| 317 | // TODO: is this > or >= | |
| 318 | if (ref_int > Index.static_len) | |
| 319 | return null; | |
| 320 | ||
| 321 | return @enumFromInt(ref_int); | |
| 322 | } | |
| 323 | ||
| 324 | pub fn toOptional(ref: Ref) Optional { | |
| 325 | return @enumFromInt(@intFromEnum(ref)); | |
| 326 | } | |
| 327 | ||
| 328 | pub const Optional = enum(u32) { | |
| 329 | none = std.math.maxInt(u32), | |
| 330 | _, | |
| 331 | ||
| 332 | pub fn unwrap(opt: Optional) ?Ref { | |
| 333 | return if (opt != .none) @enumFromInt(@intFromEnum(opt)) else null; | |
| 334 | } | |
| 335 | }; | |
| 336 | }; | |
| 337 | }; | |
| 338 | ||
| 339 | pub const Bin = struct { | |
| 340 | lhs: Inst.Ref, | |
| 341 | rhs: Inst.Ref, | |
| 342 | }; | |
| 343 | ||
| 344 | pub const Store = struct { | |
| 345 | memory: Inst.Index, | |
| 346 | operand: Inst.Ref, | |
| 347 | }; | |
| 348 | ||
| 349 | pub const StoreVarDecl = struct { | |
| 350 | var_decl: NullTerminatedString, | |
| 351 | operand: Inst.Ref, | |
| 352 | }; | |
| 353 | ||
| 354 | pub const StoreField = struct { | |
| 355 | base: Inst.Ref, | |
| 356 | field: Inst.Ref, | |
| 357 | operand: Inst.Ref, | |
| 358 | }; | |
| 359 | ||
| 360 | pub const Coercion = struct { | |
| 361 | type: Inst.Ref, | |
| 362 | operand: Inst.Ref, | |
| 363 | }; | |
| 364 | ||
| 365 | pub const Break = struct { | |
| 366 | block: Inst.Index, | |
| 367 | operand: Inst.Ref, | |
| 368 | }; | |
| 369 | ||
| 370 | pub const Call = struct { | |
| 371 | base: Inst.Ref, | |
| 372 | args: RefList, | |
| 373 | }; | |
| 374 | ||
| 375 | pub const If = struct { | |
| 376 | cond: Inst.Ref, | |
| 377 | yes: Inst.Ref, | |
| 378 | no: Inst.Ref, | |
| 379 | }; | |
| 380 | ||
| 381 | pub const JsNew = struct { | |
| 382 | base: Inst.Ref, | |
| 383 | args: RefList, | |
| 384 | }; | |
| 385 | ||
| 386 | /// Index into extra which contains `field_len * 2` u32s. The first half | |
| 387 | /// are the keys (NullTerminatedString) and the second half are field types | |
| 388 | /// (Ref). This basically is like a specialized MultiArrayList. | |
| 389 | pub const StructDecl = struct { | |
| 390 | payload_index: u32, | |
| 391 | field_len: u32, | |
| 392 | ||
| 393 | pub fn keys(decl: StructDecl, teg: *const Teg) []const NullTerminatedString { | |
| 394 | return @ptrCast( | |
| 395 | teg.extra.list.items[decl.payload_index..][0..decl.field_len], | |
| 396 | ); | |
| 397 | } | |
| 398 | ||
| 399 | pub fn types(decl: StructDecl, teg: *const Teg) []const Inst.Ref { | |
| 400 | return @ptrCast( | |
| 401 | teg.extra.list.items[decl.payload_index + decl.field_len ..][0..decl.field_len], | |
| 402 | ); | |
| 403 | } | |
| 404 | }; | |
| 405 | ||
| 406 | /// This memory is laid out with the same strategy described in StructDecl | |
| 407 | pub const StructInit = struct { | |
| 408 | base_type: Inst.Ref, | |
| 409 | payload_index: u32, | |
| 410 | field_len: u32, | |
| 411 | ||
| 412 | pub fn keys(decl: StructInit, teg: *const Teg) []const NullTerminatedString { | |
| 413 | return @ptrCast( | |
| 414 | teg.extra.list.items[decl.payload_index..][0..decl.field_len], | |
| 415 | ); | |
| 416 | } | |
| 417 | ||
| 418 | pub fn inits(decl: StructInit, teg: *const Teg) []const Inst.Ref { | |
| 419 | return @ptrCast( | |
| 420 | teg.extra.list.items[decl.payload_index + decl.field_len ..][0..decl.field_len], | |
| 421 | ); | |
| 422 | } | |
| 423 | }; | |
| 424 | ||
| 425 | pub const ArrayInit = struct { | |
| 426 | /// Optionally provide a result type for more reliable type coercion. | |
| 427 | /// If specified, this must be an array type. Otherwise, the first | |
| 428 | /// element's type is used. | |
| 429 | type_hint: Inst.Ref.Optional, | |
| 430 | /// The items in the array | |
| 431 | list: RefList, | |
| 432 | }; | |
| 433 | ||
| 434 | pub const TupleType = struct { | |
| 435 | /// The items in the tuple | |
| 436 | items: RefList, | |
| 437 | }; | |
| 438 | ||
| 439 | pub const TupleInit = struct { | |
| 440 | /// Optionally provide a result type for more reliable type coercion. | |
| 441 | /// If specified, this must be an array type. Otherwise, the first | |
| 442 | /// element's type is used. | |
| 443 | type_hint: Inst.Ref.Optional, | |
| 444 | /// The items in the tuple | |
| 445 | items: RefList, | |
| 446 | }; | |
| 447 | ||
| 448 | pub const Decl = struct { | |
| 449 | name: NullTerminatedString, | |
| 450 | hash: Cache.BinDigest, | |
| 451 | instruction_count: u32, | |
| 452 | body: Inst.Ref, | |
| 453 | }; | |
| 454 | ||
| 455 | pub const Func = struct { | |
| 456 | params: OptionalRefList, | |
| 457 | return_type: Inst.Ref.Optional, | |
| 458 | body: Inst.Index, | |
| 459 | captures: IndexList, | |
| 460 | instruction_count: u32, | |
| 461 | }; | |
| 462 | ||
| 463 | pub const ResultTypeArgument = struct { | |
| 464 | /// The VALUE that is going to be called. | |
| 465 | call_base: Inst.Ref, | |
| 466 | /// Which argument | |
| 467 | argument: u32, | |
| 468 | }; | |
| 469 | ||
| 470 | pub const ResultTypeStructField = struct { | |
| 471 | /// The type of the struct itself, | |
| 472 | type: Inst.Ref, | |
| 473 | /// Which field | |
| 474 | field: NullTerminatedString, | |
| 475 | }; | |
| 476 | ||
| 477 | pub const ResultTypeTupleField = struct { | |
| 478 | /// The type of the tuple itself, | |
| 479 | type: Inst.Ref, | |
| 480 | /// Which item | |
| 481 | item: u32, | |
| 482 | }; | |
| 483 | ||
| 484 | pub const ResultTypeArrayValue = struct { | |
| 485 | /// The type of the array itself, | |
| 486 | type: Inst.Ref, | |
| 487 | unused: u32 = 0, | |
| 488 | }; | |
| 489 | ||
| 490 | // TODO: make this an enum | |
| 491 | const NodeOffset = i32; | |
| 492 | ||
| 493 | // TODO: remove InstOp. LazyNode should not have a decl | |
| 494 | pub const InstOp = struct { | |
| 495 | index: Inst.Index, | |
| 496 | op: Report.Operand, | |
| 497 | ||
| 498 | pub fn lazyNode(inst: InstOp, decl: Comp.Decl.Index) LazyNode { | |
| 499 | return .{ | |
| 500 | .inst = inst.index, | |
| 501 | .operand = inst.op, | |
| 502 | .decl = decl, | |
| 503 | }; | |
| 504 | } | |
| 505 | }; | |
| 506 | ||
| 507 | pub const NullTerminatedString = enum(u32) { | |
| 508 | empty = 0, | |
| 509 | _, | |
| 510 | ||
| 511 | pub fn slice(str: NullTerminatedString, string_bytes: []const u8) [:0]const u8 { | |
| 512 | if (str == .empty) return ""; | |
| 513 | const sub = string_bytes[@intFromEnum(str)..]; | |
| 514 | const i = mem.indexOfScalar(u8, sub, 0) orelse unreachable; | |
| 515 | ||
| 516 | return sub[0..i :0]; | |
| 517 | } | |
| 518 | }; | |
| 519 | ||
| 520 | pub const SlicedString = struct { | |
| 521 | start: u32, | |
| 522 | len: u32, | |
| 523 | ||
| 524 | pub fn slice(str: SlicedString, string_bytes: []const u8) []const u8 { | |
| 525 | return string_bytes[str.start..][0..str.len]; | |
| 526 | } | |
| 527 | }; | |
| 528 | ||
| 529 | // TODO: Make the next three structs using a generic comptime thing | |
| 530 | ||
| 531 | pub const RefList = struct { | |
| 532 | start: u32, | |
| 533 | len: u32, | |
| 534 | ||
| 535 | pub fn slice(self: RefList, teg: *const Teg) []const Inst.Ref { | |
| 536 | return @ptrCast(teg.extra.list.items[self.start..][0..self.len]); | |
| 537 | } | |
| 538 | }; | |
| 539 | ||
| 540 | pub const OptionalRefList = struct { | |
| 541 | start: u32, | |
| 542 | len: u32, | |
| 543 | ||
| 544 | pub fn slice(self: OptionalRefList, teg: *const Teg) []const Inst.Ref.Optional { | |
| 545 | return @ptrCast(teg.extra.list.items[self.start..][0..self.len]); | |
| 546 | } | |
| 547 | }; | |
| 548 | ||
| 549 | pub const IndexList = struct { | |
| 550 | start: u32, | |
| 551 | len: u32, | |
| 552 | ||
| 553 | pub fn slice(self: IndexList, teg: *const Teg) []const Inst.Index { | |
| 554 | return @ptrCast(teg.extra.list.items[self.start..][0..self.len]); | |
| 555 | } | |
| 556 | }; | |
| 557 | ||
| 558 | pub const NullTermStringList = struct { | |
| 559 | start: u32, | |
| 560 | len: u32, | |
| 561 | ||
| 562 | pub fn slice(self: IndexList, teg: *const Teg) []const NullTerminatedString { | |
| 563 | return @ptrCast(teg.extra.list.items[self.start..][0..self.len]); | |
| 564 | } | |
| 565 | }; | |
| 566 | ||
| 567 | pub fn deinit(teg: *Teg, gpa: std.mem.Allocator) void { | |
| 568 | gpa.free(teg.string_bytes); | |
| 569 | teg.extra.deinit(gpa); | |
| 570 | teg.insts.deinit(gpa); | |
| 571 | teg.report.deinit(gpa); | |
| 572 | teg.* = undefined; | |
| 573 | } | |
| 574 | ||
| 575 | pub fn instTag(teg: *const Teg, index: Inst.Index) Teg.Tag { | |
| 576 | return teg.insts.items(.tag)[@intFromEnum(index)]; | |
| 577 | } | |
| 578 | ||
| 579 | pub fn instEncodedData(teg: *const Teg, index: Inst.Index) EncodedData { | |
| 580 | return teg.insts.items(.data)[@intFromEnum(index)]; | |
| 581 | } | |
| 582 | ||
| 583 | pub fn instData(teg: *const Teg, comptime tag: Teg.Tag, index: Inst.Index) tag.Data() { | |
| 584 | return teg.instEncodedData(index).decode(tag, teg.instTag(index)); | |
| 585 | } | |
| 586 | ||
| 587 | pub fn instDataUnsafe(teg: *const Teg, comptime T: type, index: Inst.Index) T { | |
| 588 | return teg.instEncodedData(index).decodeUnsafe(T, teg.instTag(index)); | |
| 589 | } | |
| 590 | ||
| 591 | pub fn instPayload(teg: *const Teg, comptime tag: Teg.Tag, index: Inst.Index) tag.Data().T { | |
| 592 | return teg.instData(tag, index).extra_index.get(teg); | |
| 593 | } | |
| 594 | ||
| 595 | pub fn instNodeOffset(teg: *const Teg, index: Inst.Index) i32 { | |
| 596 | return switch (teg.instTag(index)) { | |
| 597 | // these nodes never get errors, but Teg.Dump will print these regardless | |
| 598 | // TODO: | |
| 599 | .declaration, | |
| 600 | .result_type_argument, | |
| 601 | .result_type_struct_field, | |
| 602 | .result_type_tuple_field, | |
| 603 | .result_type_array_value, | |
| 604 | => 0, | |
| 605 | ||
| 606 | inline else => |tag| teg.instData(tag, index).src_node, | |
| 607 | }; | |
| 608 | } | |
| 609 | ||
| 610 | pub fn blockInstructions(teg: *const Teg, index: Inst.Index) []const Inst.Index { | |
| 611 | return teg.instData(.block, index).extra_index.get(teg).slice(teg); | |
| 612 | } | |
| 613 | ||
| 614 | pub fn fullFuncDecl(teg: *const Teg, index: Inst.Index) struct { Teg.Decl, Teg.DeclFn } { | |
| 615 | const decl, var trail = teg.instData(.declaration, index).extra_index.getTrail(teg); | |
| 616 | assert(decl.kind == .function); | |
| 617 | const decl_fn = trail.read(&teg.extra, Teg.DeclFn); | |
| 618 | return .{ decl, decl_fn }; | |
| 619 | } | |
| 620 | ||
| 621 | pub fn fullDecl(teg: *const Teg, index: Inst.Index) Decl { | |
| 622 | const decl = teg.instEncodedData(index).decodeUnsafe(PlNode(Decl), teg.instTag(index)).extra_index.get(teg); | |
| 623 | return .{ | |
| 624 | .name = decl.name, | |
| 625 | .hash = decl.hash, | |
| 626 | .instruction_count = decl.instruction_count, | |
| 627 | .body = decl.body, | |
| 628 | }; | |
| 629 | } | |
| 630 | ||
| 631 | pub fn declData(teg: *const Teg, index: Inst.Index) Teg.Decl { | |
| 632 | return teg.instDataUnsafe(PlNode(Decl), index).extra_index.get(teg); | |
| 633 | } | |
| 634 | ||
| 635 | pub fn moduleDeclarations(teg: *const Teg, module_index: Inst.Index) []const Inst.Index { | |
| 636 | const module = teg.instData(.module, module_index); | |
| 637 | const module_data: IndexList = module.extra_index.get(teg); | |
| 638 | const slice = module_data.slice(teg); | |
| 639 | if (core.runtime_safety) { | |
| 640 | for (slice) |item| { | |
| 641 | switch (teg.instTag(item)) { | |
| 642 | .declaration, .variable_declaration, .test_declaration => {}, | |
| 643 | else => { | |
| 644 | std.debug.panic("\ngot unknown tag {s}\n", .{@tagName(teg.instTag(item))}); | |
| 645 | }, | |
| 646 | } | |
| 647 | } | |
| 648 | } | |
| 649 | return slice; | |
| 650 | } | |
| 651 | ||
| 652 | pub fn rootFunction(teg: *const Teg) Inst.Index { | |
| 653 | const decls = teg.moduleDeclarations(.main_module_inst); | |
| 654 | const root_fn = decls[decls.len - 1]; | |
| 655 | assert(teg.declName(root_fn).len == 0); | |
| 656 | return root_fn; | |
| 657 | } | |
| 658 | ||
| 659 | pub fn declName(teg: *const Teg, decl_index: Inst.Index) []const u8 { | |
| 660 | const decl = teg.instDataUnsafe(PlNode(Decl), decl_index); | |
| 661 | const decl_data: Decl = decl.extra_index.get(teg); | |
| 662 | return decl_data.name.slice(teg.string_bytes); | |
| 663 | } | |
| 664 | ||
| 665 | pub fn dumpToWriter(teg: Teg, writer: anytype, tty: ?std.io.tty.Config) !void { | |
| 666 | try writer.print("{}", .{Dump{ .teg = teg, .tty = tty }}); | |
| 667 | } | |
| 668 | ||
| 669 | /// Used for generating decl hashes | |
| 670 | fn isolatedRefValue(decl_index: Inst.Index, ref_to_hash: Inst.Ref) i32 { | |
| 671 | return switch (ref_to_hash.decode()) { | |
| 672 | .value => |value| -@as(i32, @intCast(@intFromEnum(value))), | |
| 673 | .index => |index| @intCast(@intFromEnum(index) - @intFromEnum(decl_index)), | |
| 674 | }; | |
| 675 | } | |
| 676 | ||
| 677 | /// Used for generating decl hashes | |
| 678 | fn isolatedIndexValue(decl_index: Inst.Index, index_to_hash: Inst.Index) u32 { | |
| 679 | return @intFromEnum(index_to_hash) - @intFromEnum(decl_index); | |
| 680 | } | |
| 681 | ||
| 682 | pub fn writeToHasher( | |
| 683 | teg: *const Teg, | |
| 684 | hasher: *HashHelper, | |
| 685 | tag_list: []Tag, | |
| 686 | data_list: []EncodedData, | |
| 687 | decl_index: Inst.Index, | |
| 688 | ) void { | |
| 689 | // Add all of the tags | |
| 690 | hasher.addBytes(std.mem.sliceAsBytes(tag_list)); | |
| 691 | ||
| 692 | // Add all of the data | |
| 693 | for (tag_list, data_list) |tag, data| { | |
| 694 | ||
| 695 | // This should roughly line up with Teg.Tag.Data | |
| 696 | switch (tag) { | |
| 697 | // PlNode(IndexList), | |
| 698 | .module, | |
| 699 | .block, | |
| 700 | .@"comptime", | |
| 701 | => { | |
| 702 | const pl_node = data.decodeUnsafe(PlNode(IndexList), tag); | |
| 703 | hasher.add(pl_node.src_node); | |
| 704 | writeIndexListToHasher(hasher, pl_node.extra_index.get(teg).slice(teg), decl_index); | |
| 705 | }, | |
| 706 | ||
| 707 | // PlNode | |
| 708 | inline .declaration, | |
| 709 | .variable_declaration, | |
| 710 | .test_declaration, | |
| 711 | .coercion, | |
| 712 | .@"break", | |
| 713 | .number, | |
| 714 | .string, | |
| 715 | .call, | |
| 716 | .@"if", | |
| 717 | .store, | |
| 718 | .js_new, | |
| 719 | .struct_decl, | |
| 720 | .struct_init, | |
| 721 | .array_init, | |
| 722 | .tuple_init, | |
| 723 | .tuple_type, | |
| 724 | .func, | |
| 725 | .store_decl, | |
| 726 | .store_field, | |
| 727 | => |pl_node_tag| { | |
| 728 | const pl_node = data.decode(pl_node_tag, tag); | |
| 729 | hasher.add(pl_node.src_node); | |
| 730 | teg.writePlNodeInnerToHasher(hasher, pl_node_tag.Data().T, pl_node.extra_index.get(teg), decl_index); | |
| 731 | }, | |
| 732 | // StrNode | |
| 733 | .load_decl => { | |
| 734 | const str_node = data.decodeUnsafe(StrNode, tag); | |
| 735 | hasher.add(str_node.src_node); | |
| 736 | hasher.addBytes(str_node.string.slice(teg.string_bytes)); | |
| 737 | }, | |
| 738 | // DataNode | |
| 739 | .param => { | |
| 740 | const data_node = data.decodeUnsafe(DataNode, tag); | |
| 741 | hasher.add(data_node.src_node); | |
| 742 | hasher.add(data_node.data); | |
| 743 | }, | |
| 744 | // RefNode | |
| 745 | .memory, | |
| 746 | .discard, | |
| 747 | .ensure_void, | |
| 748 | .negate, | |
| 749 | .bool_not, | |
| 750 | .bit_not, | |
| 751 | .@"extern", | |
| 752 | .import, | |
| 753 | .fetch, | |
| 754 | .compile_error, | |
| 755 | .type_of, | |
| 756 | .array_type, | |
| 757 | .assert, | |
| 758 | => { | |
| 759 | const ref_node = data.decodeUnsafe(RefNode, tag); | |
| 760 | hasher.add(ref_node.src_node); | |
| 761 | hasher.add(isolatedRefValue(decl_index, ref_node.operand)); | |
| 762 | }, | |
| 763 | // PlNode(Bin) | |
| 764 | .field, | |
| 765 | .index, | |
| 766 | .add, | |
| 767 | .sub, | |
| 768 | .mul, | |
| 769 | .div, | |
| 770 | .rem, | |
| 771 | .pow, | |
| 772 | .@"and", | |
| 773 | .@"or", | |
| 774 | .bit_and, | |
| 775 | .bit_or, | |
| 776 | .bit_xor, | |
| 777 | .shl, | |
| 778 | .shr, | |
| 779 | .eq, | |
| 780 | .ne, | |
| 781 | .lt, | |
| 782 | .le, | |
| 783 | .gt, | |
| 784 | .ge, | |
| 785 | => { | |
| 786 | const pl_node = data.decodeUnsafe(PlNode(Bin), tag); | |
| 787 | const bin = pl_node.extra_index.get(teg); | |
| 788 | hasher.add(isolatedRefValue(decl_index, bin.lhs)); | |
| 789 | hasher.add(isolatedRefValue(decl_index, bin.rhs)); | |
| 790 | }, | |
| 791 | // Result Types | |
| 792 | .result_type_argument => { | |
| 793 | const arg = data.decodeUnsafe(ResultTypeArgument, tag); | |
| 794 | hasher.add(isolatedRefValue(decl_index, arg.call_base)); | |
| 795 | hasher.add(arg.argument); | |
| 796 | }, | |
| 797 | .result_type_struct_field => { | |
| 798 | const struct_field = data.decodeUnsafe(ResultTypeStructField, tag); | |
| 799 | hasher.add(isolatedRefValue(decl_index, struct_field.type)); | |
| 800 | hasher.addBytes(struct_field.field.slice(teg.string_bytes)); | |
| 801 | }, | |
| 802 | .result_type_tuple_field => { | |
| 803 | const tuple_field = data.decodeUnsafe(ResultTypeTupleField, tag); | |
| 804 | hasher.add(isolatedRefValue(decl_index, tuple_field.type)); | |
| 805 | hasher.add(tuple_field.item); | |
| 806 | }, | |
| 807 | .result_type_array_value => { | |
| 808 | const array_value = data.decodeUnsafe(ResultTypeArrayValue, tag); | |
| 809 | hasher.add(isolatedRefValue(decl_index, array_value.type)); | |
| 810 | }, | |
| 811 | } | |
| 812 | } | |
| 813 | } | |
| 814 | ||
| 815 | fn writeIndexListToHasher( | |
| 816 | hasher: *HashHelper, | |
| 817 | index_list: []const Inst.Index, | |
| 818 | decl_index: Inst.Index, | |
| 819 | ) void { | |
| 820 | hasher.add(index_list.len); | |
| 821 | for (index_list) |idx| { | |
| 822 | hasher.add(isolatedIndexValue(decl_index, idx)); | |
| 823 | } | |
| 824 | } | |
| 825 | ||
| 826 | fn writeRefListToHasher( | |
| 827 | hasher: *HashHelper, | |
| 828 | decl_index: Inst.Index, | |
| 829 | index_list: []const Inst.Ref, | |
| 830 | ) void { | |
| 831 | hasher.add(index_list.len); | |
| 832 | for (index_list) |idx| { | |
| 833 | hasher.add(isolatedRefValue(decl_index, idx)); | |
| 834 | } | |
| 835 | } | |
| 836 | ||
| 837 | fn writePlNodeInnerToHasher( | |
| 838 | teg: *const Teg, | |
| 839 | hasher: *HashHelper, | |
| 840 | comptime T: type, | |
| 841 | data: T, | |
| 842 | decl_index: Inst.Index, | |
| 843 | ) void { | |
| 844 | switch (T) { | |
| 845 | Decl => { | |
| 846 | hasher.addBytes(&data.hash); | |
| 847 | hasher.addBytes(data.name.slice(teg.string_bytes)); | |
| 848 | }, | |
| 849 | Float => { | |
| 850 | const as_bytes: [2]u32 = .{ | |
| 851 | data.low, | |
| 852 | data.high, | |
| 853 | }; | |
| 854 | hasher.add(@as(u64, @bitCast(as_bytes))); | |
| 855 | }, | |
| 856 | SlicedString => { | |
| 857 | hasher.addBytes(data.slice(teg.string_bytes)); | |
| 858 | }, | |
| 859 | Coercion => { | |
| 860 | hasher.add(isolatedRefValue(decl_index, data.type)); | |
| 861 | hasher.add(isolatedRefValue(decl_index, data.operand)); | |
| 862 | }, | |
| 863 | Break => { | |
| 864 | hasher.add(isolatedIndexValue(decl_index, data.block)); | |
| 865 | hasher.add(isolatedRefValue(decl_index, data.operand)); | |
| 866 | }, | |
| 867 | Call => { | |
| 868 | hasher.add(isolatedRefValue(decl_index, data.base)); | |
| 869 | writeRefListToHasher(hasher, decl_index, data.args.slice(teg)); | |
| 870 | }, | |
| 871 | If => { | |
| 872 | hasher.add(isolatedRefValue(decl_index, data.cond)); | |
| 873 | hasher.add(isolatedRefValue(decl_index, data.yes)); | |
| 874 | hasher.add(isolatedRefValue(decl_index, data.no)); | |
| 875 | }, | |
| 876 | Store => { | |
| 877 | hasher.add(isolatedIndexValue(decl_index, data.memory)); | |
| 878 | hasher.add(isolatedRefValue(decl_index, data.operand)); | |
| 879 | }, | |
| 880 | StoreField => { | |
| 881 | hasher.add(isolatedRefValue(decl_index, data.base)); | |
| 882 | hasher.add(isolatedRefValue(decl_index, data.field)); | |
| 883 | hasher.add(isolatedRefValue(decl_index, data.operand)); | |
| 884 | }, | |
| 885 | StoreVarDecl => { | |
| 886 | hasher.addBytes(data.var_decl.slice(teg.string_bytes)); | |
| 887 | hasher.add(isolatedRefValue(decl_index, data.operand)); | |
| 888 | }, | |
| 889 | JsNew => { | |
| 890 | hasher.add(isolatedRefValue(decl_index, data.base)); | |
| 891 | writeRefListToHasher(hasher, decl_index, data.args.slice(teg)); | |
| 892 | }, | |
| 893 | StructDecl => { | |
| 894 | hasher.add(data.field_len); | |
| 895 | for (data.keys(teg), data.types(teg)) |key, ty| { | |
| 896 | hasher.addBytes(key.slice(teg.string_bytes)); | |
| 897 | hasher.add(isolatedRefValue(decl_index, ty)); | |
| 898 | } | |
| 899 | }, | |
| 900 | StructInit => { | |
| 901 | hasher.add(isolatedRefValue(decl_index, data.base_type)); | |
| 902 | hasher.add(data.field_len); | |
| 903 | for (data.keys(teg), data.inits(teg)) |key, init| { | |
| 904 | hasher.addBytes(key.slice(teg.string_bytes)); | |
| 905 | hasher.add(isolatedRefValue(decl_index, init)); | |
| 906 | } | |
| 907 | }, | |
| 908 | ArrayInit => { | |
| 909 | if (data.type_hint.unwrap()) |type_hint| | |
| 910 | hasher.add(isolatedRefValue(decl_index, type_hint)) | |
| 911 | else | |
| 912 | hasher.add(@as(i32, std.math.maxInt(i32))); | |
| 913 | writeRefListToHasher(hasher, decl_index, data.list.slice(teg)); | |
| 914 | }, | |
| 915 | Func => { | |
| 916 | for (data.params.slice(teg)) |optional| { | |
| 917 | if (optional.unwrap()) |item| | |
| 918 | hasher.add(isolatedRefValue(decl_index, item)); | |
| 919 | } | |
| 920 | ||
| 921 | if (data.return_type.unwrap()) |type_hint| | |
| 922 | hasher.add(isolatedRefValue(decl_index, type_hint)) | |
| 923 | else | |
| 924 | hasher.add(@as(i32, std.math.maxInt(i32))); | |
| 925 | ||
| 926 | hasher.add(isolatedIndexValue(decl_index, data.body)); | |
| 927 | hasher.add(data.instruction_count); | |
| 928 | }, | |
| 929 | TupleType => { | |
| 930 | hasher.add(data.items.len); | |
| 931 | for (data.items.slice(teg)) |item| { | |
| 932 | hasher.add(isolatedRefValue(decl_index, item)); | |
| 933 | } | |
| 934 | }, | |
| 935 | TupleInit => { | |
| 936 | if (data.type_hint.unwrap()) |type_hint| | |
| 937 | hasher.add(isolatedRefValue(decl_index, type_hint)) | |
| 938 | else | |
| 939 | hasher.add(@as(i32, std.math.maxInt(i32))); | |
| 940 | writeRefListToHasher(hasher, decl_index, data.items.slice(teg)); | |
| 941 | }, | |
| 942 | else => @compileError("hash not implemented for " ++ @typeName(T)), | |
| 943 | } | |
| 944 | } | |
| 945 | ||
| 946 | pub const SerializedHeader = extern struct { | |
| 947 | const version = @import("config").version_string ++ "\x00"; | |
| 948 | ||
| 949 | instruction_len: u32, | |
| 950 | string_bytes: u32, | |
| 951 | extra_len: u32, | |
| 952 | report_err_len: u32, | |
| 953 | report_warn_len: u32, | |
| 954 | }; | |
| 955 | ||
| 956 | pub fn serialize(teg: Teg, target: core.SerializeTarget) !void { | |
| 957 | const header: SerializedHeader = .{ | |
| 958 | .instruction_len = @intCast(teg.insts.len), | |
| 959 | .string_bytes = @intCast(teg.string_bytes.len), | |
| 960 | .extra_len = @intCast(teg.extra.list.items.len), | |
| 961 | .report_err_len = @intCast(teg.report.errors.len), | |
| 962 | .report_warn_len = @intCast(teg.report.warnings.len), | |
| 963 | }; | |
| 964 | ||
| 965 | var iovecs = [_]std.posix.iovec_const{ | |
| 966 | core.iovecConst(SerializedHeader.version), | |
| 967 | core.iovecConst(std.mem.asBytes(&header)), | |
| 968 | core.iovecConst(std.mem.sliceAsBytes(teg.insts.items(.tag))), | |
| 969 | core.iovecConst(std.mem.sliceAsBytes(teg.insts.items(.data))), | |
| 970 | core.iovecConst(teg.string_bytes), | |
| 971 | core.iovecConst(std.mem.sliceAsBytes(teg.extra.list.items)), | |
| 972 | core.iovecConst(std.mem.sliceAsBytes(teg.report.errors)), | |
| 973 | core.iovecConst(std.mem.sliceAsBytes(teg.report.warnings)), | |
| 974 | }; | |
| 975 | try target.writev(&iovecs); | |
| 976 | } | |
| 977 | ||
| 978 | const Teg = @This(); | |
| 979 | ||
| 980 | const std = @import("std"); | |
| 981 | const mem = std.mem; | |
| 982 | const assert = std.debug.assert; | |
| 983 | const HashHelper = std.Build.Cache.HashHelper; | |
| 984 | ||
| 985 | const core = @import("mod.zig"); | |
| 986 | const Cache = core.Cache; | |
| 987 | ||
| 988 | const Ast = core.Ast; | |
| 989 | const Unused = Ast.Unused; | |
| 990 | const NodeIndex = Ast.NodeIndex; | |
| 991 | const TokenIndex = Ast.TokenIndex; | |
| 992 | const OptionalNodeIndex = Ast.OptionalNodeIndex; | |
| 993 | const OptionalTokenIndex = Ast.OptionalTokenIndex; | |
| 994 | const OptionalExtraIndex = Ast.OptionalExtraIndex; | |
| 995 | ||
| 996 | const dod = core.array; | |
| 997 | const Float = dod.Float; | |
| 998 | ||
| 999 | const InternPool = core.InternPool; | |
| 1000 | ||
| 1001 | const Air = core.Air; | |
| 1002 | ||
| 1003 | const Comp = core.Comp; | |
| 1004 | ||
| 1005 | const Report = core.Report; | |
| 1006 | const LazyNode = Report.LazyNode; |
src/core/Transform.zig+52-52| ... | ... | @@ -1,5 +1,5 @@ |
| 1 | //! Transform pass converts an Ast into a high-level/untyped instruction format. | |
| 2 | //! See Teg.zig for more details about the IR. Transforming handles: | |
| 1 | //! Transform pass converts an Ast into a Hir. See Hir.zig for more details | |
| 2 | //! about the resulting data structure. Transforming handles: | |
| 3 | 3 | //! |
| 4 | 4 | //! - Flattening nested expressions into instruction sequences. |
| 5 | 5 | //! - Resolving all local variables into reference or declaration names. |
| ... | ... | @@ -38,7 +38,7 @@ pub const Error = error{ |
| 38 | 38 | TransformFail, |
| 39 | 39 | } || Allocator.Error; |
| 40 | 40 | |
| 41 | pub fn transform(ast: Ast, gpa: Allocator, fail_report: *Report) Error!Teg { | |
| 41 | pub fn transform(ast: Ast, gpa: Allocator, fail_report: *Report) Error!Hir { | |
| 42 | 42 | const trace = tracer.trace(@src()); |
| 43 | 43 | defer trace.end(); |
| 44 | 44 | |
| ... | ... | @@ -117,16 +117,16 @@ const ResultType = union(enum) { |
| 117 | 117 | /// The expression will be cast to the type of this ref |
| 118 | 118 | type_of: Inst.Ref, |
| 119 | 119 | /// The expression is an argument to a function. |
| 120 | argument: Teg.ResultTypeArgument, | |
| 120 | argument: Hir.ResultTypeArgument, | |
| 121 | 121 | /// The expression is a field in a struct initialization |
| 122 | struct_field: Teg.ResultTypeStructField, | |
| 122 | struct_field: Hir.ResultTypeStructField, | |
| 123 | 123 | /// The expression is a field in a tuple initialization |
| 124 | tuple_field: Teg.ResultTypeTupleField, | |
| 124 | tuple_field: Hir.ResultTypeTupleField, | |
| 125 | 125 | /// The expression is a field in an array initialization |
| 126 | 126 | array_value: Inst.Ref, |
| 127 | 127 | |
| 128 | 128 | // /// The expression is unknown field |
| 129 | // field: Teg.ResultTypeField, | |
| 129 | // field: Hir.ResultTypeField, | |
| 130 | 130 | |
| 131 | 131 | /// This will return an instruction pointing to the the type |
| 132 | 132 | pub fn consume(result: *ResultType, t: *Transform) !?Inst.Ref { |
| ... | ... | @@ -259,8 +259,8 @@ const Scope = struct { |
| 259 | 259 | /// Sema requires that function expressions must know their up-front captures, |
| 260 | 260 | /// so it can classify a function as comptime or runtime. |
| 261 | 261 | const CaptureScope = struct { |
| 262 | start_index: Teg.Inst.Index, | |
| 263 | symbol_uses: std.AutoArrayHashMapUnmanaged(Teg.Inst.Index, void) = .{}, | |
| 262 | start_index: Hir.Inst.Index, | |
| 263 | symbol_uses: std.AutoArrayHashMapUnmanaged(Hir.Inst.Index, void) = .{}, | |
| 264 | 264 | |
| 265 | 265 | fn deinit(s: *CaptureScope, t: *Transform) void { |
| 266 | 266 | s.symbol_uses.deinit(t.gpa); |
| ... | ... | @@ -535,7 +535,7 @@ fn transformDecl(t: *Transform, outer_decl: BlockContext, node: NodeIndex) Alloc |
| 535 | 535 | var hasher: std.Build.Cache.HashHelper = .{ .hasher = core.Cache.hasher_init }; |
| 536 | 536 | hasher.addBytes(id); |
| 537 | 537 | |
| 538 | const temp_teg: Teg = .{ | |
| 538 | const temp_teg: Hir = .{ | |
| 539 | 539 | .insts = t.insts.slice(), |
| 540 | 540 | .extra = t.extra.constant(), |
| 541 | 541 | .string_bytes = t.string_bytes.items, |
| ... | ... | @@ -547,7 +547,7 @@ fn transformDecl(t: *Transform, outer_decl: BlockContext, node: NodeIndex) Alloc |
| 547 | 547 | |
| 548 | 548 | temp_teg.writeToHasher(&hasher, tag_list, data_list, decl_index); |
| 549 | 549 | |
| 550 | const decl_extra = try t.extra.append(t.gpa, Teg.Decl, .{ | |
| 550 | const decl_extra = try t.extra.append(t.gpa, Hir.Decl, .{ | |
| 551 | 551 | .name = name, |
| 552 | 552 | .hash = hasher.hasher.finalResult(), |
| 553 | 553 | .instruction_count = inst_count, |
| ... | ... | @@ -579,7 +579,7 @@ fn transformTestDecl(t: *Transform, outer_decl: BlockContext, node: NodeIndex) A |
| 579 | 579 | |
| 580 | 580 | var hasher: std.Build.Cache.HashHelper = .{ .hasher = core.Cache.hasher_init }; |
| 581 | 581 | |
| 582 | const temp_teg: Teg = .{ | |
| 582 | const temp_teg: Hir = .{ | |
| 583 | 583 | .insts = t.insts.slice(), |
| 584 | 584 | .extra = t.extra.constant(), |
| 585 | 585 | .string_bytes = t.string_bytes.items, |
| ... | ... | @@ -591,7 +591,7 @@ fn transformTestDecl(t: *Transform, outer_decl: BlockContext, node: NodeIndex) A |
| 591 | 591 | |
| 592 | 592 | temp_teg.writeToHasher(&hasher, tag_list, data_list, decl_index); |
| 593 | 593 | |
| 594 | const decl_extra = try t.extra.append(t.gpa, Teg.Decl, .{ | |
| 594 | const decl_extra = try t.extra.append(t.gpa, Hir.Decl, .{ | |
| 595 | 595 | .name = .empty, |
| 596 | 596 | .hash = hasher.hasher.finalResult(), |
| 597 | 597 | .instruction_count = inst_count, |
| ... | ... | @@ -738,7 +738,7 @@ fn transformToBlock( |
| 738 | 738 | .none, .used => result, |
| 739 | 739 | else => try t.addRef(.coercion, .{ |
| 740 | 740 | .src_node = ctx.nodeOffset(node), |
| 741 | .extra_index = try t.extra.append(t.gpa, Teg.Coercion, .{ | |
| 741 | .extra_index = try t.extra.append(t.gpa, Hir.Coercion, .{ | |
| 742 | 742 | .type = try result_type_ptr.consume(t) orelse |
| 743 | 743 | unreachable, // `.none` already handled |
| 744 | 744 | .operand = result, |
| ... | ... | @@ -748,7 +748,7 @@ fn transformToBlock( |
| 748 | 748 | |
| 749 | 749 | _ = try t.addIndex(.@"break", .{ |
| 750 | 750 | .src_node = ctx.nodeOffset(node), |
| 751 | .extra_index = try t.extra.append(t.gpa, Teg.Break, .{ | |
| 751 | .extra_index = try t.extra.append(t.gpa, Hir.Break, .{ | |
| 752 | 752 | .block = ret_block, |
| 753 | 753 | .operand = coerced_result, |
| 754 | 754 | }), |
| ... | ... | @@ -864,7 +864,7 @@ pub const Builtin = enum { |
| 864 | 864 | |
| 865 | 865 | return try t.addRef(.js_new, .{ |
| 866 | 866 | .src_node = decl.nodeOffset(args[0]), |
| 867 | .extra_index = try t.extra.append(t.gpa, Teg.JsNew, .{ | |
| 867 | .extra_index = try t.extra.append(t.gpa, Hir.JsNew, .{ | |
| 868 | 868 | .base = base, |
| 869 | 869 | .args = args_list, |
| 870 | 870 | }), |
| ... | ... | @@ -987,7 +987,7 @@ fn transformExpression( |
| 987 | 987 | |
| 988 | 988 | return try t.addRef(.coercion, .{ |
| 989 | 989 | .src_node = ctx.nodeOffset(node), |
| 990 | .extra_index = try t.extra.append(t.gpa, Teg.Coercion, .{ | |
| 990 | .extra_index = try t.extra.append(t.gpa, Hir.Coercion, .{ | |
| 991 | 991 | .type = type_ref.?, |
| 992 | 992 | .operand = data_ref, |
| 993 | 993 | }), |
| ... | ... | @@ -1075,7 +1075,7 @@ fn transformExpression( |
| 1075 | 1075 | // compound compute + assign operation. |
| 1076 | 1076 | const is_assign = comptime tag.isAssignBin(); |
| 1077 | 1077 | const teg_tag = @field( |
| 1078 | Teg.Tag, | |
| 1078 | Hir.Tag, | |
| 1079 | 1079 | if (is_assign) |
| 1080 | 1080 | @tagName(tag)[0 .. @tagName(tag).len - "_assign".len] |
| 1081 | 1081 | else |
| ... | ... | @@ -1096,7 +1096,7 @@ fn transformExpression( |
| 1096 | 1096 | |
| 1097 | 1097 | const compute_inst = try t.addRef(teg_tag, .{ |
| 1098 | 1098 | .src_node = ctx.nodeOffset(node), |
| 1099 | .extra_index = try t.extra.append(t.gpa, Teg.Bin, .{ | |
| 1099 | .extra_index = try t.extra.append(t.gpa, Hir.Bin, .{ | |
| 1100 | 1100 | .lhs = if (is_assign) try lhs.toRef(t) else lhs, |
| 1101 | 1101 | .rhs = rhs, |
| 1102 | 1102 | }), |
| ... | ... | @@ -1116,7 +1116,7 @@ fn transformExpression( |
| 1116 | 1116 | .assert, |
| 1117 | 1117 | => |tag| { |
| 1118 | 1118 | const ast_un = t.ast.nodeData(node).un; |
| 1119 | const teg_tag = @field(Teg.Tag, @tagName(tag)); | |
| 1119 | const teg_tag = @field(Hir.Tag, @tagName(tag)); | |
| 1120 | 1120 | |
| 1121 | 1121 | var operand_type: ResultType = switch (tag) { |
| 1122 | 1122 | .negate => .none, // any numeric type allowed |
| ... | ... | @@ -1178,7 +1178,7 @@ fn transformExpression( |
| 1178 | 1178 | if (inner_expr) |out| { |
| 1179 | 1179 | _ = try t.addRef(.@"break", .{ |
| 1180 | 1180 | .src_node = ctx.nodeOffset(node), |
| 1181 | .extra_index = try t.extra.append(t.gpa, Teg.Break, .{ | |
| 1181 | .extra_index = try t.extra.append(t.gpa, Hir.Break, .{ | |
| 1182 | 1182 | .block = block, |
| 1183 | 1183 | .operand = out, |
| 1184 | 1184 | }), |
| ... | ... | @@ -1276,7 +1276,7 @@ fn transformExpression( |
| 1276 | 1276 | |
| 1277 | 1277 | const call_inst = try t.addRef(.call, .{ |
| 1278 | 1278 | .src_node = ctx.nodeOffset(node), |
| 1279 | .extra_index = try t.extra.append(t.gpa, Teg.Call, .{ | |
| 1279 | .extra_index = try t.extra.append(t.gpa, Hir.Call, .{ | |
| 1280 | 1280 | .base = base, |
| 1281 | 1281 | .args = args_list, |
| 1282 | 1282 | }), |
| ... | ... | @@ -1319,7 +1319,7 @@ fn transformExpression( |
| 1319 | 1319 | |
| 1320 | 1320 | return try t.addRef(.field, .{ |
| 1321 | 1321 | .src_node = ctx.nodeOffset(node), |
| 1322 | .extra_index = try t.extra.append(t.gpa, Teg.Bin, .{ | |
| 1322 | .extra_index = try t.extra.append(t.gpa, Hir.Bin, .{ | |
| 1323 | 1323 | .lhs = base, |
| 1324 | 1324 | .rhs = rhs, |
| 1325 | 1325 | }), |
| ... | ... | @@ -1339,7 +1339,7 @@ fn transformExpression( |
| 1339 | 1339 | |
| 1340 | 1340 | return try t.addRef(.field, .{ |
| 1341 | 1341 | .src_node = ctx.nodeOffset(node), |
| 1342 | .extra_index = try t.extra.append(t.gpa, Teg.Bin, .{ | |
| 1342 | .extra_index = try t.extra.append(t.gpa, Hir.Bin, .{ | |
| 1343 | 1343 | .lhs = lhs, |
| 1344 | 1344 | .rhs = rhs, |
| 1345 | 1345 | }), |
| ... | ... | @@ -1370,7 +1370,7 @@ fn transformExpression( |
| 1370 | 1370 | |
| 1371 | 1371 | return try t.addRef(.@"if", .{ |
| 1372 | 1372 | .src_node = ctx.nodeOffset(node), |
| 1373 | .extra_index = try t.extra.append(t.gpa, Teg.If, .{ | |
| 1373 | .extra_index = try t.extra.append(t.gpa, Hir.If, .{ | |
| 1374 | 1374 | .cond = cond, |
| 1375 | 1375 | .yes = yes, |
| 1376 | 1376 | .no = no, |
| ... | ... | @@ -1399,7 +1399,7 @@ fn transformExpression( |
| 1399 | 1399 | |
| 1400 | 1400 | _ = try t.addIndex(.@"break", .{ |
| 1401 | 1401 | .src_node = ctx.nodeOffset(node), |
| 1402 | .extra_index = try t.extra.append(t.gpa, Teg.Break, .{ | |
| 1402 | .extra_index = try t.extra.append(t.gpa, Hir.Break, .{ | |
| 1403 | 1403 | .block = target.block_index, |
| 1404 | 1404 | .operand = operand, |
| 1405 | 1405 | }), |
| ... | ... | @@ -1431,7 +1431,7 @@ fn transformExpression( |
| 1431 | 1431 | .none, .used => operand, |
| 1432 | 1432 | else => try t.addRef(.coercion, .{ |
| 1433 | 1433 | .src_node = ctx.nodeOffset(node), |
| 1434 | .extra_index = try t.extra.append(t.gpa, Teg.Coercion, .{ | |
| 1434 | .extra_index = try t.extra.append(t.gpa, Hir.Coercion, .{ | |
| 1435 | 1435 | .type = try break_result.consume(t) orelse |
| 1436 | 1436 | unreachable, // `.none` already handled |
| 1437 | 1437 | .operand = operand, |
| ... | ... | @@ -1441,7 +1441,7 @@ fn transformExpression( |
| 1441 | 1441 | |
| 1442 | 1442 | _ = try t.addIndex(.@"break", .{ |
| 1443 | 1443 | .src_node = ctx.nodeOffset(node), |
| 1444 | .extra_index = try t.extra.append(t.gpa, Teg.Break, .{ | |
| 1444 | .extra_index = try t.extra.append(t.gpa, Hir.Break, .{ | |
| 1445 | 1445 | .block = try block.getInst(t), |
| 1446 | 1446 | .operand = coerced_operand, |
| 1447 | 1447 | }), |
| ... | ... | @@ -1474,7 +1474,7 @@ fn transformExpression( |
| 1474 | 1474 | |
| 1475 | 1475 | return try t.addRef(.struct_decl, .{ |
| 1476 | 1476 | .src_node = ctx.nodeOffset(node), |
| 1477 | .extra_index = try t.extra.append(t.gpa, Teg.StructDecl, .{ | |
| 1477 | .extra_index = try t.extra.append(t.gpa, Hir.StructDecl, .{ | |
| 1478 | 1478 | .payload_index = payload_index, |
| 1479 | 1479 | .field_len = @intCast(struct_node.fields.len), |
| 1480 | 1480 | }), |
| ... | ... | @@ -1524,7 +1524,7 @@ fn transformExpression( |
| 1524 | 1524 | |
| 1525 | 1525 | return try t.addRef(.struct_init, .{ |
| 1526 | 1526 | .src_node = ctx.nodeOffset(node), |
| 1527 | .extra_index = try t.extra.append(t.gpa, Teg.StructInit, .{ | |
| 1527 | .extra_index = try t.extra.append(t.gpa, Hir.StructInit, .{ | |
| 1528 | 1528 | .base_type = base_type, |
| 1529 | 1529 | .payload_index = payload_index, |
| 1530 | 1530 | .field_len = @intCast(struct_node.fields.len), |
| ... | ... | @@ -1549,7 +1549,7 @@ fn transformExpression( |
| 1549 | 1549 | |
| 1550 | 1550 | return try t.addRef(.array_init, .{ |
| 1551 | 1551 | .src_node = ctx.nodeOffset(node), |
| 1552 | .extra_index = try t.extra.append(t.gpa, Teg.ArrayInit, .{ | |
| 1552 | .extra_index = try t.extra.append(t.gpa, Hir.ArrayInit, .{ | |
| 1553 | 1553 | .type_hint = if (array_type) |ty| ty.toOptional() else .none, |
| 1554 | 1554 | .list = items, |
| 1555 | 1555 | }), |
| ... | ... | @@ -1567,7 +1567,7 @@ fn transformExpression( |
| 1567 | 1567 | |
| 1568 | 1568 | return try t.addRef(.tuple_init, .{ |
| 1569 | 1569 | .src_node = ctx.nodeOffset(node), |
| 1570 | .extra_index = try t.extra.append(t.gpa, Teg.TupleInit, .{ | |
| 1570 | .extra_index = try t.extra.append(t.gpa, Hir.TupleInit, .{ | |
| 1571 | 1571 | .type_hint = .none, |
| 1572 | 1572 | .items = items, |
| 1573 | 1573 | }), |
| ... | ... | @@ -1581,7 +1581,7 @@ fn transformExpression( |
| 1581 | 1581 | |
| 1582 | 1582 | return try t.addRef(.tuple_type, .{ |
| 1583 | 1583 | .src_node = ctx.nodeOffset(node), |
| 1584 | .extra_index = try t.extra.append(t.gpa, Teg.TupleType, .{ | |
| 1584 | .extra_index = try t.extra.append(t.gpa, Hir.TupleType, .{ | |
| 1585 | 1585 | .items = items, |
| 1586 | 1586 | }), |
| 1587 | 1587 | }); |
| ... | ... | @@ -1645,7 +1645,7 @@ fn transformExpression( |
| 1645 | 1645 | |
| 1646 | 1646 | return try t.addRef(.func, .{ |
| 1647 | 1647 | .src_node = ctx.nodeOffset(node), |
| 1648 | .extra_index = try t.extra.append(t.gpa, Teg.Func, .{ | |
| 1648 | .extra_index = try t.extra.append(t.gpa, Hir.Func, .{ | |
| 1649 | 1649 | .params = param_list, |
| 1650 | 1650 | .return_type = if (return_type) |ref| ref.toOptional() else .none, |
| 1651 | 1651 | .body = body, |
| ... | ... | @@ -1862,7 +1862,7 @@ const AssignmentTarget = union(enum) { |
| 1862 | 1862 | }), |
| 1863 | 1863 | .field => |field| try t.addRef(.field, .{ |
| 1864 | 1864 | .src_node = field.src_node, |
| 1865 | .extra_index = try t.extra.append(t.gpa, Teg.Bin, .{ | |
| 1865 | .extra_index = try t.extra.append(t.gpa, Hir.Bin, .{ | |
| 1866 | 1866 | .lhs = field.base, |
| 1867 | 1867 | .rhs = field.field, |
| 1868 | 1868 | }), |
| ... | ... | @@ -1874,21 +1874,21 @@ const AssignmentTarget = union(enum) { |
| 1874 | 1874 | return switch (target) { |
| 1875 | 1875 | .memory => |memory| try t.addRef(.store, .{ |
| 1876 | 1876 | .src_node = ctx.nodeOffset(node), |
| 1877 | .extra_index = try t.extra.append(t.gpa, Teg.Store, .{ | |
| 1877 | .extra_index = try t.extra.append(t.gpa, Hir.Store, .{ | |
| 1878 | 1878 | .memory = memory, |
| 1879 | 1879 | .operand = rhs, |
| 1880 | 1880 | }), |
| 1881 | 1881 | }), |
| 1882 | 1882 | .variable_declaration => |var_decl| try t.addRef(.store_decl, .{ |
| 1883 | 1883 | .src_node = ctx.nodeOffset(node), |
| 1884 | .extra_index = try t.extra.append(t.gpa, Teg.StoreVarDecl, .{ | |
| 1884 | .extra_index = try t.extra.append(t.gpa, Hir.StoreVarDecl, .{ | |
| 1885 | 1885 | .var_decl = var_decl.string, |
| 1886 | 1886 | .operand = rhs, |
| 1887 | 1887 | }), |
| 1888 | 1888 | }), |
| 1889 | 1889 | .field => |field| try t.addRef(.store_field, .{ |
| 1890 | 1890 | .src_node = ctx.nodeOffset(node), |
| 1891 | .extra_index = try t.extra.append(t.gpa, Teg.StoreField, .{ | |
| 1891 | .extra_index = try t.extra.append(t.gpa, Hir.StoreField, .{ | |
| 1892 | 1892 | .base = field.base, |
| 1893 | 1893 | .field = field.field, |
| 1894 | 1894 | .operand = rhs, |
| ... | ... | @@ -1998,7 +1998,7 @@ fn transformBlockStatement( |
| 1998 | 1998 | if (value_result != .used) { |
| 1999 | 1999 | break :coerced try t.addRef(.coercion, .{ |
| 2000 | 2000 | .src_node = ctx.nodeOffset(node), |
| 2001 | .extra_index = try t.extra.append(t.gpa, Teg.Coercion, .{ | |
| 2001 | .extra_index = try t.extra.append(t.gpa, Hir.Coercion, .{ | |
| 2002 | 2002 | .type = ref, |
| 2003 | 2003 | .operand = data_ref, |
| 2004 | 2004 | }), |
| ... | ... | @@ -2110,7 +2110,7 @@ fn transformBlockStatement( |
| 2110 | 2110 | } |
| 2111 | 2111 | } |
| 2112 | 2112 | |
| 2113 | fn addUntracked(t: *Transform, comptime tag: Teg.Tag, data: tag.Data()) !Inst.Index { | |
| 2113 | fn addUntracked(t: *Transform, comptime tag: Hir.Tag, data: tag.Data()) !Inst.Index { | |
| 2114 | 2114 | try t.insts.append(t.gpa, .{ |
| 2115 | 2115 | .tag = tag, |
| 2116 | 2116 | .data = .encode(tag, data), |
| ... | ... | @@ -2118,13 +2118,13 @@ fn addUntracked(t: *Transform, comptime tag: Teg.Tag, data: tag.Data()) !Inst.In |
| 2118 | 2118 | return @enumFromInt(t.insts.len - 1); |
| 2119 | 2119 | } |
| 2120 | 2120 | |
| 2121 | fn addIndex(t: *Transform, comptime tag: Teg.Tag, data: tag.Data()) !Inst.Index { | |
| 2121 | fn addIndex(t: *Transform, comptime tag: Hir.Tag, data: tag.Data()) !Inst.Index { | |
| 2122 | 2122 | const index = try t.addUntracked(tag, data); |
| 2123 | 2123 | try t.scratch.add(t.arena, Inst.Index, index); |
| 2124 | 2124 | return index; |
| 2125 | 2125 | } |
| 2126 | 2126 | |
| 2127 | fn addRef(t: *Transform, comptime tag: Teg.Tag, data: tag.Data()) !Inst.Ref { | |
| 2127 | fn addRef(t: *Transform, comptime tag: Hir.Tag, data: tag.Data()) !Inst.Ref { | |
| 2128 | 2128 | return (try t.addIndex(tag, data)).toRef(); |
| 2129 | 2129 | } |
| 2130 | 2130 | |
| ... | ... | @@ -2333,18 +2333,18 @@ const Allocator = mem.Allocator; |
| 2333 | 2333 | const assert = std.debug.assert; |
| 2334 | 2334 | |
| 2335 | 2335 | const core = @import("mod.zig"); |
| 2336 | const Teg = core.Teg; | |
| 2337 | const Inst = Teg.Inst; | |
| 2338 | const NullTerminatedString = Teg.NullTerminatedString; | |
| 2339 | const SlicedString = Teg.SlicedString; | |
| 2340 | const RefList = Teg.RefList; | |
| 2341 | const IndexList = Teg.IndexList; | |
| 2342 | const OptionalRefList = Teg.OptionalRefList; | |
| 2343 | const EncodedData = Teg.EncodedData; | |
| 2344 | const ExtraIndex = Teg.ExtraIndex; | |
| 2336 | const Hir = core.Hir; | |
| 2337 | const Inst = Hir.Inst; | |
| 2338 | const NullTerminatedString = Hir.NullTerminatedString; | |
| 2339 | const SlicedString = Hir.SlicedString; | |
| 2340 | const RefList = Hir.RefList; | |
| 2341 | const IndexList = Hir.IndexList; | |
| 2342 | const OptionalRefList = Hir.OptionalRefList; | |
| 2343 | const EncodedData = Hir.EncodedData; | |
| 2344 | const ExtraIndex = Hir.ExtraIndex; | |
| 2345 | 2345 | |
| 2346 | 2346 | const array = core.array; |
| 2347 | const ExtraStore = array.ExtraStore(.teg, .@"var"); | |
| 2347 | const ExtraStore = array.ExtraStore(.hir, .@"var"); | |
| 2348 | 2348 | const Float = array.Float; |
| 2349 | 2349 | |
| 2350 | 2350 | const Tokenizer = core.Tokenizer; |
src/core/array.zig+1-1| ... | ... | @@ -77,7 +77,7 @@ fn getAsU32(items: []const u32, comptime T: type, index: usize) T { |
| 77 | 77 | |
| 78 | 78 | pub const StoreKind = enum { |
| 79 | 79 | intern_pool, |
| 80 | teg, | |
| 80 | hir, | |
| 81 | 81 | air, |
| 82 | 82 | js_tree, |
| 83 | 83 |
src/core/mod.zig+1-1| ... | ... | @@ -17,7 +17,7 @@ pub const U32Stack = Stack(u32); |
| 17 | 17 | pub const StoredTrace = @import("StoredTrace.zig"); |
| 18 | 18 | pub const DebugStoredTrace = StoredTrace.DebugStoredTrace; |
| 19 | 19 | pub const Queue = @import("queue.zig").Queue; |
| 20 | pub const Teg = @import("Teg.zig"); | |
| 20 | pub const Hir = @import("Hir.zig"); | |
| 21 | 21 | pub const Tokenizer = @import("Tokenizer.zig"); |
| 22 | 22 | pub const Transform = @import("Transform.zig"); |
| 23 | 23 | pub const unicode_props = @import("unicode_props.zig"); |
src/main.zig+2-2| ... | ... | @@ -299,7 +299,7 @@ fn cmdBuildOrRun(ctx: Context, comptime mode: enum { build, run }) !void { |
| 299 | 299 | const main_file = try comp.getFile(file_path); |
| 300 | 300 | |
| 301 | 301 | var fail_report: Report = undefined; |
| 302 | const teg = main_file.getTeg(&comp, &fail_report) catch |err| switch (err) { | |
| 302 | const hir = main_file.getHir(&comp, &fail_report) catch |err| switch (err) { | |
| 303 | 303 | error.TransformFail => { |
| 304 | 304 | std.debug.print("Transform failed:\n", .{}); |
| 305 | 305 | try fail_report.dump(.initComp(&comp, main_file), comp.out); |
| ... | ... | @@ -321,7 +321,7 @@ fn cmdBuildOrRun(ctx: Context, comptime mode: enum { build, run }) !void { |
| 321 | 321 | |
| 322 | 322 | if (comp.options.dump_ir) { |
| 323 | 323 | const stderr = std.io.getStdErr().writer(); |
| 324 | try teg.dumpToWriter(stderr, null); | |
| 324 | try hir.dumpToWriter(stderr, null); | |
| 325 | 325 | } |
| 326 | 326 | |
| 327 | 327 | const entry_point = comp.enqueueEntryModule(main_file) catch |err| switch (err) { |
src/wasm/enum_codegen.zig+3-3| ... | ... | @@ -6,8 +6,8 @@ pub fn main() !void { |
| 6 | 6 | inline for (.{ |
| 7 | 7 | .{ "TokenTag", Tokenizer.Token.Tag }, |
| 8 | 8 | .{ "NodeTag", Ast.Node.Tag }, |
| 9 | .{ "TegInstTag", Teg.Tag }, | |
| 10 | .{ "TegInstRef", Teg.Inst.Ref }, | |
| 9 | .{ "HirInstTag", Hir.Tag }, | |
| 10 | .{ "HirInstRef", Hir.Inst.Ref }, | |
| 11 | 11 | }) |decl| { |
| 12 | 12 | const name, const enum_type = decl; |
| 13 | 13 | |
| ... | ... | @@ -24,4 +24,4 @@ const std = @import("std"); |
| 24 | 24 | const core = @import("core"); |
| 25 | 25 | const Tokenizer = core.Tokenizer; |
| 26 | 26 | const Ast = core.Ast; |
| 27 | const Teg = core.Teg; | |
| 27 | const Hir = core.Hir; |
test/compiler_tests.zig+5-5| ... | ... | @@ -98,7 +98,7 @@ fn runTestCase( |
| 98 | 98 | const main_file = try comp.getFile(file_path); |
| 99 | 99 | |
| 100 | 100 | var fail_report: core.Report = undefined; |
| 101 | const teg = main_file.getTeg(&comp, &fail_report) catch |err| switch (err) { | |
| 101 | const hir = main_file.getHir(&comp, &fail_report) catch |err| switch (err) { | |
| 102 | 102 | error.TransformFail => { |
| 103 | 103 | try out.print("Transform failed:\n", .{}); |
| 104 | 104 | try fail_report.dump(.{ .comp = .{ .comp = &comp, .file = main_file } }, comp.out); |
| ... | ... | @@ -112,7 +112,7 @@ fn runTestCase( |
| 112 | 112 | }; |
| 113 | 113 | |
| 114 | 114 | if (case_options.dump_ir) { |
| 115 | try teg.dumpToWriter(out, .escape_codes); | |
| 115 | try hir.dumpToWriter(out, .escape_codes); | |
| 116 | 116 | } |
| 117 | 117 | |
| 118 | 118 | const entry_point = try comp.enqueueEntryModule(main_file); |
| ... | ... | @@ -121,8 +121,8 @@ fn runTestCase( |
| 121 | 121 | if (comp.temp_flag_had_errors) |
| 122 | 122 | return error.SemaErrors; |
| 123 | 123 | |
| 124 | if (teg.report.warnings.len > 0) | |
| 125 | return error.TegWarnings; | |
| 124 | if (hir.report.warnings.len > 0) | |
| 125 | return error.HirWarnings; | |
| 126 | 126 | |
| 127 | 127 | var js_out: std.ArrayListUnmanaged(u8) = .{}; |
| 128 | 128 | defer js_out.deinit(alloc); |
| ... | ... | @@ -227,7 +227,7 @@ pub fn runTestCaseWrap( |
| 227 | 227 | const stack = switch (err) { |
| 228 | 228 | error.TransformFail, |
| 229 | 229 | error.ParseFail, |
| 230 | error.TegWarnings, | |
| 230 | error.HirWarnings, | |
| 231 | 231 | error.SemaErrors, |
| 232 | 232 | error.AnalysisFail, |
| 233 | 233 | => core.StoredTrace.empty, |