Skip to content

Commit d9bfdb4

Browse files
authored
Update main.zig
1 parent 0478b1f commit d9bfdb4

File tree

1 file changed

+21
-267
lines changed

1 file changed

+21
-267
lines changed

hacker-parser/main.zig

Lines changed: 21 additions & 267 deletions
Original file line numberDiff line numberDiff line change
@@ -1,246 +1,6 @@
11
const std = @import("std");
2-
const HACKER_DIR_SUFFIX = "/.hackeros/hacker-lang";
3-
fn parse_hacker_file(allocator: std.mem.Allocator, file_path: []const u8, verbose: bool) !struct {
4-
deps: std.StringHashMap(void),
5-
libs: std.StringHashMap(void),
6-
vars_dict: std.StringHashMap([]const u8),
7-
cmds: std.ArrayList([]const u8),
8-
includes: std.ArrayList([]const u8),
9-
binaries: std.ArrayList([]const u8),
10-
errors: std.ArrayList([]const u8),
11-
config_data: std.StringHashMap([]const u8),
12-
} {
13-
var deps = std.StringHashMap(void).init(allocator);
14-
var libs = std.StringHashMap(void).init(allocator);
15-
var vars_dict = std.StringHashMap([]const u8).init(allocator);
16-
var cmds = std.ArrayList([]const u8).init(allocator);
17-
var includes = std.ArrayList([]const u8).init(allocator);
18-
var binaries = std.ArrayList([]const u8).init(allocator);
19-
var errors = std.ArrayList([]const u8).init(allocator);
20-
var config_data = std.StringHashMap([]const u8).init(allocator);
21-
var in_config = false;
22-
var line_num: u32 = 0;
23-
const home = std.posix.getenv("HOME") orelse "";
24-
const hacker_dir = try std.fs.path.join(allocator, &.{ home, HACKER_DIR_SUFFIX });
25-
defer allocator.free(hacker_dir);
26-
const console = std.io.getStdOut().writer();
27-
const file = std.fs.cwd().openFile(file_path, .{}) catch |err| {
28-
if (err == error.FileNotFound) {
29-
if (verbose) try console.print("File {s} not found\n", .{file_path});
30-
try errors.append(try std.fmt.allocPrint(allocator, "File {s} not found", .{file_path}));
31-
return .{
32-
.deps = deps,
33-
.libs = libs,
34-
.vars_dict = vars_dict,
35-
.cmds = cmds,
36-
.includes = includes,
37-
.binaries = binaries,
38-
.errors = errors,
39-
.config_data = config_data,
40-
};
41-
}
42-
return err;
43-
};
44-
defer file.close();
45-
const reader = file.reader();
46-
var line_buf: [4096]u8 = undefined;
47-
while (reader.readUntilDelimiterOrEof(&line_buf, '\n') catch null) |line_slice| {
48-
line_num += 1;
49-
const line_trimmed = std.mem.trim(u8, line_slice, " \t\r\n");
50-
if (line_trimmed.len == 0) continue;
51-
const line = try allocator.dupe(u8, line_trimmed);
52-
defer allocator.free(line);
53-
if (std.mem.eql(u8, line, "[")) {
54-
if (in_config) {
55-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Nested config section", .{line_num}));
56-
}
57-
in_config = true;
58-
continue;
59-
} else if (std.mem.eql(u8, line, "]")) {
60-
if (!in_config) {
61-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Closing ] without [", .{line_num}));
62-
}
63-
in_config = false;
64-
continue;
65-
}
66-
if (in_config) {
67-
if (std.mem.indexOfScalar(u8, line, '=')) |eq_pos| {
68-
const key = std.mem.trim(u8, line[0..eq_pos], " \t");
69-
const value = std.mem.trim(u8, line[eq_pos + 1 ..], " \t");
70-
try config_data.put(try allocator.dupe(u8, key), try allocator.dupe(u8, value));
71-
}
72-
continue;
73-
}
74-
if (std.mem.startsWith(u8, line, "//")) {
75-
const dep = std.mem.trim(u8, line[2..], " \t");
76-
if (dep.len > 0) {
77-
_ = try deps.put(try allocator.dupe(u8, dep), {});
78-
} else {
79-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Empty system dependency", .{line_num}));
80-
}
81-
} else if (std.mem.startsWith(u8, line, "#")) {
82-
const lib = std.mem.trim(u8, line[1..], " \t");
83-
if (lib.len > 0) {
84-
const lib_dir = try std.fs.path.join(allocator, &.{ hacker_dir, "libs", lib });
85-
defer allocator.free(lib_dir);
86-
const lib_hacker_path = try std.fs.path.join(allocator, &.{ lib_dir, "main.hacker" });
87-
defer allocator.free(lib_hacker_path);
88-
const lib_bin_path = try std.fs.path.join(allocator, &.{ hacker_dir, "libs", lib });
89-
defer allocator.free(lib_bin_path);
90-
if (std.fs.cwd().access(lib_hacker_path, .{})) |_| {
91-
try includes.append(try allocator.dupe(u8, lib));
92-
var sub = try parse_hacker_file(allocator, lib_hacker_path, verbose);
93-
var dep_it = sub.deps.keyIterator();
94-
while (dep_it.next()) |sub_dep_ptr| {
95-
const sub_dep = sub_dep_ptr.*;
96-
_ = try deps.put(try allocator.dupe(u8, sub_dep), {});
97-
}
98-
var lib_it = sub.libs.keyIterator();
99-
while (lib_it.next()) |sub_lib_ptr| {
100-
const sub_lib = sub_lib_ptr.*;
101-
_ = try libs.put(try allocator.dupe(u8, sub_lib), {});
102-
}
103-
{
104-
var sub_it = sub.vars_dict.iterator();
105-
while (sub_it.next()) |entry| {
106-
try vars_dict.put(try allocator.dupe(u8, entry.key_ptr.*), try allocator.dupe(u8, entry.value_ptr.*));
107-
}
108-
}
109-
try cmds.appendSlice(sub.cmds.items);
110-
try includes.appendSlice(sub.includes.items);
111-
try binaries.appendSlice(sub.binaries.items);
112-
for (sub.errors.items) |sub_err| {
113-
try errors.append(try std.fmt.allocPrint(allocator, "In {s}: {s}", .{ lib, sub_err }));
114-
}
115-
// Deinit sub resources
116-
sub.deps.deinit();
117-
sub.libs.deinit();
118-
sub.vars_dict.deinit();
119-
sub.cmds.deinit();
120-
sub.includes.deinit();
121-
sub.binaries.deinit();
122-
sub.errors.deinit();
123-
sub.config_data.deinit();
124-
} else |_| {} // ignore access error for now
125-
if (std.posix.access(lib_bin_path, std.posix.X_OK)) |_| {
126-
try binaries.append(try allocator.dupe(u8, lib_bin_path));
127-
} else |_| {
128-
_ = try libs.put(try allocator.dupe(u8, lib), {});
129-
}
130-
} else {
131-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Empty library/include", .{line_num}));
132-
}
133-
} else if (std.mem.startsWith(u8, line, ">")) {
134-
const cmd_part = std.mem.trim(u8, if (std.mem.indexOfScalar(u8, line[1..], '!')) |pos| line[1 .. 1 + pos] else line[1..], " \t");
135-
if (cmd_part.len > 0) {
136-
try cmds.append(try allocator.dupe(u8, cmd_part));
137-
} else {
138-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Empty command", .{line_num}));
139-
}
140-
} else if (std.mem.startsWith(u8, line, "@")) {
141-
if (std.mem.indexOfScalar(u8, line[1..], '=')) |eq_pos| {
142-
const var_name = std.mem.trim(u8, line[1 .. 1 + eq_pos], " \t");
143-
const value = std.mem.trim(u8, line[1 + eq_pos + 1 ..], " \t");
144-
if (var_name.len > 0 and value.len > 0) {
145-
try vars_dict.put(try allocator.dupe(u8, var_name), try allocator.dupe(u8, value));
146-
} else {
147-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Invalid variable", .{line_num}));
148-
}
149-
} else {
150-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Missing = in variable", .{line_num}));
151-
}
152-
} else if (std.mem.startsWith(u8, line, "=")) {
153-
if (std.mem.indexOfScalar(u8, line[1..], '>')) |gt_pos| {
154-
const num_str = std.mem.trim(u8, line[1 .. 1 + gt_pos], " \t");
155-
const cmd_part = std.mem.trim(u8, if (std.mem.indexOfScalar(u8, line[1 + gt_pos + 1 ..], '!')) |pos| line[1 + gt_pos + 1 .. 1 + gt_pos + 1 + pos] else line[1 + gt_pos + 1 ..], " \t");
156-
const num = std.fmt.parseInt(i32, num_str, 10) catch {
157-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Invalid loop count", .{line_num}));
158-
continue;
159-
};
160-
if (num < 0) {
161-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Negative loop count", .{line_num}));
162-
continue;
163-
}
164-
if (cmd_part.len > 0) {
165-
var i: i32 = 0;
166-
while (i < num) : (i += 1) {
167-
try cmds.append(try allocator.dupe(u8, cmd_part));
168-
}
169-
} else {
170-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Empty loop command", .{line_num}));
171-
}
172-
} else {
173-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Invalid loop syntax", .{line_num}));
174-
}
175-
} else if (std.mem.startsWith(u8, line, "?")) {
176-
if (std.mem.indexOfScalar(u8, line[1..], '>')) |gt_pos| {
177-
const condition = std.mem.trim(u8, line[1 .. 1 + gt_pos], " \t");
178-
const cmd_part = std.mem.trim(u8, if (std.mem.indexOfScalar(u8, line[1 + gt_pos + 1 ..], '!')) |pos| line[1 + gt_pos + 1 .. 1 + gt_pos + 1 + pos] else line[1 + gt_pos + 1 ..], " \t");
179-
if (condition.len > 0 and cmd_part.len > 0) {
180-
const if_cmd = try std.fmt.allocPrint(allocator, "if {s}; then {s}; fi", .{ condition, cmd_part });
181-
try cmds.append(if_cmd);
182-
} else {
183-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Invalid conditional", .{line_num}));
184-
}
185-
} else {
186-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Invalid conditional syntax", .{line_num}));
187-
}
188-
} else if (std.mem.startsWith(u8, line, "&")) {
189-
const cmd_part = std.mem.trim(u8, if (std.mem.indexOfScalar(u8, line[1..], '!')) |pos| line[1 .. 1 + pos] else line[1..], " \t");
190-
if (cmd_part.len > 0) {
191-
const bg_cmd = try std.fmt.allocPrint(allocator, "{s} &", .{ cmd_part });
192-
try cmds.append(bg_cmd);
193-
} else {
194-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Empty background command", .{line_num}));
195-
}
196-
} else if (std.mem.startsWith(u8, line, "!")) {
197-
// pass
198-
} else {
199-
try errors.append(try std.fmt.allocPrint(allocator, "Line {d}: Invalid syntax", .{line_num}));
200-
}
201-
}
202-
if (in_config) {
203-
try errors.append(try allocator.dupe(u8, "Unclosed config section"));
204-
}
205-
if (verbose) {
206-
var dep_keys = try allocator.alloc([]const u8, deps.count());
207-
defer allocator.free(dep_keys);
208-
var i: usize = 0;
209-
var dep_it = deps.keyIterator();
210-
while (dep_it.next()) |key| {
211-
dep_keys[i] = key.*;
212-
i += 1;
213-
}
214-
try console.print("System Deps: {any}\n", .{dep_keys});
215-
var lib_keys = try allocator.alloc([]const u8, libs.count());
216-
defer allocator.free(lib_keys);
217-
i = 0;
218-
var lib_it = libs.keyIterator();
219-
while (lib_it.next()) |key| {
220-
lib_keys[i] = key.*;
221-
i += 1;
222-
}
223-
try console.print("Custom Libs: {any}\n", .{lib_keys});
224-
try console.print("Vars: {any}\n", .{vars_dict});
225-
try console.print("Cmds: {any}\n", .{cmds.items});
226-
try console.print("Includes: {any}\n", .{includes.items});
227-
try console.print("Binaries: {any}\n", .{binaries.items});
228-
try console.print("Config: {any}\n", .{config_data});
229-
if (errors.items.len > 0) {
230-
try console.print("Errors: {any}\n", .{errors.items});
231-
}
232-
}
233-
return .{
234-
.deps = deps,
235-
.libs = libs,
236-
.vars_dict = vars_dict,
237-
.cmds = cmds,
238-
.includes = includes,
239-
.binaries = binaries,
240-
.errors = errors,
241-
.config_data = config_data,
242-
};
243-
}
2+
const parse = @import("parse.zig");
3+
const utils = @import("utils.zig");
2444
pub fn main() !void {
2455
var gpa = std.heap.GeneralPurposeAllocator(.{}){};
2466
defer _ = gpa.deinit();
@@ -262,43 +22,29 @@ pub fn main() !void {
26222
try std.io.getStdErr().writer().print("Usage: hacker-parser [--verbose] <file>\n", .{});
26323
std.process.exit(1);
26424
}
265-
var res = try parse_hacker_file(allocator, file_path.?, verbose);
266-
defer res.deps.deinit();
267-
defer res.libs.deinit();
268-
defer res.vars_dict.deinit();
269-
defer res.cmds.deinit();
270-
defer res.includes.deinit();
271-
defer res.binaries.deinit();
272-
defer res.errors.deinit();
273-
defer res.config_data.deinit();
274-
var deps_list = std.ArrayList([]const u8).init(allocator);
275-
defer deps_list.deinit();
276-
var dep_it = res.deps.keyIterator();
277-
while (dep_it.next()) |key| {
278-
try deps_list.append(key.*);
279-
}
280-
var libs_list = std.ArrayList([]const u8).init(allocator);
281-
defer libs_list.deinit();
282-
var lib_it = res.libs.keyIterator();
283-
while (lib_it.next()) |key| {
284-
try libs_list.append(key.*);
285-
}
25+
var res = try parse.parse_hacker_file(allocator, file_path.?, verbose);
26+
defer utils.deinitParseResult(&res, allocator);
27+
try outputJson(res);
28+
}
29+
fn outputJson(res: parse.ParseResult) !void {
28630
const stdout = std.io.getStdOut().writer();
28731
try stdout.print("{{", .{});
28832
try stdout.print("\"deps\":[", .{});
28933
var first = true;
290-
for (deps_list.items) |d| {
34+
var dep_it = res.deps.keyIterator();
35+
while (dep_it.next()) |key| {
29136
if (!first) try stdout.print(",", .{});
29237
first = false;
293-
try std.json.encodeJsonString(d, .{}, stdout);
38+
try std.json.encodeJsonString(key.*, .{}, stdout);
29439
}
29540
try stdout.print("],", .{});
29641
try stdout.print("\"libs\":[", .{});
29742
first = true;
298-
for (libs_list.items) |l| {
43+
var lib_it = res.libs.keyIterator();
44+
while (lib_it.next()) |key| {
29945
if (!first) try stdout.print(",", .{});
30046
first = false;
301-
try std.json.encodeJsonString(l, .{}, stdout);
47+
try std.json.encodeJsonString(key.*, .{}, stdout);
30248
}
30349
try stdout.print("],", .{});
30450
try stdout.print("\"vars\":{{", .{});
@@ -336,6 +82,14 @@ pub fn main() !void {
33682
try std.json.encodeJsonString(b, .{}, stdout);
33783
}
33884
try stdout.print("],", .{});
85+
try stdout.print("\"plugins\":[", .{});
86+
first = true;
87+
for (res.plugins.items) |p| {
88+
if (!first) try stdout.print(",", .{});
89+
first = false;
90+
try std.json.encodeJsonString(p, .{}, stdout);
91+
}
92+
try stdout.print("],", .{});
33993
try stdout.print("\"errors\":[", .{});
34094
first = true;
34195
for (res.errors.items) |e| {

0 commit comments

Comments
 (0)