Differences From
Artifact [5feb0b86b1]:
83 83 return string.format("mode ā%sā "..msg, ...)
84 84 end);
85 85 unimpl = ss.exnkind 'feature not implemented';
86 86 ext = ss.exnkind 'extension error';
87 87 enc = ss.exnkind('encoding error', function(msg, ...)
88 88 return string.format('[%s]' .. msg, ...)
89 89 end);
90 + rdr = ss.exnkind('could not render', function(msg, ...)
91 + return string.format('(backend %s)'..msg, ...)
92 + end);
90 93 }
91 94
92 95 ct.ctx = declare {
93 96 mk = function(src) return {src = src} end;
94 97 ident = 'context';
95 98 cast = {
96 99 string = function(me)
................................................................................
141 144 depth = 0;
142 145 kind = 'ordinary';
143 146 } end;
144 147 construct = function(self, id, depth)
145 148 self.id = id
146 149 self.depth = depth
147 150 end;
151 + fns = {
152 + visible = function(self)
153 + if self.kind == 'nonprinting' then return false end
154 + local invisibles = {
155 + ['break'] = true;
156 + reference = true;
157 + resource = true;
158 + directive = true;
159 + }
160 + for k,b in pairs(self.blocks) do
161 + if not (invisibles[b.kind] or b.invisible) then return true end
162 + -- extensions that add invisible nodes to the AST must
163 + -- mark them as such for rendering to work properly!
164 + end
165 + return false
166 + end;
167 + }
148 168 }
149 169
150 170 ct.doc = declare {
151 171 ident = 'doc';
152 172 fns = {
153 173 mksec = function(self, id, depth)
154 174 local o = ct.sec(id, depth)
................................................................................
749 769 if ss.str.begins(substr, i.seq) then
750 770 found = true
751 771 table.insert(spans, i.parse(substr:sub(1+#i.seq), ctx))
752 772 break
753 773 end
754 774 end
755 775 if not found then
756 - ctx:fail('no recognized control sequence in [%s]', substr)
776 + buf = buf .. c
757 777 end
758 778 elseif c == '\n' then
759 779 flush()
760 780 table.insert(spans,{kind='line-break',origin=ctx:clone()})
761 781 else
762 782 buf = buf .. c
763 783 end
................................................................................
986 1006 if (not last) or (last.kind ~= 'reference') then
987 1007 c:fail('reference continuations must immediately follow a reference')
988 1008 end
989 1009 local str = l:match '^\t\t(.-)%s*$'
990 1010 last.val = last.val .. '\n' .. str
991 1011 c.sec.refs[last.key] = last.val
992 1012 end};
993 - {seq = '\t', fn = blockwrap(function(l,c,j,d)
1013 + {seq = '\t', pred = function(l)
1014 + return (l:match '\t+([^:]+):%s*(.*)$')
1015 + end; fn = blockwrap(function(l,c,j,d)
994 1016 local ref, val = l:match '\t+([^:]+):%s*(.*)$'
995 1017 local last = d[#d]
996 1018 local rsrc
997 1019 if last and last.kind == 'resource' then
998 1020 last.props[ref] = val
999 1021 rsrc = last
1000 1022 elseif last and last.kind == 'reference' and last.rsrc then
................................................................................
1185 1207 end
1186 1208 end
1187 1209 end
1188 1210 job:hook('line_end',ctx,l)
1189 1211 end
1190 1212
1191 1213 function ct.parse(file, src, mode, setup)
1192 -
1214 + -- this object is threaded down through the parse tree
1215 + -- and copied to store information like the origin of the
1216 + -- element in the source code
1193 1217 local ctx = ct.ctx.mk(src)
1194 1218 ctx.line = 0
1195 1219 ctx.doc = ct.doc.mk()
1196 1220 ctx.doc.src = src
1197 1221 ctx.sec = ctx.doc:mksec() -- toplevel section
1198 1222 ctx.sec.origin = ctx:clone()
1199 1223 ctx.lang = mode['meta:lang']
................................................................................
1267 1291 end
1268 1292 end
1269 1293 end
1270 1294 ctx.doc.stage = nil
1271 1295 ctx.doc.docjob:hook('meddle_ast')
1272 1296 return ctx.doc
1273 1297 end
1298 +
1299 +function ct.expand_var(v)
1300 + local val
1301 + if v.pos then
1302 + if not v.origin.invocation then
1303 + v.origin:fail 'positional arguments can only be used in a macro invocation'
1304 + elseif not v.origin.invocation.args[v.pos] then
1305 + v.origin.invocation.origin:fail('macro invocation %s missing positional argument #%u', v.origin.invocation.macro, v.pos)
1306 + end
1307 + val = v.origin.invocation.args[v.pos]
1308 + else
1309 + val = v.origin.doc:context_var(v.var, v.origin)
1310 + end
1311 + if v.raw then
1312 + return val, true
1313 + else
1314 + return ct.parse_span(val, v.origin), false
1315 + end
1316 +end