This is an Engineering Notebook post. Feel free to ignore. However, it
contains a new coding pattern, for you code affectionados.
*tl;dr:* Setting a skip count encourages multi-line pattern matching. This
can drastically simplify some importers.
*A new scanning pattern*
The new rst importer overrides i.v2_gen_lines. Here is the interesting
part:
skip = 0
lines = g.splitLines(s)
for i, line in enumerate(lines):
if trace: g.trace('%2s %r' % (i+1, line))
if skip > 0:
skip -= 1
elif self.is_lookahead_overline(i, lines):
level = self.ch_level(line[0])
self.make_node(level, lines[i+1])
skip = 2
elif self.is_lookahead_underline(i, lines):
level = self.ch_level(lines[i+1][0])
self.make_node(level, line)
skip = 1
elif i == 0:
p = self.make_dummy_node('!Dummy chapter')
self.add_line(p, line)
else:
p = self.stack[-1]
self.add_line(p, line)
There are several things about this code worth special mention:
1. Unlike most importers, this truly is line-oriented code. The enumerate
loop handles each line without *any* character scanning. Actually, that's
not quite true. Lines are scanned to determine whether they are
under/overlines, but that's a nit...
2. The truly clever thing about this code is that it uses a skip count.
This allows the code to look ahead *naturally*. The lookahead methods scan,
as their names imply, lines *after* the line returned by enumerate.
The lookahead methods are very simple pattern matchers. When they match,
it is easy for the main line code to deal with the match, using 1 or two
*following* lines. The skip logic then ensures that the main line never
looks at the lines a second time.
Folks, this is important. Without it, matching patterns becomes a complex
mess. The markdown importer is an example.
3. The skip pattern allows us to use enumerate more often. Previously, I
have used this kind of code when the 'i' variable can change:
i = 0
lines = g.splitLines(s)
while i < len(lines):
progress = i
line = lines[i]
<< code that may change i >>
assert progress < i, (i, line)
It's not terrible, but this is *so* much better:
skip = 0
lines = g.splitLines(s)
for i, line in enumerate(lines):
if skip:
skip -= 1
elif lookahead_n_lines(lines):
# Handle n lines.
skip = n
elif lookahead_m_lines(lines):
# Handle m lines.
skip = m
else:
...
*Summary*
The new coding pattern encourages multi-line pattern matching. This can
*drastically* simplify code.
The new coding pattern makes it possible to use enumerate in more
situations. Not huge, but not nothing.
Edward
--
You received this message because you are subscribed to the Google Groups
"leo-editor" group.
To unsubscribe from this group and stop receiving emails from it, send an email
to [email protected].
To post to this group, send email to [email protected].
Visit this group at https://groups.google.com/group/leo-editor.
For more options, visit https://groups.google.com/d/optout.