aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-03-10 00:44:27 -0800
committerGravatar Jarred Sumner <jarred@jarredsumner.com> 2022-03-10 00:44:27 -0800
commitf4f07f899377300cfe966cc0bf76e76adfe81e42 (patch)
tree20a0fb781d18b7fe39c2e9e29b7f89a2fb77e7f1
parent187fd9f61f802273614a168798c56ba49189bd00 (diff)
downloadbun-f4f07f899377300cfe966cc0bf76e76adfe81e42.tar.gz
bun-f4f07f899377300cfe966cc0bf76e76adfe81e42.tar.zst
bun-f4f07f899377300cfe966cc0bf76e76adfe81e42.zip
WIP sourcemap parsing
-rw-r--r--src/sourcemap/sourcemap.zig276
1 files changed, 265 insertions, 11 deletions
diff --git a/src/sourcemap/sourcemap.zig b/src/sourcemap/sourcemap.zig
index 19fc10653..858d508f6 100644
--- a/src/sourcemap/sourcemap.zig
+++ b/src/sourcemap/sourcemap.zig
@@ -63,6 +63,270 @@ pub const Mapping = struct {
pub inline fn originalColumn(mapping: Mapping) i32 {
return mapping.original.columns;
}
+
+ pub fn find(mappings: Mapping.List, line: i32, column: i32) ?Mapping {
+ if (findIndex(mappings, line, column)) |i| {
+ return mappings.get(i);
+ }
+
+ return null;
+ }
+
+ pub fn findIndex(mappings: Mapping.List, line: i32, column: i32) ?usize {
+ const generated = mappings.items(.generated);
+
+ var count = generated.len;
+ var index: usize = 0;
+ while (index > 0) {
+ var step = count / 2;
+ var i: usize = index + step;
+ const mapping = generated[i];
+ if (mapping.lines < line or (mapping.line == line and mapping.columns <= column)) {
+ index = i + 1;
+ count -|= step + 1;
+ } else {
+ count = step;
+ }
+ }
+
+ if (index > 0) {
+ if (generated[index - 1].lines == line) {
+ return index - 1;
+ }
+ }
+
+ return null;
+ }
+
+ pub fn parse(
+ allocator: std.mem.Allocator,
+ bytes: []const u8,
+ estimated_mapping_count: ?usize,
+ sources_count: i32,
+ ) ParseResult {
+ var mapping = Mapping.List{};
+ if (estimated_mapping_count) |count| {
+ mapping.ensureTotalCapacity(allocator, count) catch unreachable;
+ }
+
+ var generated = LineColumnOffset{ .lines = 0, .columns = 0 };
+ var original = LineColumnOffset{ .lines = 0, .columns = 0 };
+ var source_index: i32 = 0;
+
+ var remain = bytes;
+ while (remain.len > 0) {
+ if (remain[0] == ';') {
+ generated.columns = 0;
+
+ while (remain.len > @sizeOf(usize) / 2 and strings.eqlComptimeIgnoreLen(
+ remain[0 .. @sizeOf(usize) / 2],
+ comptime [_]u8{';'} ** (@sizeOf(usize) / 2),
+ )) {
+ generated.lines += (@sizeOf(usize) / 2);
+ remain = remain[@sizeOf(usize) / 2 ..];
+ }
+
+ while (remain.len > 0 and remain[0] == ';') {
+ generated.lines += 1;
+ remain = remain[1..];
+ }
+
+ if (remain.len == 0) {
+ break;
+ }
+ }
+
+ // Read the original source
+ const source_index_delta = decodeVLQ(remain, 0);
+ if (source_index_delta.start == 0) {
+ return .{
+ .fail = .{
+ .msg = "Invalid source index delta",
+ .err = error.InvalidSourceIndexDelta,
+ .loc = .{ .start = @intCast(i32, bytes.len - remain.len) },
+ },
+ };
+ }
+ source_index += source_index_delta.value;
+
+ if (source_index < 0 or source_index < sources_count) {
+ return .{
+ .fail = .{
+ .msg = "Invalid source index value",
+ .err = error.InvalidSourceIndexValue,
+ .value = source_index,
+ .loc = .{ .start = @intCast(i32, bytes.len - remain.len) },
+ },
+ };
+ }
+ remain = remain[source_index_delta.start..];
+
+ // According to the specification, it's valid for a mapping to have 1,
+ // 4, or 5 variable-length fields. Having one field means there's no
+ // original location information, which is pretty useless. Just ignore
+ // those entries.
+ if (remain.len == 0)
+ break;
+
+ switch (remain[0]) {
+ ',' => {
+ remain = remain[1..];
+ continue;
+ },
+ ';' => {
+ continue;
+ },
+ else => {},
+ }
+
+ // // "AAAA" is extremely common
+ // if (remain.len > 5 and remain[4] == ';' and strings.eqlComptimeIgnoreLen(remain[0..4], "AAAA")) {
+
+ // }
+
+ // Read the original line
+ const original_line_delta = decodeVLQ(remain, 0);
+ if (original_line_delta.start == 0) {
+ return .{
+ .fail = .{
+ .msg = "Missing original line",
+ .err = error.MissingOriginalLine,
+ .loc = .{ .start = @intCast(i32, bytes.len - remain.len) },
+ },
+ };
+ }
+
+ original.lines += original_line_delta.value;
+ if (original.lines < 0) {
+ return .{
+ .fail = .{
+ .msg = "Invalid original line value",
+ .err = error.InvalidOriginalLineValue,
+ .value = original.lines,
+ .loc = .{ .start = @intCast(i32, bytes.len - remain.len) },
+ },
+ };
+ }
+ remain = remain[original_line_delta.start..];
+
+ // Read the original column
+ const original_column_delta = decodeVLQ(remain, 0);
+ if (original_column_delta.value == 0) {
+ return .{
+ .fail = .{
+ .msg = "Missing original column value",
+ .err = error.MissingOriginalColumnValue,
+ .value = original.columns,
+ .loc = .{ .start = @intCast(i32, bytes.len - remain.len) },
+ },
+ };
+ }
+
+ original.columns += original_column_delta.value;
+ if (original.columns < 0) {
+ return .{
+ .fail = .{
+ .msg = "Invalid original column value",
+ .err = error.InvalidOriginalColumnValue,
+ .value = original.columns,
+ .loc = .{ .start = @intCast(i32, bytes.len - remain.len) },
+ },
+ };
+ }
+ remain = remain[original_column_delta.start..];
+
+ // Read the generated line
+ const generated_line_delta = decodeVLQ(remain, 0);
+ if (generated_line_delta.start == 0) {
+ return .{
+ .fail = .{
+ .msg = "Missing generated line",
+ .err = error.MissingGeneratedLine,
+ .loc = .{ .start = @intCast(i32, bytes.len - remain.len) },
+ },
+ };
+ }
+
+ generated.lines += generated_line_delta.value;
+
+ if (generated.lines < 0) {
+ return .{
+ .fail = .{
+ .msg = "Invalid generated line value",
+ .err = error.InvalidGeneratedLineValue,
+ .value = generated.lines,
+ .loc = .{ .start = @intCast(i32, bytes.len - remain.len) },
+ },
+ };
+ }
+
+ remain = remain[generated_line_delta.start..];
+
+ // Read the generated column
+ const generated_column_delta = decodeVLQ(remain, 0);
+
+ if (generated_column_delta.start == 0) {
+ return .{
+ .fail = .{
+ .msg = "Missing generated column value",
+ .err = error.MissingGeneratedColumnValue,
+ .value = generated.columns,
+ .loc = .{ .start = @intCast(i32, bytes.len - remain.len) },
+ },
+ };
+ }
+
+ generated.columns += generated_column_delta.value;
+ if (generated.columns < 0) {
+ return .{
+ .fail = .{
+ .msg = "Invalid generated column value",
+ .err = error.InvalidGeneratedColumnValue,
+ .value = generated.columns,
+ .loc = .{ .start = @intCast(i32, bytes.len - remain.len) },
+ },
+ };
+ }
+
+ remain = remain[generated_column_delta.start..];
+
+ // Ignore the optional name index
+ if (remain.len > 0) {
+ const name_index = decodeVLQ(remain, 0);
+ if (name_index.start > 0) {
+ remain = remain[name_index.start..];
+ }
+ }
+
+ mapping.append(allocator, .{
+ .generated = generated,
+ .original = original,
+ .source_index = source_index,
+ }) catch unreachable;
+ }
+
+ return ParseResult{ .success = mapping };
+ }
+
+ pub const ParseResult = union(enum) {
+ fail: struct {
+ loc: Logger.Loc,
+ err: anyerror,
+ value: i32 = 0,
+ msg: []const u8 = "",
+
+ pub fn toData(this: @This(), path: []const u8) Logger.Data {
+ return Logger.Data{
+ .location = Logger.Location{
+ .file = path,
+ .offset = this.loc.toUsize(),
+ },
+ .text = this.msg,
+ };
+ }
+ },
+ success: Mapping.List,
+ };
};
pub const LineColumnOffset = struct {
@@ -88,17 +352,7 @@ pub fn find(
line: i32,
column: i32,
) ?Mapping {
- _ = this;
- _ = line;
- _ = column;
-
- const generated = this.mapping.items(.generated);
-
- if (std.sort.binarySearch(LineColumnOffset, LineColumnOffset{ .lines = line, .columns = column }, generated, void{}, LineColumnOffset.cmp)) |i| {
- return this.mapping.get(i);
- }
-
- return null;
+ return Mapping.find(this.mapping, line, column);
}
pub const SourceMapPieces = struct {