lib/pluck/src/toplevel/forms.zig
daab053ee43316e1809a84551d573ddd1e5bf3d2
1 const std = @import("std");
2 const pluck = @import("../root.zig");
3
4 const pexpr = pluck.pexpr;
5 const PExpr = pexpr.PExpr;
6 const Symbol = pexpr.Symbol;
7
8 const context_owner = @import("context.zig");
9 const ToplevelContext = context_owner.ToplevelContext;
10 const top_types = @import("types.zig");
11 const ToplevelError = top_types.ToplevelError;
12 const result_owner = @import("result.zig");
13 const QueryResult = result_owner.QueryResult;
14 const definitions_owner = @import("definitions.zig");
15 const query_owner = @import("query.zig");
16 const source_owner = @import("source.zig");
17
18 pub fn processForm(self: *ToplevelContext, source: []const u8) ToplevelError!?QueryResult {
19 return processFormSexpr(self, source);
20 }
21
22 pub fn processFormSexpr(self: *ToplevelContext, source: []const u8) ToplevelError!?QueryResult {
23 const arena_alloc = self.arena.allocator();
24
25 self.last_query_constructor_typo = null;
26
27 const source_copy = arena_alloc.dupe(u8, source) catch return ToplevelError.OutOfMemory;
28 self.current_source = source_copy;
29
30 const tokens = pexpr.tokenize(arena_alloc, source) catch return failParse(self);
31 defer pexpr.freeTokens(arena_alloc, tokens);
32
33 if (tokens.len == 0) {
34 return null;
35 }
36
37 if (tokens.len >= 2 and std.mem.eql(u8, tokens[0], "(")) {
38 if (std.mem.eql(u8, tokens[1], "define")) {
39 try processDefine(self, tokens);
40 return null;
41 }
42 if (std.mem.eql(u8, tokens[1], "define-type")) {
43 try processDefineType(self, tokens);
44 return null;
45 }
46 if (std.mem.eql(u8, tokens[1], "query")) {
47 return try processQuery(self, tokens);
48 }
49 }
50
51 return try processExprQuery(self, tokens);
52 }
53
54 pub fn processDefine(self: *ToplevelContext, tokens: []const pexpr.Token) ToplevelError!void {
55 const arena_alloc = self.arena.allocator();
56
57 if (tokens.len < 4) {
58 return ToplevelError.InvalidDefineForm;
59 }
60
61 var pos: usize = 2;
62
63 if (std.mem.eql(u8, tokens[pos], "(")) {
64 return processDefineFunction(self, tokens);
65 }
66
67 const name = tokens[pos];
68 pos += 1;
69
70 if (!source_owner.isIdentifier(name)) {
71 return ToplevelError.InvalidDefineForm;
72 }
73
74 const duped_name = arena_alloc.dupe(u8, name) catch return ToplevelError.OutOfMemory;
75 const prev_def = self.definitions.remove(duped_name);
76 const dummy = PExpr.init(arena_alloc, .{ .construct = .{ .constructor = "Unit" } }) catch return ToplevelError.OutOfMemory;
77 self.definitions.define(duped_name, dummy) catch return ToplevelError.OutOfMemory;
78
79 errdefer {
80 _ = self.definitions.remove(duped_name);
81 if (prev_def) |expr| {
82 self.definitions.define(duped_name, expr) catch {};
83 }
84 }
85
86 const remaining_tokens = tokens[pos..];
87
88 if (remaining_tokens.len < 2) {
89 return ToplevelError.InvalidDefineForm;
90 }
91
92 var parser = pexpr.Parser.init(arena_alloc, remaining_tokens, &self.types, &self.definitions);
93 defer parser.deinit();
94
95 const expr = parser.parseExpr() catch return failParse(self);
96
97 if (parser.peek()) |tok| {
98 if (!std.mem.eql(u8, tok, ")")) {
99 return ToplevelError.InvalidDefineForm;
100 }
101 }
102
103 _ = definitions_owner.defineWithDocTrackChange(self, duped_name, expr, null) catch return ToplevelError.OutOfMemory;
104 }
105
106 pub fn processDefineFunction(self: *ToplevelContext, tokens: []const pexpr.Token) ToplevelError!void {
107 const arena_alloc = self.arena.allocator();
108
109 var pos: usize = 3;
110
111 if (pos >= tokens.len) return ToplevelError.InvalidDefineForm;
112 const name = tokens[pos];
113 pos += 1;
114
115 if (!source_owner.isIdentifier(name)) {
116 return ToplevelError.InvalidDefineForm;
117 }
118
119 const duped_name = arena_alloc.dupe(u8, name) catch return ToplevelError.OutOfMemory;
120 const prev_def = self.definitions.remove(duped_name);
121 const dummy = PExpr.init(arena_alloc, .{ .construct = .{ .constructor = "Unit" } }) catch return ToplevelError.OutOfMemory;
122 self.definitions.define(duped_name, dummy) catch return ToplevelError.OutOfMemory;
123
124 errdefer {
125 _ = self.definitions.remove(duped_name);
126 if (prev_def) |expr| {
127 self.definitions.define(duped_name, expr) catch {};
128 }
129 }
130
131 var args: std.ArrayList(Symbol) = .empty;
132 defer args.deinit(arena_alloc);
133
134 while (pos < tokens.len) {
135 const tok = tokens[pos];
136 if (std.mem.eql(u8, tok, ")")) {
137 pos += 1;
138 break;
139 }
140 if (!source_owner.isIdentifier(tok)) {
141 return ToplevelError.InvalidDefineForm;
142 }
143 args.append(arena_alloc, tok) catch return ToplevelError.OutOfMemory;
144 pos += 1;
145 }
146
147 const body_tokens = tokens[pos..];
148 if (body_tokens.len < 2) {
149 return ToplevelError.InvalidDefineForm;
150 }
151
152 var parser = pexpr.Parser.init(arena_alloc, body_tokens, &self.types, &self.definitions);
153 defer parser.deinit();
154
155 for (args.items) |arg| {
156 parser.pushEnv(arg) catch return ToplevelError.OutOfMemory;
157 }
158
159 const body = parser.parseExpr() catch return failParse(self);
160
161 for (args.items) |_| {
162 parser.popEnv();
163 }
164
165 var result = body;
166 var i = args.items.len;
167 while (i > 0) {
168 i -= 1;
169 const arg_name = arena_alloc.dupe(u8, args.items[i]) catch return ToplevelError.OutOfMemory;
170 result = PExpr.initWithArgs(arena_alloc, .{ .abs = .{ .var_name = arg_name } }, &.{result}) catch return ToplevelError.OutOfMemory;
171 }
172
173 if (args.items.len == 0) {
174 result = PExpr.initWithArgs(arena_alloc, .{ .abs = .{ .var_name = "_" } }, &.{result}) catch return ToplevelError.OutOfMemory;
175 }
176
177 _ = definitions_owner.defineWithDocTrackChange(self, duped_name, result, null) catch return ToplevelError.OutOfMemory;
178 }
179
180 pub fn processDefineType(self: *ToplevelContext, tokens: []const pexpr.Token) ToplevelError!void {
181 const arena_alloc = self.arena.allocator();
182
183 if (tokens.len < 5) {
184 return ToplevelError.InvalidDefineTypeForm;
185 }
186
187 var pos: usize = 2;
188
189 const type_name = tokens[pos];
190 pos += 1;
191
192 if (!source_owner.isIdentifier(type_name)) {
193 return ToplevelError.InvalidDefineTypeForm;
194 }
195
196 const CtorNameArgs = struct { name: Symbol, args: []const Symbol };
197 var parsed_ctors: std.ArrayList(CtorNameArgs) = .empty;
198 defer parsed_ctors.deinit(arena_alloc);
199
200 while (pos < tokens.len) {
201 const tok = tokens[pos];
202
203 if (std.mem.eql(u8, tok, ")")) {
204 break;
205 }
206
207 if (!std.mem.eql(u8, tok, "(")) {
208 return ToplevelError.InvalidDefineTypeForm;
209 }
210 pos += 1;
211
212 if (pos >= tokens.len) return ToplevelError.InvalidDefineTypeForm;
213 const ctor_name = tokens[pos];
214 pos += 1;
215
216 if (!source_owner.isConstructorName(ctor_name)) {
217 return ToplevelError.InvalidDefineTypeForm;
218 }
219
220 var ctor_args: std.ArrayList(Symbol) = .empty;
221 defer ctor_args.deinit(arena_alloc);
222
223 while (pos < tokens.len) {
224 const arg_tok = tokens[pos];
225 if (std.mem.eql(u8, arg_tok, ")")) {
226 pos += 1;
227 break;
228 }
229 ctor_args.append(arena_alloc, arg_tok) catch return ToplevelError.OutOfMemory;
230 pos += 1;
231 }
232
233 const args_slice = ctor_args.toOwnedSlice(arena_alloc) catch return ToplevelError.OutOfMemory;
234 parsed_ctors.append(arena_alloc, .{ .name = ctor_name, .args = args_slice }) catch return ToplevelError.OutOfMemory;
235 }
236
237 if (parsed_ctors.items.len == 0) {
238 return ToplevelError.InvalidDefineTypeForm;
239 }
240
241 const type_name_duped = arena_alloc.dupe(u8, type_name) catch return ToplevelError.OutOfMemory;
242 for (parsed_ctors.items) |ctor| {
243 const ctor_name_duped = arena_alloc.dupe(u8, ctor.name) catch return ToplevelError.OutOfMemory;
244 try self.types.type_of_constructor.put(ctor_name_duped, type_name_duped);
245 const args_copy = arena_alloc.alloc(Symbol, ctor.args.len) catch return ToplevelError.OutOfMemory;
246 for (ctor.args, 0..) |arg, i| {
247 args_copy[i] = arena_alloc.dupe(u8, arg) catch return ToplevelError.OutOfMemory;
248 }
249 try self.types.args_of_constructor.put(ctor_name_duped, args_copy);
250 }
251 const ctor_names = arena_alloc.alloc(Symbol, parsed_ctors.items.len) catch return ToplevelError.OutOfMemory;
252 for (parsed_ctors.items, 0..) |ctor, i| {
253 ctor_names[i] = arena_alloc.dupe(u8, ctor.name) catch return ToplevelError.OutOfMemory;
254 }
255 try self.types.constructors_of_type.put(type_name_duped, ctor_names);
256 }
257
258 pub fn processQuery(self: *ToplevelContext, tokens: []const pexpr.Token) ToplevelError!QueryResult {
259 const arena_alloc = self.arena.allocator();
260
261 if (tokens.len < 4) {
262 return ToplevelError.InvalidQueryForm;
263 }
264
265 var expr_start: usize = 2;
266 if (tokens.len > 4) {
267 const maybe_name = tokens[2];
268 const next_token = tokens[3];
269 if (source_owner.isIdentifier(maybe_name) and !std.mem.eql(u8, next_token, ")")) {
270 expr_start = 3;
271 }
272 }
273
274 const expr_tokens = tokens[expr_start..];
275
276 var parser = pexpr.Parser.init(arena_alloc, expr_tokens, &self.types, &self.definitions);
277 defer parser.deinit();
278
279 const expr = parser.parseExpr() catch return failParse(self);
280
281 return query_owner.runQuery(self, expr);
282 }
283
284 pub fn processExprQuery(self: *ToplevelContext, tokens: []const pexpr.Token) ToplevelError!QueryResult {
285 const arena_alloc = self.arena.allocator();
286
287 var parser = pexpr.Parser.init(arena_alloc, tokens, &self.types, &self.definitions);
288 defer parser.deinit();
289
290 const expr = parser.parseExpr() catch return failParse(self);
291
292 return query_owner.runQuery(self, expr);
293 }
294
295 fn failParse(self: *ToplevelContext) ToplevelError {
296 if (self.current_source) |source| {
297 self.last_error_span = source_owner.spanFromOffsets(source, 0, source.len);
298 }
299 return ToplevelError.ParseError;
300 }