Skip to content

Commit 5a4095a

Browse files
committed
Rough implementations of IRs for all stages
1 parent 5e4ff44 commit 5a4095a

33 files changed

+3668
-0
lines changed

src/base.zig

Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
const region = @import("base/region.zig");
2+
const symbol = @import("base/symbol.zig");
3+
const module = @import("base/module.zig");
4+
const package = @import("base/package.zig");
5+
const primitive = @import("base/primitive.zig");
6+
const env = @import("base/env.zig");
7+
8+
pub const Region = region.Region;
9+
pub const Position = region.Position;
10+
pub const LineAndColumn = region.LineAndColumn;
11+
12+
pub const Ident = symbol.Ident;
13+
pub const IdentAttributes = symbol.IdentAttributes;
14+
pub const IdentProblems = symbol.IdentProblems;
15+
pub const IdentId = symbol.IdentId;
16+
pub const IdentStore = symbol.IdentStore;
17+
pub const Symbol = symbol.Symbol;
18+
pub const SymbolStore = symbol.SymbolStore;
19+
20+
pub const Module = module.Module;
21+
pub const ModuleId = module.ModuleId;
22+
pub const ModuleStore = module.ModuleStore;
23+
24+
pub const Package = package.Package;
25+
pub const PackageId = package.PackageId;
26+
pub const PackageStore = package.PackageStore;
27+
28+
pub const Primitive = primitive.Primitive;
29+
pub const Literal = primitive.Literal;
30+
31+
pub const ModuleEnv = env.ModuleEnv;
32+
pub const GlobalEnv = env.GlobalEnv;
33+
34+
pub const Recursive = enum {
35+
NotRecursive,
36+
Recursive,
37+
TailRecursive,
38+
};
39+
40+
// TODO: can this be smaller than u32?
41+
/// Source of crash, and its runtime representation to roc_panic.
42+
pub const CrashOrigin = enum(u32) {
43+
/// The crash is due to Roc, either via a builtin or type error.
44+
Roc = 0,
45+
/// The crash is user-defined.
46+
User = 1,
47+
};
48+
49+
pub const LowLevel = .{};
50+
51+
// TODO: move to relevant stages
52+
pub const TypeVar = struct { id: u32 };

src/base/env.zig

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
const std = @import("std");
2+
const base = @import("../base.zig");
3+
const cols = @import("../collections.zig");
4+
const problem = @import("../problem.zig");
5+
6+
pub const ModuleEnv = struct {
7+
symbols: base.SymbolStore,
8+
modules: base.ModuleStore,
9+
strings: cols.LargeStringInterner,
10+
tag_names: cols.TagNameInterner,
11+
tag_ids_for_slicing: cols.SafeList(cols.TagNameId),
12+
field_names: cols.FieldNameInterner,
13+
field_ids_for_slicing: cols.SafeList(cols.FieldNameId),
14+
problems: cols.SafeList(problem.Problem),
15+
// TODO: where are these used, and how do we manage them?
16+
// pub tuple_elem_indices: Vec<usize>,
17+
// pub record_fields: Vec<RecordField<()>>,
18+
19+
pub fn init(allocator: std.mem.Allocator) ModuleEnv {
20+
return ModuleEnv{
21+
.symbols = base.SymbolStore.init(allocator),
22+
.modules = base.ModuleStore.init(allocator),
23+
.strings = cols.LargeStringInterner.init(allocator),
24+
.tag_names = cols.TagNameInterner.init(allocator),
25+
.tag_ids_for_slicing = cols.SafeList(cols.TagNameId).init(allocator),
26+
.field_names = cols.FieldNameInterner.init(allocator),
27+
.field_ids_for_slicing = cols.SafeList(cols.FieldNameId).init(allocator),
28+
.problems = cols.SafeList(problem.Problem).init(allocator),
29+
};
30+
}
31+
32+
pub fn deinit(self: *ModuleEnv) void {
33+
self.symbols.deinit();
34+
self.modules.deinit();
35+
self.strings.deinit();
36+
self.tag_names.deinit();
37+
self.tag_ids_for_slicing.deinit();
38+
self.field_names.deinit();
39+
self.field_ids_for_slicing.deinit();
40+
self.problems.deinit();
41+
}
42+
43+
pub fn addTagNameSlice(
44+
self: *ModuleEnv,
45+
name_ids: []cols.TagNameId,
46+
) cols.SafeList(cols.TagNameId).Slice {
47+
return self.tag_ids_for_slicing.appendSlice(name_ids);
48+
}
49+
50+
pub fn addFieldNameSlice(
51+
self: *ModuleEnv,
52+
name_ids: []cols.FieldNameId,
53+
) cols.SafeList(cols.FieldNameId).Slice {
54+
return self.field_ids_for_slicing.appendSlice(name_ids);
55+
}
56+
};
57+
58+
pub const GlobalEnv = struct {
59+
// TODO: do we need this if each module manages this?
60+
modules: base.ModuleStore,
61+
packages: base.PackageStore,
62+
63+
pub fn init(allocator: std.mem.Allocator) GlobalEnv {
64+
return GlobalEnv{
65+
.modules = base.ModuleStore.init(allocator),
66+
.packages = base.PackageStore.init(allocator),
67+
};
68+
}
69+
70+
pub fn deinit(self: *GlobalEnv) void {
71+
self.modules.deinit();
72+
self.packages.deinit();
73+
}
74+
};

