• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

andremm / lua-parser / #8

07 Jan 2026 04:52PM UTC coverage: 97.719% (-0.7%) from 98.416%
#8

push

github

andremm
fixing ci syntax

2099 of 2148 relevant lines covered (97.72%)

23.42 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

86.64
/lua-parser/pp.lua
1
--[[
2
This module impements a pretty printer to the AST
3
]]
4
local pp = {}
1 ✔
5

6
local block2str, stm2str, exp2str, var2str
7
local explist2str, varlist2str, parlist2str, fieldlist2str
8

9
local function iscntrl (x)
10
  if (x >= 0 and x <= 31) or (x == 127) then return true end
281 ✔
11
  return false
278 ✔
12
end
13

14
local function isprint (x)
15
  return not iscntrl(x)
281 ✔
16
end
17

18
local function fixed_string (str)
19
  local new_str = ""
34 ✔
20
  for i=1,string.len(str) do
346 ✔
21
    char = string.byte(str, i)
312 ✔
22
    if char == 34 then new_str = new_str .. string.format("\\\"")
312 ✔
23
    elseif char == 92 then new_str = new_str .. string.format("\\\\")
308 ✔
24
    elseif char == 7 then new_str = new_str .. string.format("\\a")
300 ✔
25
    elseif char == 8 then new_str = new_str .. string.format("\\b")
298 ✔
26
    elseif char == 12 then new_str = new_str .. string.format("\\f")
298 ✔
27
    elseif char == 10 then new_str = new_str .. string.format("\\n")
298 ✔
28
    elseif char == 13 then new_str = new_str .. string.format("\\r")
283 ✔
29
    elseif char == 9 then new_str = new_str .. string.format("\\t")
283 ✔
30
    elseif char == 11 then new_str = new_str .. string.format("\\v")
281 ✔
31
    else
32
      if isprint(char) then
281 ✔
33
        new_str = new_str .. string.format("%c", char)
278 ✔
34
      else
35
        new_str = new_str .. string.format("\\%03d", char)
3 ✔
36
      end
37
    end
38
  end
39
  return new_str
34 ✔
40
end
41

42
local function name2str (name)
43
  return string.format('"%s"', name)
228 ✔
44
end
45

46
local function boolean2str (b)
47
  return string.format('"%s"', tostring(b))
2 ✔
48
end
49

50
local function number2str (n)
51
  return string.format('"%s"', tostring(n))
123 ✔
52
end
53

54
local function string2str (s)
55
  return string.format('"%s"', fixed_string(s))
34 ✔
56
end
57

58
function var2str (var)
×
59
  local tag = var.tag
173 ✔
60
  local str = "`" .. tag
173 ✔
61
  if tag == "Id" then -- `Id{ <string> }
173 ✔
62
    str = str .. " " .. name2str(var[1])
161 ✔
63
  elseif tag == "Index" then -- `Index{ expr expr }
12 ✔
64
    str = str .. "{ "
12 ✔
65
    str = str .. exp2str(var[1]) .. ", "
12 ✔
66
    str = str .. exp2str(var[2])
12 ✔
67
    str = str .. " }"
12 ✔
68
  else
69
    error("expecting a variable, but got a " .. tag)
×
70
  end
71
  return str
173 ✔
72
end
73

74
function varlist2str (varlist)
×
75
  local l = {}
83 ✔
76
  for k, v in ipairs(varlist) do
180 ✔
77
    l[k] = var2str(v)
97 ✔
78
  end
79
  return "{ " .. table.concat(l, ", ") .. " }"
83 ✔
80
end
81

82
function parlist2str (parlist)
×
83
  local l = {}
16 ✔
84
  local len = #parlist
16 ✔
85
  local is_vararg = false
16 ✔
86
  if len > 0 and parlist[len].tag == "Dots" then
16 ✔
87
    is_vararg = true
11 ✔
88
    len = len - 1
11 ✔
89
  end
90
  local i = 1
16 ✔
91
  while i <= len do
32 ✔
92
    l[i] = var2str(parlist[i])
