summaryrefslogtreecommitdiff
path: root/mac/.config/mpv/script-modules/utf8/charclass/compiletime/builder.lua
blob: 9d9c603fa5ff4bfa4d2f761f5d1b4ad66381372b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
return function(utf8)

local byte = utf8.byte
local unpack = utf8.config.unpack

local builder = {}
local mt = {__index = builder}

utf8.regex.compiletime.charclass.builder = builder

function builder.new()
  return setmetatable({}, mt)
end

function builder:invert()
  self.inverted = true
  return self
end

function builder:internal() -- is it enclosed in []
  self.internal = true
  return self
end

function builder:with_codes(...)
  local codes = {...}
  self.codes = self.codes or {}

  for _, v in ipairs(codes) do
    table.insert(self.codes, type(v) == "number" and v or byte(v))
  end

  table.sort(self.codes)
  return self
end

function builder:with_ranges(...)
  local ranges = {...}
  self.ranges = self.ranges or {}

  for _, v in ipairs(ranges) do
    table.insert(self.ranges, v)
  end

  return self
end

function builder:with_classes(...)
  local classes = {...}
  self.classes = self.classes or {}

  for _, v in ipairs(classes) do
    table.insert(self.classes, v)
  end

  return self
end

function builder:without_classes(...)
  local not_classes = {...}
  self.not_classes = self.not_classes or {}

  for _, v in ipairs(not_classes) do
    table.insert(self.not_classes, v)
  end

  return self
end

function builder:include(b)
  if not b.inverted then
    if b.codes then
      self:with_codes(unpack(b.codes))
    end
    if b.ranges then
      self:with_ranges(unpack(b.ranges))
    end
    if b.classes then
      self:with_classes(unpack(b.classes))
    end
    if b.not_classes then
      self:without_classes(unpack(b.not_classes))
    end
  else
    self.includes = self.includes or {}
    self.includes[#self.includes + 1] = b
  end
  return self
end

function builder:build()
  if self.codes and #self.codes == 1 and not self.inverted and not self.ranges and not self.classes and not self.not_classes and not self.includes then
    return "{test = function(self, cc) return cc == " .. self.codes[1] .. " end}"
  else
    local codes_list = table.concat(self.codes or {}, ', ')
    local ranges_list = ''
    for i, r in ipairs(self.ranges or {}) do ranges_list = ranges_list .. (i > 1 and ', {' or '{') .. tostring(r[1]) .. ', ' .. tostring(r[2]) .. '}' end
    local classes_list = ''
    if self.classes then classes_list = "'" .. table.concat(self.classes, "', '") .. "'" end
    local not_classes_list = ''
    if self.not_classes then not_classes_list = "'" .. table.concat(self.not_classes, "', '") .. "'" end

    local subs_list = ''
    for i, r in ipairs(self.includes or {}) do subs_list = subs_list .. (i > 1 and ', ' or '') .. r:build() .. '' end

    local src = [[cl.new():with_codes(
        ]] .. codes_list .. [[
      ):with_ranges(
        ]] .. ranges_list .. [[
      ):with_classes(
        ]] .. classes_list .. [[
      ):without_classes(
        ]] .. not_classes_list .. [[
      ):with_subs(
        ]] .. subs_list .. [[
      )]]

    if self.inverted then
      src = src .. ':invert()'
    end

    return src
  end
end

return builder

end