src/base/module.zig

Lines changed: 75 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,75 @@
1+
const std = @import("std");
2+
const cols = @import("../collections.zig");
3+
4+
pub const ModuleId = struct { id: u32 };
5+
6+
pub const Module = struct {
7+
name: []u8,
8+
package_shorthand: ?[]u8,
9+
is_builtin: bool,
10+
};
11+
12+
pub const ModuleStore = struct {
13+
modules: cols.SafeMultiList(Module),
14+
15+
pub fn init(allocator: std.mem.Allocator) ModuleStore {
16+
const modules = cols.SafeMultiList(Module).init(allocator);
17+
modules.append(Module{
18+
.id = 0,
19+
.name = &.{},
20+
.base_name = &.{},
21+
.package_shorthand = null,
22+
.is_builtin = false,
23+
});
24+
25+
// TODO: insert builtins automatically?
26+
27+
return ModuleStore{ .modules = modules };
28+
}
29+
30+
pub fn deinit(self: *ModuleStore) void {
31+
self.modules.deinit();
32+
}
33+
34+
pub fn lookup(self: *ModuleStore, name: []const u8, package_shorthand: ?[]const u8) ?ModuleId {
35+
const items = self.modules.items;
36+
37+
for (0..self.modules.len()) |index| {
38+
const other_name = items.items(.name_segments)[index];
39+
if (name == other_name) {
40+
const other_package_shorthand = items.items(.package_shorthand)[index];
41+
if (other_package_shorthand == package_shorthand) {
42+
return ModuleId{ .id = @as(u32, index) };
43+
}
44+
}
45+
}
46+
47+
return null;
48+
}
49+
50+
pub fn getOrInsert(
51+
self: *ModuleStore,
52+
name: []const u8,
53+
package_shorthand: ?[]const u8,
54+
) ModuleId {
55+
if (self.lookup(name, package_shorthand)) |id| {
56+
return id;
57+
} else {
58+
const new_id = self.modules.insert(Module{
59+
.name = name,
60+
.package_shorthand = package_shorthand,
61+
.is_builtin = false,
62+
});
63+
64+
return ModuleId{ .id = new_id.id };
65+
}
66+
}
67+
68+
pub fn getName(self: *ModuleStore, id: ModuleId) []u8 {
69+
return self.modules.items.items(.name)[@as(usize, id.id)];
70+
}
71+
72+
pub fn getPackageShorthand(self: *ModuleStore, id: ModuleId) ?[]u8 {
73+
return self.modules.items.items(.package_shorthand)[@as(usize, id.id)];
74+
}
75+
};

