@nova-lang/cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/src/main.zig ADDED
@@ -0,0 +1,147 @@
1
+ const std = @import("std");
2
+ const types = @import("types.zig");
3
+ const lexer_mod = @import("lexer.zig");
4
+ const parser_mod = @import("parser.zig");
5
+ const interpreter_mod = @import("interpreter.zig");
6
+ const renderer_mod = @import("renderer.zig");
7
+
8
+ pub fn main() !void {
9
+ var arena = std.heap.ArenaAllocator.init(std.heap.page_allocator);
10
+ defer arena.deinit();
11
+ const allocator = arena.allocator();
12
+
13
+ var args_list = std.ArrayList([]const u8).init(allocator);
14
+ {
15
+ var args_iter = try std.process.Args.Iterator.initAllocator(std.process.args, allocator);
16
+ defer args_iter.deinit();
17
+ while (try args_iter.next()) |arg| {
18
+ try args_list.append(try allocator.dupe(u8, arg));
19
+ }
20
+ }
21
+
22
+ if (args_list.items.len < 2) {
23
+ std.debug.print("Usage: nova <input.nv> [output.html]\n", .{});
24
+ std.debug.print(" nova lex <input.nv>\n", .{});
25
+ std.debug.print(" nova ast <input.nv>\n", .{});
26
+ return;
27
+ }
28
+
29
+ const command = args_list.items[1];
30
+ if (std.mem.eql(u8, command, "lex") or std.mem.eql(u8, command, "ast")) {
31
+ if (args_list.items.len < 3) {
32
+ std.debug.print("Usage: nova {s} <input.nv>\n", .{command});
33
+ return;
34
+ }
35
+ const input_file = args_list.items[2];
36
+ const source = try readFile(allocator, input_file);
37
+ var lexer = lexer_mod.Lexer.init(allocator, source);
38
+ defer lexer.deinit();
39
+ const tokens = try lexer.getTokens();
40
+ if (std.mem.eql(u8, command, "lex")) {
41
+ for (tokens.items) |tok| {
42
+ const padding = " "[@tagName(tok.type).len..];
43
+ std.debug.print("{s}{s} '{s}' L:{} C:{}\n", .{
44
+ @tagName(tok.type), padding, tok.value, tok.line, tok.col,
45
+ });
46
+ }
47
+ } else {
48
+ var pool = types.AstPool.init(allocator);
49
+ var parser = parser_mod.Parser.init(allocator, tokens, &pool);
50
+ const doc = parser.parse() catch |err| {
51
+ std.debug.print("Parse error: {}\n", .{err});
52
+ return;
53
+ };
54
+ printAST(doc, 0);
55
+ }
56
+ return;
57
+ }
58
+
59
+ const input_file = args_list.items[1];
60
+ const output_file = if (args_list.items.len > 2) args_list.items[2] else "";
61
+ const source = readFile(allocator, input_file) catch {
62
+ std.debug.print("Error: file not found: {s}\n", .{input_file});
63
+ return;
64
+ };
65
+
66
+ var lexer = lexer_mod.Lexer.init(allocator, source);
67
+ defer lexer.deinit();
68
+ const tokens = lexer.getTokens() catch |err| {
69
+ std.debug.print("Lex error: {}\n", .{err});
70
+ return;
71
+ };
72
+
73
+ var pool = types.AstPool.init(allocator);
74
+ var parser = parser_mod.Parser.init(allocator, tokens, &pool);
75
+ const doc = parser.parse() catch |err| {
76
+ std.debug.print("Parse error: {}\n", .{err});
77
+ return;
78
+ };
79
+
80
+ var interp = interpreter_mod.Interpreter.init(allocator);
81
+ defer interp.deinit();
82
+ const evaled_doc = interp.evalDocument(@constCast(&doc)) catch |err| {
83
+ std.debug.print("Interpretation error: {}\n", .{err});
84
+ return;
85
+ };
86
+
87
+ var renderer = renderer_mod.Renderer.init(allocator);
88
+ defer renderer.deinit();
89
+ const html = renderer.render(evaled_doc) catch |err| {
90
+ std.debug.print("Render error: {}\n", .{err});
91
+ return;
92
+ };
93
+
94
+ if (output_file.len > 0) {
95
+ const file = std.fs.cwd().createFile(output_file, .{}) catch |err| {
96
+ std.debug.print("Error creating output file: {}\n", .{err});
97
+ return;
98
+ };
99
+ defer file.close();
100
+ _ = file.write(html) catch {};
101
+ std.debug.print("Written to {s}\n", .{output_file});
102
+ } else {
103
+ std.debug.print("{s}", .{html});
104
+ }
105
+ }
106
+
107
+ fn readFile(allocator: std.mem.Allocator, path: []const u8) ![]const u8 {
108
+ const file = std.fs.cwd().openFile(path, .{}) catch return error.FileNotFound;
109
+ defer file.close();
110
+ return file.readToEndAlloc(allocator, 1_000_000);
111
+ }
112
+
113
+ fn printAST(node: types.Node, indent: u32) void {
114
+ var i: u32 = 0;
115
+ while (i < indent) : (i += 1) std.debug.print(" ", .{});
116
+ switch (node.tag) {
117
+ .document => {
118
+ std.debug.print("Document\n", .{});
119
+ for (node.data.document.children.items) |child| printAST(child, indent + 1);
120
+ },
121
+ .text => std.debug.print("Text(value='{s}')\n", .{node.data.text.value}),
122
+ .block => {
123
+ const b = &node.data.block;
124
+ std.debug.print("Block(name='{s}', attrs={any}, inline_content=[], position=null)\n", .{ b.name, b.attrs });
125
+ for (b.children.items) |child| printAST(child, indent + 1);
126
+ },
127
+ .inline_block => {
128
+ const ib = &node.data.inline_block;
129
+ std.debug.print("InlineBlock(name='{s}', attrs={any}, content=[])\n", .{ ib.name, ib.attrs });
130
+ },
131
+ .math_inline => std.debug.print("MathInline(source='{s}')\n", .{node.data.math_inline.source}),
132
+ .math_display => std.debug.print("MathDisplay(source='{s}')\n", .{node.data.math_display.source}),
133
+ .interpolation => std.debug.print("Interpolation(expression='{s}')\n", .{node.data.interpolation.expression}),
134
+ .list_block => std.debug.print("ListBlock(ordered={})\n", .{node.data.list_block.ordered}),
135
+ .table_block => std.debug.print("TableBlock\n", .{}),
136
+ .schema_def => std.debug.print("SchemaDef(name='{s}')\n", .{node.data.schema_def.name}),
137
+ .service_def => std.debug.print("ServiceDef(name='{s}')\n", .{node.data.service_def.name}),
138
+ .macro_def => std.debug.print("MacroDef(name='{s}')\n", .{node.data.macro_def.name}),
139
+ .if_block => std.debug.print("IfBlock(condition='{s}')\n", .{node.data.if_block.condition}),
140
+ .for_block => std.debug.print("ForBlock(var='{s}', iterable='{s}')\n", .{ node.data.for_block.var_name, node.data.for_block.iterable }),
141
+ .use_block => std.debug.print("UseBlock(path='{s}')\n", .{node.data.use_block.path}),
142
+ .meta_block => std.debug.print("MetaBlock\n", .{}),
143
+ .biblio_entry => std.debug.print("BiblioEntry(key='{s}')\n", .{node.data.biblio_entry.key}),
144
+ .field_def => std.debug.print("FieldDef\n", .{}),
145
+ .method_def => std.debug.print("MethodDef\n", .{}),
146
+ }
147
+ }