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 }