summaryrefslogtreecommitdiff
path: root/tangle.lp
diff options
context:
space:
mode:
authoreudoxia <uplink@distress.network>2022-03-31 10:19:21 -0400
committereudoxia <uplink@distress.network>2022-03-31 10:19:21 -0400
commit27f4773b122a2758cfaf88537c9e1a8ad5df7e69 (patch)
treef6a31476fee7208d1ceb49186b243b106b09a5bd /tangle.lp
initial
Diffstat (limited to 'tangle.lp')
-rw-r--r--tangle.lp100
1 files changed, 100 insertions, 0 deletions
diff --git a/tangle.lp b/tangle.lp
new file mode 100644
index 0000000..f0a99e1
--- /dev/null
+++ b/tangle.lp
@@ -0,0 +1,100 @@
+# tangle.zig
+
+The structure of this file is quite similar to that of `weave.zig`, only differing in terms of which functions are used to transform the input data.
+
+@: *
+@= Imports
+
+pub fn main() !u8 {
+ @= IO initialization
+
+ @= Allocator initialization
+
+ @= Read file from stdin
+
+ @= Split into lines
+
+ @= Parse lines into sections
+
+ @= Generate code
+
+ @= Write to stdout
+
+ return 0;
+}
+@.
+
+First we import the other files containing the core functions.
+
+@: Imports
+const std = @import("std");
+const data = @import("data.zig");
+const log = @import("log.zig").log;
+
+const Allocator = std.mem.Allocator;
+@.
+
+Within the main procedure, we first initialize the stdin and stdout interfaces.
+
+@: IO initialization
+const stdin = std.io.getStdIn();
+const stdout = std.io.getStdOut();
+@.
+
+We then initialize the allocator, deferring its deinitialization to the end of the process. Since the overall memory usage pattern is one in which all resources may be freed at once, the arena allocator is the most appropriate choice for this program.
+
+@: Allocator initialization
+var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
+var alloc = arena.allocator();
+defer arena.deinit();
+@.
+
+The input file is then read from stdin. In the case of input exceeding the maximum permitted file size, the program may report the error and exit normally. All other errors which may be returned are memory allocation failures and should thus yield control to the panic handler.
+
+@: Read file from stdin
+const input = stdin.reader().readAllAlloc(alloc, data.input_max) catch |err| switch (err) {
+ error.StreamTooLong => {
+ log(.err, "input too large (maximum {})", .{std.fmt.fmtIntSizeBin(data.input_max)});
+ return 1;
+ },
+ else => |e| return e,
+};
+@.
+
+We then pass the input into the line splitting function, creating an array of strings.
+
+@: Split into lines
+const lines = try data.split_lines(input, alloc);
+@.
+
+The lines are then passed into the parsing function, which may return a parsing error. Logging such errors is handled by the function itself, and thus the errors are handled here solely by exiting.
+
+@: Parse lines into sections
+const sections = data.parse(lines, alloc) catch |err| switch (err) {
+ error.UnexpectedStart,
+ error.UnexpectedEnd => {
+ return 1;
+ },
+ else => |e| return e,
+};
+@.
+
+The code file is then generated. This entails resolving references to section names, which may return an error, handled by exiting as above.
+
+@: Generate code
+const code = data.codegen(lines, sections, alloc) catch |err| switch (err) {
+ error.DereferenceLimit,
+ error.NotFound => {
+ return 1;
+ },
+ else => |e| return e,
+};
+@.
+
+Finally, the lines of the code file are written to stdout, separated by newlines.
+
+@: Write to stdout
+for (code) |line| {
+ try stdout.writer().print("{s}\n", .{line});
+}
+@.