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

sile-typesetter / sile / 11534409649

26 Oct 2024 07:27PM UTC coverage: 33.196% (-28.7%) from 61.897%
11534409649

push

github

alerque
chore(tooling): Update editor-config key for stylua as accepted upstream

Our setting addition is still not in a tagged release, but the PR was
accepted into the default branch of stylua. This means you no longer
need to run my fork of Stylua to get this project's style, you just nead
any build from the main development branch. However the config key was
renamed as part of the acceptance, so this is the relevant adjustment.

5810 of 17502 relevant lines covered (33.2%)

1300.57 hits per line

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

25.41
/core/utilities/ast.lua
1
--- AST utilities.
2
-- Functions for working with SILE's Abstract Syntax Trees.
3
-- @module SU.ast
4

5
-- @type SU.ast
6
local ast = {}
18✔
7

8
--- Output developer friendly debugging view of an AST.
9
-- @tparam table tree Abstract Syntax Tree.
10
-- @tparam integer level Starting level to review.
11
function ast.debug (tree, level)
18✔
12
   if not tree then
×
13
      SU.error("debugAST called with nil", true)
×
14
   end
15
   local out = string.rep("  ", 1 + level)
×
16
   if level == 0 then
×
17
      SU.debug("ast", function ()
×
18
         return "[" .. (SILE.currentlyProcessingFile or "<nowhere>")
×
19
      end)
20
   end
21
   if type(tree) == "function" then
×
22
      SU.debug("ast", function ()
×
23
         return out .. tostring(tree)
×
24
      end)
25
   elseif type(tree) == "table" then
×
26
      for _, content in ipairs(tree) do
×
27
         if type(content) == "string" then
×
28
            SU.debug("ast", function ()
×
29
               return out .. "[" .. content .. "]"
×
30
            end)
31
         elseif type(content) == "table" then
×
32
            if SILE.Commands[content.command] then
×
33
               SU.debug("ast", function ()
×
34
                  return out .. "\\" .. content.command .. " " .. pl.pretty.write(content.options, "")
×
35
               end)
36
               if #content >= 1 then
×
37
                  ast.debug(content, level + 1)
×
38
               end
39
            elseif not content.command and not content.id then
×
40
               ast.debug(content, level + 1)
×
41
            else
42
               SU.debug("ast", function ()
×
43
                  return out .. "?\\" .. (content.command or content.id)
×
44
               end)
45
            end
46
         end
47
      end
48
   end
49
   if level == 0 then
×
50
      SU.debug("ast", "]")
×
51
   end
52
end
53