16 ✔
93
    i = i + 1
16 ✔
94
  end
95
  if is_vararg then
16 ✔
96
    l[i] = "`" .. parlist[i].tag
11 ✔
97
  end
98
  return "{ " .. table.concat(l, ", ") .. " }"
16 ✔
99
end
100

101
function fieldlist2str (fieldlist)
×
102
  local l = {}
61 ✔
103
  for k, v in ipairs(fieldlist) do
129 ✔
104
    local tag = v.tag
68 ✔
105
    if tag == "Pair" then -- `Pair{ expr expr }
68 ✔
106
      l[k] = "`" .. tag .. "{ "
8 ✔
107
      l[k] = l[k] .. exp2str(v[1]) .. ", " .. exp2str(v[2])
8 ✔
108
      l[k] = l[k] .. " }"
8 ✔
109
    else -- expr
110
      l[k] = exp2str(v)
60 ✔
111
    end
112
  end
113
  if #l > 0 then
61 ✔
114
    return "{ " .. table.concat(l, ", ") .. " }"
57 ✔
115
  else
116
    return ""
4 ✔
117
  end
118
end
119

120
function exp2str (exp)
×
121
  local tag = exp.tag
352 ✔
122
  local str = "`" .. tag
352 ✔
123
  if tag == "Nil" or
352 ✔
124
     tag == "Dots" then
351 ✔
125
  elseif tag == "Boolean" then -- `Boolean{ <boolean> }
342 ✔
126
    str = str .. " " .. boolean2str(exp[1])
2 ✔
127
  elseif tag == "Number" then -- `Number{ <number> }
340 ✔
128
    str = str .. " " .. number2str(exp[1])
123 ✔
129
  elseif tag == "String" then -- `String{ <string> }
217 ✔
130
    str = str .. " " .. string2str(exp[1])
34 ✔
131
  elseif tag == "Function" then -- `Function{ { `Id{ <string> }* `Dots? } block }
183 ✔
132
    str = str .. "{ "
16 ✔
133
    str = str .. parlist2str(exp[1]) .. ", "
16 ✔
134
    str = str .. block2str(exp[2])
16 ✔
135
    str = str .. " }"
16 ✔
136
  elseif tag == "Table" then -- `Table{ ( `Pair{ expr expr } | expr )* }
167 ✔
137
    str = str .. fieldlist2str(exp)
61 ✔
138
  elseif tag == "Op" then -- `Op{ opid expr expr? }
106 ✔
139
    str = str .. "{ "
45 ✔
140
    str = str .. name2str(exp[1]) .. ", "
45 ✔
141
    str = str .. exp2str(exp[2])
45 ✔
142
    if exp[3] then
45 ✔
143
      str = str .. ", " .. exp2str(exp[3])
43 ✔
144
    end
145
    str = str .. " }"
45 ✔
146
  elseif tag == "Paren" then -- `Paren{ expr }
61 ✔
147
    str = str .. "{ " .. exp2str(exp[1]) .. " }"
