migrate to 12.0
[ta-parkour.git] / parkour / fmt.lua
blobb84ef24e53824b6f3e0da794bf273e3e24fc04b5
1 -- SPDX-License-Identifier: GPL-3.0-or-later
2 -- © 2020 Georgi Kirilov
4 local M = {}
6 local function get_special(words, list)
7 local head = list[1] and list[1].text
8 return head and (words[head] or words[0] and words[0]:match(head))
9 end
11 local function adjust_bracket_p(self, indices, nodes, range)
12 local parent = nodes[#nodes - 1]
13 if not parent then return true end
14 local nth = indices[#indices]
15 if not nth then
16 local _, nxt = parent.find_after(range, function() return true end)
17 nth = nxt or #parent + 1
18 end
19 local sexp = parent[nth] or parent[#parent]
20 local distance = nth - (sexp and range.start == sexp.finish + 1 and 0 or 1)
21 local rule = get_special(self.squarewords, parent)
22 if type(rule) == "number" then
23 if rule < 0 then
24 return -rule > distance
25 elseif rule > 0 then
26 -- XXX: the "[" check is because in Fennel fn has optional name
27 return rule < distance or sexp.d == "["
28 end
29 elseif not rule then
30 local grandparent, pnth = nodes[#nodes - 2], indices[#indices - 1]
31 if not grandparent then return true end
32 rule = get_special(self.squarewords, grandparent)
33 if not rule or type(rule) ~= "table" then return true end
34 local _, first_list_arg = grandparent.find_after(grandparent[1], function(t) return t.is_list end)
35 local first_nonlist_uncle = first_list_arg - 1
36 -- TODO: handle negative rule[1] and rule[2] (just for consistency with the scalar rules)
37 -- first_nonlist_uncle is checked so we can handle both let and named let:
38 if (not rule[1] or first_nonlist_uncle + rule[1] >= pnth) then
39 if (not rule[2] or rule[2] >= distance + 1) then
40 if parent[distance] then
41 -- allows mixing [clauses] with #:when conditions in Racket for loops:
42 if parent[distance].is_list then
43 return false
44 end
45 else
46 return false
47 end
48 end
49 end
50 end
51 return true
52 end
54 local function last_distinguished(self, list)
55 return get_special(self.lispwords, list)
56 end
58 function M.new(lispwords, squarewords)
59 return {
60 lispwords = lispwords,
61 squarewords = squarewords,
62 last_distinguished = last_distinguished,
63 adjust_bracket_p = adjust_bracket_p,
65 end
67 return M