54
--- Find a command node in a SILE AST tree,
55
-- looking only at the first level.
56
-- (We're not reimplementing XPath here.)
57
-- @tparam table tree AST tree
58
-- @tparam string command command name
59
-- @treturn table|nil AST command node
60
function ast.findInTree (tree, command)
18✔
61
   for i = 1, #tree do
×
62
      if type(tree[i]) == "table" and tree[i].command == command then
×
63
         return tree[i]
×
64
      end
65
   end
66
end
67

68
--- Find and extract (remove) a command node in a SILE AST tree,
69
-- looking only at the first level.
70
-- @tparam table tree AST tree
71
-- @tparam string command command name
72
-- @treturn table|nil AST command node
73
function ast.removeFromTree (tree, command)
18✔
74
   for i = 1, #tree do
×
75
      if type(tree[i]) == "table" and tree[i].command == command then
×
76
         return table.remove(tree, i)
×
77
      end
78
   end
79
end
80

81
--- Create a command from a simple content tree.
82
-- It encapsulates the content in a command node.
83
-- @tparam string command command name
84
-- @tparam table options command options
85
-- @tparam table content child AST tree
86
-- @tparam table position position in source (or parent AST command node)
87
-- @treturn table       AST command node
88
function ast.createCommand (command, options, content, position)
18✔
89
   local result = { content }
1✔
90
   result.options = options or {}
1✔
91
   result.command = command
1✔
92
   result.id = "command"
1✔
93
   if position then
1✔
94
      result.col = position.col or 0
1✔
95
      result.lno = position.lno or 0
1✔
96
      result.pos = position.pos or 0
1✔
97
   else
98
      result.col = 0
×
99
      result.lno = 0
×
100
      result.pos = 0
×
101
   end
102
   return result
1✔
103
end
104

105
--- Create a command from a structured content tree.
106
-- The content is normally a table of an already prepared content list.
107
-- @tparam string command command name
108
-- @tparam table options command options
109
-- @tparam table content child AST tree
110
-- @tparam table position position in source (or parent AST command node)
111
-- @treturn table AST command node
112
function ast.createStructuredCommand (command, options, content, position)
18✔
113
   local result = type(content) == "table" and content or { content }
×
114
   result.options = options or {}
×
115
   result.command = command
×
116
   result.id = "command"
×
117
   if position then
×
118
      result.col = position.col or 0
×
119
      result.lno = position.lno or 0
×
120
      result.pos = position.pos or 0
×
121
   else
122
      result.col = 0
×
123
      result.lno = 0
×
124
      result.pos = 0
×
125
   end
126
   return result
×
127
end
128

129
--- Extract the sub-content tree from a (command) node,
130
-- that is the child nodes of the (command) node.
131
-- @tparam table content AST tree
132
-- @treturn table AST tree
133
function ast.subContent (content)
18✔
134
   local out = {}
×
135
   for _, val in ipairs(content) do
×
136
      out[#out + 1] = val
×
137
   end
138
   return out
×
139
end
140

141
-- String trimming
142
local function trimLeft (str)
143
   return str:gsub("^%s*", "")
×
144
end
145
local function trimRight (str)
146
   return str:gsub("%s*$", "")
×
147
end
148

149
--- Content tree trimming: remove leading and trailing spaces, but from
150
--- a content tree i.e. possibly containing several elements.
151
-- @tparam table content AST tree
152
-- @treturn table AST tree
153
function ast.trimSubContent (content)
18✔
154
   if #content == 0 then
×
155
      return
×
156
   end
157
   if type(content[1]) == "string" then
×
158
      content[1] = trimLeft(content[1])
×
159
      if content[1] == "" then
×
160
         table.remove(content, 1)
×
161
      end
162
   end
163
   if type(content[#content]) == "string" then
×
164
      content[#content] = trimRight(content[#content])
×
165
      if content[#content] == "" then
×
166
         table.remove(content, #content)
×
167
      end
168
   end
169
   return content
×
170
end
171

172
--- Process the AST walking through content nodes as a "structure":
173
-- Text nodes are ignored (e.g. usually just spaces due to indentation)
174
-- Command options are enriched with their "true" node position, so we can later
175
-- refer to it (as with an XPath pos()).
176
-- @tparam table content AST tree
177
function ast.processAsStructure (content)
18✔
178
   local iElem = 0
×
179
   local nElem = 0
×
180
   for i = 1, #content do
×
181
      if type(content[i]) == "table" then
×
182
         nElem = nElem + 1
×
183
      end
184
   end
185
   for i = 1, #content do
×
186
      if type(content[i]) == "table" then
×
187
         iElem = iElem + 1
×
188
         content[i].options._pos_ = iElem
×
189
         content[i].options._last_ = iElem == nElem
×
190
         SILE.process({ content[i] })
×
191
      end
192
      -- All text nodes in ignored in structure tags.
193
   end
194
end
195

196
--- Call `action` on each content AST node, recursively, including `content` itself.
197
-- Not called on leaves, i.e. strings.
198
-- @tparam table content AST tree
199
-- @tparam function action A function to call on each node
200
function ast.walkContent (content, action)
18✔
201
   if type(content) ~= "table" then
×
202
      return
×
203
   end
204
   action(content)
×
205
   for i = 1, #content do
×
206
      ast.walkContent(content[i], action)
×
207
   end
208
end
209

210
--- Strip position, line and column recursively from a content tree.
211
-- This can be used to remove position details where we do not want them,
212
-- e.g. in table of contents entries (referring to the original content,
213
-- regardless where it was exactly, for the purpose of checking whether
214
-- the table of contents changed.)
215
-- @param table content AST tree
216
-- @treturn table AST tree
217
function ast.stripContentPos (content)
18✔
218
   if type(content) ~= "table" then
×
219
      return content
×
220
   end
221
   local stripped = {}
×
222
   for k, v in pairs(content) do
×
223
      if type(v) == "table" then
×
224
         v = ast.stripContentPos(v)
×
225
      end
226
      stripped[k] = v
×
227
   end
228
   if content.id or content.command then
×
229
      stripped.pos, stripped.col, stripped.lno = nil, nil, nil
×
230
   end
231
   return stripped
×
232
end
233

234
--- Flatten content trees into just the string components (allows passing
235
-- objects with complex structures to functions that need plain strings)
236
-- @tparam table content AST tree
237
-- @treturn string A string representation of content
238
function ast.contentToString (content)
18✔
239
   local string = ""
5✔
240
   for i = 1, #content do
10✔
241
      if type(content[i]) == "table" and type(content[i][1]) == "string" then
5✔
242
         string = string .. content[i][1]
×
243
      elseif type(content[i]) == "string" then
5✔
244
         -- Work around PEG parser returning env tags as content
245
         -- TODO: refactor capture groups in PEG parser
246
         if content.command == content[i] and content[i] == content[i + 1] then
5✔
247
            break
248
         end
249
         string = string .. content[i]
5✔
250
      end
251
   end
252
   return string
5✔
253
end
254

255
--- Check whether a content AST tree is empty.
256
-- @tparam table content AST tree
257
-- @treturn boolean true if content is not empty
258
function ast.hasContent (content)
18✔
259
   return type(content) == "function" or type(content) == "table" and #content > 0
27✔
260
end
261

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

© 2026 Coveralls, Inc