1 ✔
148
  elseif tag == "Call" then -- `Call{ expr expr* }
60 ✔
149
    str = str .. "{ "
6 ✔
150
    str = str .. exp2str(exp[1])
6 ✔
151
    if exp[2] then
6 ✔
152
      for i=2, #exp do
6 ✔
153
        str = str .. ", " .. exp2str(exp[i])
3 ✔
154
      end
155
    end
156
    str = str .. " }"
6 ✔
157
  elseif tag == "Invoke" then -- `Invoke{ expr `String{ <string> } expr* }
54 ✔
158
    str = str .. "{ "
1 ✔
159
    str = str .. exp2str(exp[1]) .. ", "
1 ✔
160
    str = str .. exp2str(exp[2])
1 ✔
161
    if exp[3] then
1 ✔
162
      for i=3, #exp do
2 ✔
163
        str = str .. ", " .. exp2str(exp[i])
1 ✔
164
      end
165
    end
166
    str = str .. " }"
1 ✔
167
  elseif tag == "Id" or -- `Id{ <string> }
53 ✔
168
         tag == "Index" then -- `Index{ expr expr }
6 ✔
169
    str = var2str(exp)
53 ✔
170
  else
171
    error("expecting an expression, but got a " .. tag)
×
172
  end
173
  return str
352 ✔
174
end
175

176
function explist2str (explist)
×
177
  local l = {}
109 ✔
178
  for k, v in ipairs(explist) do
226 ✔
179
    l[k] = exp2str(v)
117 ✔
180
  end
181
  if #l > 0 then
109 ✔
182
    return "{ " .. table.concat(l, ", ") .. " }"
101 ✔
183
  else
184
    return ""
8 ✔
185
  end
186
end
187

188
function stm2str (stm)
×
189
  local tag = stm.tag
175 ✔
190
  local str = "`" .. tag
175 ✔
191
  if tag == "Do" then -- `Do{ stat* }
175 ✔
192
    local l = {}
12 ✔
193
    for k, v in ipairs(stm) do
29 ✔
194
      l[k] = stm2str(v)
17 ✔
195
    end
196
    str = str .. "{ " .. table.concat(l, ", ") .. " }"
12 ✔
197
  elseif tag == "Set" then -- `Set{ {lhs+} {expr+} }
163 ✔
198
    str = str .. "{ "
65 ✔
199
    str = str .. varlist2str(stm[1]) .. ", "
65 ✔
200
    str = str .. explist2str(stm[2])
65 ✔
201
    str = str .. " }"
65 ✔
202
  elseif tag == "While" then -- `While{ expr block }
98 ✔
203
    str = str .. "{ "
4 ✔
204
    str = str .. exp2str(stm[1]) .. ", "
4 ✔
205
    str = str .. block2str(stm[2])
4 ✔
206
    str = str .. " }"
4 ✔
207
  elseif tag == "Repeat" then -- `Repeat{ block expr }
94 ✔
208
    str = str .. "{ "
2 ✔
209
    str = str .. block2str(stm[1]) .. ", "
2 ✔
210
    str = str .. exp2str(stm[2])
2 ✔
211
    str = str .. " }"
2 ✔
212
  elseif tag == "If" then -- `If{ (expr block)+ block? }
92 ✔
213
    str = str .. "{ "
7 ✔
214
    local len = #stm
7 ✔
215
    if len % 2 == 0 then
7 ✔
216
      local l = {}
4 ✔
217
      for i=1,len-2,2 do
7 ✔
218
        str = str .. exp2str(stm[i]) .. ", " .. block2str(stm[i+1]) .. ", "
3 ✔
219
      end
220
      str = str .. exp2str(stm[len-1]) .. ", " .. block2str(stm[len])
4 ✔
221
    else
222
      local l = {}
3 ✔
223
      for i=1,len-3,2 do
4 ✔
224
        str = str .. exp2str(stm[i]) .. ", " .. block2str(stm[i+1]) .. ", "
1 ✔
225
      end
226
      str = str .. exp2str(stm[len-2]) .. ", " .. block2str(stm[len-1]) .. ", "
3 ✔
227
      str = str .. block2str(stm[len])
3 ✔
228
    end
229
    str = str .. " }"
7 ✔
230
  elseif tag == "Fornum" then -- `Fornum{ ident expr expr expr? block }
85 ✔
231
    str = str .. "{ "
3 ✔
232
    str = str .. var2str(stm[1]) .. ", "
3 ✔
233
    str = str .. exp2str(stm[2]) .. ", "
3 ✔
234
    str = str .. exp2str(stm[3]) .. ", "
3 ✔
235
    if stm[5] then
3 ✔
236
      str = str .. exp2str(stm[4]) .. ", "
1 ✔
237
      str = str .. block2str(stm[5])
1 ✔
238
    else
239
      str = str .. block2str(stm[4])
2 ✔
240
    end
241
    str = str .. " }"
3 ✔
242
  elseif tag == "Forin" then -- `Forin{ {ident+} {expr+} block }
82 ✔
243
    str = str .. "{ "
1 ✔
244
    str = str .. varlist2str(stm[1]) .. ", "
1 ✔
245
    str = str .. explist2str(stm[2]) .. ", "
1 ✔
246
    str = str .. block2str(stm[3])
1 ✔
247
    str = str .. " }"
1 ✔
248
  elseif tag == "Local" then -- `Local{ {ident+} {expr+}? }
81 ✔
249
    str = str .. "{ "
17 ✔
250
    str = str .. varlist2str(stm[1])
17 ✔
251
    if #stm[2] > 0 then
17 ✔
252
      str = str .. ", " .. explist2str(stm[2])
15 ✔
253
    else
254
      str = str .. ", " .. "{  }"
2 ✔
255
    end
256
    str = str .. " }"
17 ✔
257
  elseif tag == "Localrec" then -- `Localrec{ ident expr }
64 ✔
258
    str = str .. "{ "
4 ✔
259
    str = str .. "{ " .. var2str(stm[1][1]) .. " }, "
4 ✔
260
    str = str .. "{ " .. exp2str(stm[2][1]) .. " }"
4 ✔
261
    str = str .. " }"
4 ✔
262
  elseif tag == "Goto" or -- `Goto{ <string> }
60 ✔
263
         tag == "Label" then -- `Label{ <string> }
52 ✔
264
    str = str .. "{ " .. name2str(stm[1]) .. " }"
22 ✔
265
  elseif tag == "Return" then -- `Return{ <expr>* }
38 ✔
266
    str = str .. explist2str(stm)
28 ✔
267
  elseif tag == "Break" then
10 ✔
268
  elseif tag == "Call" then -- `Call{ expr expr* }
3 ✔
269
    str = str .. "{ "
3 ✔
270
    str = str .. exp2str(stm[1])
3 ✔
271
    if stm[2] then
3 ✔
272
      for i=2, #stm do
5 ✔
273
        str = str .. ", " .. exp2str(stm[i])
3 ✔
274
      end
275
    end
276
    str = str .. " }"
3 ✔
277
  elseif tag == "Invoke" then -- `Invoke{ expr `String{ <string> } expr* }
×
278
    str = str .. "{ "
×
279
    str = str .. exp2str(stm[1]) .. ", "
×
280
    str = str .. exp2str(stm[2])
×
281
    if stm[3] then
×
282
      for i=3, #stm do
×
283
        str = str .. ", " .. exp2str(stm[i])
×
284
      end
285
    end
286
    str = str .. " }"
×
287
  else
288
    error("expecting a statement, but got a " .. tag)
×
289
  end
290
  return str
175 ✔
291
end
292

293
function block2str (block)
×
294
  local l = {}
138 ✔
295
  for k, v in ipairs(block) do
296 ✔
296
    l[k] = stm2str(v)
158 ✔
297
  end
298
  return "{ " .. table.concat(l, ", ") .. " }"
138 ✔
299
end
300

301
function pp.tostring (t)
1 ✔
302
  assert(type(t) == "table")
98 ✔
303
  return block2str(t)
98 ✔
304
end
305

306
function pp.print (t)
1 ✔
307
  assert(type(t) == "table")
×
308
  print(pp.tostring(t))
×
309
end
310

311
function pp.dump (t, i)
1 ✔
312
  if i == nil then i = 0 end
×
313
  io.write(string.format("{\n"))
×
314
  io.write(string.format("%s[tag] = %s\n", string.rep(" ", i+2), t.tag or "nil"))
×
315
  io.write(string.format("%s[pos] = %s\n", string.rep(" ", i+2), t.pos or "nil"))
×
316
  for k,v in ipairs(t) do
×
317
    io.write(string.format("%s[%s] = ", string.rep(" ", i+2), tostring(k)))
×
318
    if type(v) == "table" then
×
319
      pp.dump(v,i+2)
×
320
    else
321
      io.write(string.format("%s\n", tostring(v)))
×
322
    end
323
  end
324
  io.write(string.format("%s}\n", string.rep(" ", i)))
×
325
end
326

327
return pp
1 ✔
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE TRIAL · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc