-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathparse.zig
More file actions
151 lines (128 loc) · 6.19 KB
/
parse.zig
File metadata and controls
151 lines (128 loc) · 6.19 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
//! Makefile.am parser for Zig 0.15.1 (uses std.fs.cwd() API).
//! For Zig master, see parse_newio.zig.
const std = @import("std");
allocator: std.mem.Allocator,
upstream_path: std.Build.LazyPath,
b: *std.Build,
/// Stub type for API compatibility with parse_newio.zig.
pub const Io = void;
pub fn init(allocator: std.mem.Allocator, _: Io, upstream_path: std.Build.LazyPath, b: *std.Build) @This() {
return .{ .allocator = allocator, .upstream_path = upstream_path, .b = b };
}
pub fn parseMakefileAm(self: @This(), folder: []const u8, var_prefix: []const u8) ![]const []const u8 {
const upstream_dir = self.upstream_path.getPath(self.b);
const makefile_path = try std.fmt.allocPrint(self.allocator, "{s}/{s}/Makefile.am", .{ upstream_dir, folder });
defer self.allocator.free(makefile_path);
const content = try std.fs.cwd().readFileAlloc(self.allocator, makefile_path, std.math.maxInt(usize));
defer self.allocator.free(content);
return parseContent(self.allocator, content, folder, var_prefix);
}
pub fn findSimdFiles(self: @This(), dir_path: []const u8, suffix: []const u8) ![]const []const u8 {
const upstream_dir = self.upstream_path.getPath(self.b);
const full_path = try std.fmt.allocPrint(self.allocator, "{s}/{s}", .{ upstream_dir, dir_path });
defer self.allocator.free(full_path);
var result: std.ArrayList([]const u8) = .empty;
errdefer {
for (result.items) |item| self.allocator.free(item);
result.deinit(self.allocator);
}
var dir = std.fs.cwd().openDir(full_path, .{ .iterate = true }) catch |err| switch (err) {
error.FileNotFound => return result.toOwnedSlice(self.allocator),
else => return err,
};
defer dir.close();
var iter = dir.iterate();
while (try iter.next()) |entry| {
if (entry.kind == .file and std.mem.endsWith(u8, entry.name, suffix)) {
try result.append(self.allocator, try std.fmt.allocPrint(self.allocator, "{s}/{s}", .{ dir_path, entry.name }));
}
}
return result.toOwnedSlice(self.allocator);
}
fn parseContent(allocator: std.mem.Allocator, content: []const u8, folder: []const u8, var_prefix: []const u8) ![]const []const u8 {
var var_map = std.StringHashMap(std.ArrayList([]const u8)).init(allocator);
defer {
var it = var_map.iterator();
while (it.next()) |entry| {
for (entry.value_ptr.items) |item| allocator.free(item);
entry.value_ptr.deinit(allocator);
}
var_map.deinit();
}
// First pass: collect variable definitions
var lines = std.mem.splitScalar(u8, content, '\n');
while (lines.next()) |line| {
const trimmed = std.mem.trim(u8, line, " \t");
if (trimmed.len == 0 or trimmed[0] == '#') continue;
if (std.mem.indexOf(u8, trimmed, "_SOURCES") == null) continue;
const eq_pos = if (std.mem.indexOf(u8, trimmed, " += ")) |pos| pos + 4 else if (std.mem.indexOf(u8, trimmed, "=")) |pos| pos + 1 else continue;
const var_name = std.mem.trim(u8, trimmed[0 .. eq_pos - 1], " \t");
const files_str = std.mem.trim(u8, trimmed[eq_pos..], " \t");
if (files_str.len == 0) continue;
const idx = std.mem.lastIndexOf(u8, var_name, "_SOURCES") orelse continue;
const base_var = var_name[0..idx];
const gop = try var_map.getOrPut(base_var);
if (!gop.found_existing) gop.value_ptr.* = .empty;
var remaining = files_str;
while (remaining.len > 0) {
remaining = std.mem.trimLeft(u8, remaining, " \t");
if (remaining.len == 0) break;
if (remaining.len >= 2 and remaining[0] == '$' and remaining[1] == '(') {
const close = std.mem.indexOfScalar(u8, remaining[2..], ')') orelse break;
try gop.value_ptr.append(allocator, try allocator.dupe(u8, remaining[0 .. 3 + close]));
remaining = remaining[3 + close ..];
} else {
var end: usize = 0;
while (end < remaining.len and remaining[end] != ' ') end += 1;
const file = remaining[0..end];
remaining = remaining[end..];
if (std.mem.endsWith(u8, file, ".c")) {
try gop.value_ptr.append(allocator, try allocator.dupe(u8, file));
}
}
}
}
// Second pass: resolve references
var result: std.ArrayList([]const u8) = .empty;
errdefer {
for (result.items) |item| allocator.free(item);
result.deinit(allocator);
}
var visited = std.StringHashMap(void).init(allocator);
defer visited.deinit();
const resolve = struct {
fn f(alloc: std.mem.Allocator, map: *const std.StringHashMap(std.ArrayList([]const u8)), key: []const u8, vis: *std.StringHashMap(void), res: *std.ArrayList([]const u8)) !void {
const k = if (std.mem.endsWith(u8, key, "_SOURCES")) key[0 .. key.len - 8] else key;
if (vis.contains(k)) return;
try vis.put(k, {});
if (map.get(k)) |files| {
for (files.items) |item| {
if (item.len >= 3 and item[0] == '$' and item[1] == '(') {
const close = std.mem.indexOfScalar(u8, item[2..], ')') orelse continue;
try f(alloc, map, item[2 .. 2 + close], vis, res);
} else {
try res.append(alloc, try alloc.dupe(u8, item));
}
}
}
}
}.f;
if (var_map.get(var_prefix)) |files| {
for (files.items) |item| {
if (item.len >= 3 and item[0] == '$' and item[1] == '(') {
const close = std.mem.indexOfScalar(u8, item[2..], ')') orelse continue;
visited.clearRetainingCapacity();
try resolve(allocator, &var_map, item[2 .. 2 + close], &visited, &result);
} else {
try result.append(allocator, try allocator.dupe(u8, item));
}
}
}
// Prepend folder path
for (result.items) |*file| {
const original = file.*;
file.* = try std.fmt.allocPrint(allocator, "{s}/{s}", .{ folder, original });
allocator.free(original);
}
return result.toOwnedSlice(allocator);
}