src/base/package.zig

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
const std = @import("std");
2+
3+
pub const PackageId = struct { id: u32 };
4+
5+
pub const Package = struct {
6+
id: PackageId,
7+
/// The BLAKE3 hash of the tarball's contents. Also the .tar filename on disk.
8+
content_hash: []u8,
9+
/// On disk, this will be the subfolder inside the cache dir where the package lives
10+
cache_subdir: []u8,
11+
/// Other code will default this to main.roc, but this module isn't concerned with that default.
12+
root_module_filename: ?[]u8,
13+
};
14+
15+
pub const PackageStore = struct {
16+
allocator: std.mem.Allocator,
17+
packages: std.MultiArrayList(Package),
18+
19+
pub fn init(allocator: std.mem.Allocator) PackageStore {
20+
return PackageStore{
21+
.allocator = allocator,
22+
.packages = std.MultiArrayList(Package),
23+
};
24+
}
25+
26+
pub fn deinit(self: *PackageStore) void {
27+
self.packages.deinit();
28+
}
29+
};

src/base/primitive.zig

Lines changed: 70 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,70 @@
1+
const cols = @import("../collections.zig");
2+
3+
// TODO: figure out how to combine enums and union(enum)s at comptime
4+
// to avoid them being multilevel
5+
6+
pub const Primitive = union(enum) {
7+
Int: Int,
8+
Float: Float,
9+
Bool,
10+
Str,
11+
Crash,
12+
13+
pub const Int = enum {
14+
U8,
15+
I8,
16+
U16,
17+
I16,
18+
U32,
19+
I32,
20+
U64,
21+
I64,
22+
U128,
23+
I128,
24+
};
25+
26+
pub const Float = enum {
27+
F32,
28+
F64,
29+
Dec,
30+
};
31+
32+
pub const Num = union(enum) {
33+
Int: Int,
34+
Float: Float,
35+
};
36+
};
37+
38+
pub const Literal = union(enum) {
39+
Int: Int,
40+
Float: Float,
41+
Bool: bool,
42+
Str: cols.LargeStringId,
43+
Crash: cols.LargeStringId,
44+
45+
pub const Int = union(enum) {
46+
I8: i8,
47+
U8: u8,
48+
I16: i16,
49+
U16: u16,
50+
I32: i32,
51+
U32: u32,
52+
I64: i64,
53+
U64: u64,
54+
I128: i128,
55+
U128: u128,
56+
};
57+
58+
pub const Float = union(enum) {
59+
F32: f32,
60+
F64: f64,
61+
// We represent Dec as a large int divided by 10^18, which is the maximum
62+
// number of decimal places that allows lossless conversion of U64 to Dec
63+
Dec: u128,
64+
};
65+
66+
pub const Num = union(enum) {
67+
Int: Int,
68+
Float: Float,
69+
};
70+
};

src/base/region.zig

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
const std = @import("std");
2+
3+
pub const Region = struct {
4+
start: Position,
5+
end: Position,
6+
7+
pub fn format(self: *const Region, comptime fmt: []const u8, _: std.fmt.FormatOptions, writer: anytype) !void {
8+
if (fmt.len != 0) {
9+
std.fmt.invalidFmtError(fmt, self);
10+
}
11+
12+
if ((self.start == Position.zero()) and (self.end == Position.zero())) {
13+
// In tests, it's super common to set all Located values to 0.
14+
// Also in tests, we don't want to bother printing the locations
15+
// because it makes failed assertions much harder to read.
16+
return writer.print("…", .{});
17+
} else {
18+
return writer.print("@{}-{}", .{ self.start.offset, self.end.offset });
19+
}
20+
}
21+
};
22+
23+
pub const Position = struct {
24+
offset: u32,
25+
26+
pub fn zero() Position {
27+
return Position{ .offset = 0 };
28+
}
29+
};
30+
31+
pub const LineAndColumn = packed struct(u32) {
32+
line: u20,
33+
column: u12,
34+
};

0 commit comments

Comments
 (0)