annotate fontaine/parser.py @ 2:59fe8cb6190d

Add lots of tests, fix lots of bugs.
author Ludovic Chabant <ludovic@chabant.com>
date Tue, 03 Jan 2017 09:05:28 -0800
parents 74b83e3d921e
children
Ignore whitespace changes - Everywhere: Within whitespace: At end of lines:
rev   line source
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
1 import re
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
2 import logging
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
3 from .document import TYPE_ACTION
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
4
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
5
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
6 logger = logging.getLogger(__name__)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
7
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
8
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
9 class FontaineState:
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
10 def __init__(self):
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
11 pass
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
12
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
13 def match(self, fp, ctx):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
14 return False
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
15
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
16 def consume(self, fp, ctx):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
17 raise NotImplementedError()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
18
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
19 def exit(self, ctx, next_state):
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
20 pass
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
21
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
22
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
23 class _PassThroughState(FontaineState):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
24 def consume(self, fp, ctx):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
25 return ANY_STATE
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
26
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
27
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
28 class FontaineParserError(Exception):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
29 def __init__(self, line_no, message):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
30 super().__init__("Error line %d: %s" % (line_no, message))
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
31
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
32
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
33 ANY_STATE = object()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
34 EOF_STATE = object()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
35
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
36
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
37 RE_EMPTY_LINE = re.compile(r"^$", re.M)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
38 RE_BLANK_LINE = re.compile(r"^\s*$", re.M)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
39
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
40 RE_TITLE_KEY_VALUE = re.compile(r"^(?P<key>[\w\s\-]+)\s*:\s*")
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
41
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
42
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
43 class _TitlePageState(FontaineState):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
44 def __init__(self):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
45 super().__init__()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
46 self._cur_key = None
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
47 self._cur_val = None
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
48
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
49 def match(self, fp, ctx):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
50 line = fp.peekline()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
51 return RE_TITLE_KEY_VALUE.match(line)
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
52
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
53 def consume(self, fp, ctx):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
54 while True:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
55 line = fp.readline()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
56 if not line:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
57 return EOF_STATE
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
58
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
59 m = RE_TITLE_KEY_VALUE.match(line)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
60 if m:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
61 # Commit current value, start new one.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
62 self._commit(ctx)
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
63 self._cur_key = m.group('key').lower()
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
64 self._cur_val = line[m.end():]
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
65 else:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
66 # Keep accumulating the value of one of the title page's
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
67 # values.
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
68 self._cur_val += line.lstrip()
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
69
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
70 if RE_EMPTY_LINE.match(fp.peekline()):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
71 self._commit(ctx)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
72 # Finished with the page title, now move on to the first scene.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
73 break
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
74
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
75 return ANY_STATE
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
76
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
77 def exit(self, ctx, next_state):
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
78 self._commit(ctx)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
79
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
80 def _commit(self, ctx):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
81 if self._cur_key is not None:
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
82 val = self._cur_val.rstrip('\r\n')
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
83 ctx.document.title_values[self._cur_key] = val
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
84 self._cur_key = None
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
85 self._cur_val = None
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
86
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
87
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
88 RE_SCENE_HEADER_PATTERN = re.compile(
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
89 r"^(int|ext|est|int/ext|int./ext|i/e)[\s\.]", re.I)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
90
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
91
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
92 class _SceneHeaderState(FontaineState):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
93 def match(self, fp, ctx):
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
94 lines = fp.peeklines(3)
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
95 return (
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
96 RE_EMPTY_LINE.match(lines[0]) and
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
97 RE_SCENE_HEADER_PATTERN.match(lines[1]) and
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
98 RE_EMPTY_LINE.match(lines[2]))
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
99
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
100 def consume(self, fp, ctx):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
101 fp.readline() # Get past the blank line.
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
102 line = fp.readline().rstrip('\r\n')
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
103 line = line.lstrip('.') # In case it was forced.
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
104 ctx.document.addScene(line)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
105 return ANY_STATE
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
106
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
107
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
108 class _ActionState(FontaineState):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
109 def __init__(self):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
110 super().__init__()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
111 self.text = ''
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
112
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
113 def match(self, fp, ctx):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
114 return True
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
115
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
116 def consume(self, fp, ctx):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
117 is_first_line = True
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
118 while True:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
119 line = fp.readline()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
120 if not line:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
121 return EOF_STATE
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
122
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
123 if is_first_line:
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
124 # Ignore the fake blank line at 0 if it's threre.
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
125 if fp.line_no == 0:
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
126 continue
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
127
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
128 line = line.lstrip('!') # In case it was forced.
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
129 is_first_line = False
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
130
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
131 # If the next line is empty, strip the carriage return from
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
132 # the line we just got because it's probably gonna be the
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
133 # last one.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
134 if RE_EMPTY_LINE.match(fp.peekline()):
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
135 self.text += line.rstrip("\r\n")
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
136 break
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
137 # ...otherwise, add the line with in full.
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
138 self.text += line
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
139
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
140 return ANY_STATE
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
141
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
142 def exit(self, ctx, next_state):
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
143 last_para = ctx.document.lastParagraph()
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
144 if last_para and last_para.type == TYPE_ACTION:
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
145 last_para.text += '\n' + self.text
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
146 else:
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
147 ctx.document.lastScene().addAction(self.text)
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
148
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
149
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
150 RE_CENTERED_LINE = re.compile(r"^\s*>\s*.*\s*<\s*$", re.M)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
151
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
152
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
153 class _CenteredActionState(FontaineState):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
154 def __init__(self):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
155 super().__init__()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
156 self.text = ''
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
157 self._aborted = False
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
158
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
159 def match(self, fp, ctx):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
160 lines = fp.peeklines(2)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
161 return (
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
162 RE_EMPTY_LINE.match(lines[0]) and
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
163 RE_CENTERED_LINE.match(lines[1]))
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
164
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
165 def consume(self, fp, ctx):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
166 snapshot = fp.snapshot()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
167 fp.readline() # Get past the empty line.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
168 while True:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
169 line = fp.readline()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
170 if not line:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
171 return EOF_STATE
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
172
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
173 clean_line = line.rstrip('\r\n')
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
174 eol = line[len(clean_line):]
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
175
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
176 clean_line = clean_line.strip()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
177 if clean_line[0] != '>' or clean_line[-1] != '<':
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
178 # The whole paragraph must have `>` and `<` wrappers, so
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
179 # if we detect a line that doesn't have them, we make this
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
180 # paragraph be a normal action instead.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
181 fp.restore(snapshot)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
182 self._aborted = True
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
183 return _ActionState()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
184 else:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
185 # Remove wrapping `>`/`<`, and spaces.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
186 clean_line = clean_line[1:-1].strip()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
187
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
188 if RE_EMPTY_LINE.match(fp.peekline()):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
189 self.text += clean_line
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
190 break
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
191 self.text += clean_line + eol
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
192
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
193 return ANY_STATE
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
194
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
195 def exit(self, ctx, next_state):
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
196 if not self._aborted:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
197 ctx.document.lastScene().addCenteredAction(self.text)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
198
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
199
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
200 RE_CHARACTER_LINE = re.compile(r"^\s*[A-Z][A-Z\-\._\s]+\s*(\(.*\))?$", re.M)
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
201
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
202
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
203 class _CharacterState(FontaineState):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
204 def match(self, fp, ctx):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
205 lines = fp.peeklines(3)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
206 return (RE_EMPTY_LINE.match(lines[0]) and
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
207 RE_CHARACTER_LINE.match(lines[1]) and
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
208 not RE_EMPTY_LINE.match(lines[2]))
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
209
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
210 def consume(self, fp, ctx):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
211 fp.readline() # Get past the empty line.
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
212 line = fp.readline().rstrip('\r\n')
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
213 line = line.lstrip() # Remove indenting.
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
214 line = line.lstrip('@') # In case it was forced.
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
215 ctx.document.lastScene().addCharacter(line)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
216 return [_ParentheticalState, _DialogState]
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
217
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
218
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
219 RE_PARENTHETICAL_LINE = re.compile(r"^\s*\(.*\)\s*$", re.M)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
220
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
221
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
222 class _ParentheticalState(FontaineState):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
223 def match(self, fp, ctx):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
224 # We only get here from a `_CharacterState` so we know the previous
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
225 # one is already that.
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
226 line = fp.peekline()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
227 return RE_PARENTHETICAL_LINE.match(line)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
228
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
229 def consume(self, fp, ctx):
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
230 line = fp.readline().lstrip().rstrip('\r\n')
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
231 ctx.document.lastScene().addParenthetical(line)
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
232
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
233 next_line = fp.peekline()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
234 if not RE_EMPTY_LINE.match(next_line):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
235 return _DialogState()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
236
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
237 return ANY_STATE
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
238
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
239
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
240 class _DialogState(FontaineState):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
241 def __init__(self):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
242 super().__init__()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
243 self.text = ''
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
244
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
245 def match(self, fp, ctx):
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
246 # We only get here from a `_CharacterState` or `_ParentheticalState`
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
247 # so we just need to check there's some text.
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
248 line = fp.peekline()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
249 return not RE_EMPTY_LINE.match(line)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
250
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
251 def consume(self, fp, ctx):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
252 while True:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
253 line = fp.readline()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
254 if not line:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
255 return EOF_STATE
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
256
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
257 line = line.lstrip() # Remove indenting.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
258
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
259 # Next we could be either continuing the dialog line, going to
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
260 # a parenthetical, or exiting dialog altogether.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
261 next_line = fp.peekline()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
262
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
263 if RE_PARENTHETICAL_LINE.match(next_line):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
264 self.text += line.rstrip('\r\n')
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
265 return _ParentheticalState()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
266
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
267 if RE_EMPTY_LINE.match(next_line):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
268 self.text += line.rstrip('\r\n')
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
269 break
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
270 self.text += line
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
271
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
272 return ANY_STATE
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
273
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
274 def exit(self, ctx, next_state):
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
275 ctx.document.lastScene().addDialog(self.text.rstrip('\r\n'))
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
276
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
277
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
278 class _LyricsState(FontaineState):
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
279 def __init__(self):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
280 super().__init__()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
281 self.text = ''
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
282 self._aborted = False
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
283
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
284 # No `match` method, this can only be forced.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
285 # (see `_ForcedParagraphStates`)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
286
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
287 def consume(self, fp, ctx):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
288 snapshot = fp.snapshot()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
289 fp.readline() # Get past the empty line.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
290 while True:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
291 line = fp.readline()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
292 if not line:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
293 return EOF_STATE
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
294
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
295 if line.startswith('~'):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
296 line = line.lstrip('~')
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
297 else:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
298 logger.debug("Rolling back lyrics into action paragraph.")
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
299 fp.restore(snapshot)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
300 self._aborted = True
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
301 return _ActionState()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
302
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
303 if RE_EMPTY_LINE.match(fp.peekline()):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
304 self.text += line.rstrip('\r\n')
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
305 break
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
306 self.text += line
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
307
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
308 return ANY_STATE
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
309
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
310 def exit(self, ctx, next_state):
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
311 if not self._aborted:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
312 ctx.document.lastScene().addLyrics(self.text)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
313
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
314
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
315 RE_TRANSITION_LINE = re.compile(r"^\s*[^a-z]+TO\:$", re.M)
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
316
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
317
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
318 class _TransitionState(FontaineState):
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
319 def match(self, fp, ctx):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
320 lines = fp.peeklines(3)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
321 return (
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
322 RE_EMPTY_LINE.match(lines[0]) and
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
323 RE_TRANSITION_LINE.match(lines[1]) and
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
324 RE_EMPTY_LINE.match(lines[2]))
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
325
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
326 def consume(self, fp, ctx):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
327 fp.readline() # Get past the empty line.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
328 line = fp.readline().lstrip().rstrip('\r\n')
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
329 line = line.lstrip('>') # In case it was forced.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
330 ctx.document.lastScene().addTransition(line)
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
331 return ANY_STATE
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
332
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
333
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
334 RE_PAGE_BREAK_LINE = re.compile(r"^\=\=\=+$", re.M)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
335
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
336
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
337 class _PageBreakState(FontaineState):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
338 def match(self, fp, ctx):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
339 lines = fp.peeklines(3)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
340 return (
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
341 RE_EMPTY_LINE.match(lines[0]) and
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
342 RE_PAGE_BREAK_LINE.match(lines[1]) and
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
343 RE_EMPTY_LINE.match(lines[2]))
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
344
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
345 def consume(self, fp, ctx):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
346 fp.readline()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
347 fp.readline()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
348 ctx.document.lastScene().addPageBreak()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
349 return ANY_STATE
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
350
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
351
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
352 class _ForcedParagraphStates(FontaineState):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
353 STATE_SYMBOLS = {
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
354 '.': _SceneHeaderState,
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
355 '!': _ActionState,
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
356 '@': _CharacterState,
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
357 '~': _LyricsState,
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
358 '>': _TransitionState
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
359 }
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
360
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
361 def __init__(self):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
362 super().__init__()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
363 self._state_cls = None
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
364 self._consume_empty_line = False
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
365
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
366 def match(self, fp, ctx):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
367 lines = fp.peeklines(2)
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
368 symbol = lines[1][:1]
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
369 if (RE_EMPTY_LINE.match(lines[0]) and
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
370 symbol in self.STATE_SYMBOLS):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
371 # Special case: don't force a transition state if it's
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
372 # really some centered text.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
373 if symbol == '>' and RE_CENTERED_LINE.match(lines[1]):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
374 return False
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
375
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
376 self._state_cls = self.STATE_SYMBOLS[symbol]
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
377
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
378 # Special case: for forced action paragraphs, don't leave
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
379 # the blank line there.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
380 if symbol == '!':
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
381 self._consume_empty_line = True
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
382
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
383 return True
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
384 return False
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
385
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
386 def consume(self, fp, ctx):
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
387 if self._consume_empty_line:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
388 fp.readline()
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
389 return self._state_cls()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
390
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
391
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
392 class _EmptyLineState(FontaineState):
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
393 def __init__(self):
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
394 super().__init__()
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
395 self.line_count = 0
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
396
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
397 def match(self, fp, ctx):
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
398 return RE_EMPTY_LINE.match(fp.peekline())
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
399
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
400 def consume(self, fp, ctx):
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
401 fp.readline()
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
402 if fp.line_no > 1: # Don't take into account the fake blank at 0
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
403 self.line_count += 1
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
404 return ANY_STATE
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
405
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
406 def exit(self, ctx, next_state):
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
407 if self.line_count > 0:
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
408 text = self.line_count * '\n'
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
409 last_para = ctx.document.lastParagraph()
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
410 if last_para and last_para.type == TYPE_ACTION:
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
411 last_para.text += text
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
412 else:
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
413 ctx.document.lastScene().addAction(text[1:])
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
414
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
415
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
416 ROOT_STATES = [
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
417 _ForcedParagraphStates, # Must be first.
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
418 _SceneHeaderState,
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
419 _CharacterState,
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
420 _TransitionState,
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
421 _PageBreakState,
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
422 _CenteredActionState,
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
423 _EmptyLineState, # Must be second to last.
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
424 _ActionState, # Must be last.
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
425 ]
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
426
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
427
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
428 class _PeekableFile:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
429 def __init__(self, fp):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
430 self.line_no = 1
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
431 self._fp = fp
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
432 self._blankAt0 = False
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
433
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
434 def readline(self):
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
435 if self._blankAt0:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
436 self._blankAt0 = False
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
437 self.line_no = 0
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
438 return '\n'
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
439
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
440 data = self._fp.readline()
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
441 self.line_no += 1
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
442 return data
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
443
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
444 def peekline(self):
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
445 if self._blankAt0:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
446 return '\n'
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
447
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
448 pos = self._fp.tell()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
449 line = self._fp.readline()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
450 self._fp.seek(pos)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
451 return line
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
452
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
453 def peeklines(self, count):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
454 pos = self._fp.tell()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
455 lines = []
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
456 if self._blankAt0:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
457 lines.append('\n')
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
458 count -= 1
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
459 for i in range(count):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
460 lines.append(self._fp.readline())
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
461 self._fp.seek(pos)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
462 return lines
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
463
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
464 def snapshot(self):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
465 return (self._fp.tell(), self._blankAt0, self.line_no)
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
466
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
467 def restore(self, snapshot):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
468 self._fp.seek(snapshot[0])
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
469 self._blankAt0 = snapshot[1]
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
470 self.line_no = snapshot[2]
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
471
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
472 def _addBlankAt0(self):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
473 if self._fp.tell() != 0:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
474 raise Exception(
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
475 "Can't add blank line at 0 if reading has started.")
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
476 self._blankAt0 = True
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
477 self.line_no = 0
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
478
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
479
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
480 class _FontaineStateMachine:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
481 def __init__(self, fp, doc):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
482 self.fp = _PeekableFile(fp)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
483 self.state = None
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
484 self.document = doc
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
485
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
486 @property
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
487 def line_no(self):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
488 return self.fp.line_no
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
489
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
490 def run(self):
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
491 # Start with the page title... unless it doesn't match, in which
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
492 # case we start with a "pass through" state that will just return
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
493 # `ANY_STATE` so we can start matching stuff.
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
494 self.state = _TitlePageState()
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
495 if not self.state.match(self.fp, self):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
496 logger.debug("No title page value found on line 1, "
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
497 "using pass-through state with added blank line.")
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
498 self.state = _PassThroughState()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
499 if not RE_EMPTY_LINE.match(self.fp.peekline()):
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
500 # Add a fake empty line at the beginning of the text if
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
501 # there's not one already. This makes state matching easier.
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
502 self.fp._addBlankAt0()
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
503
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
504 # Start parsing! Here we try to do a mostly-forward-only parser with
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
505 # non overlapping regexes to make it decently fast.
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
506 while True:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
507 logger.debug("State '%s' consuming from '%s'..." %
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
508 (self.state.__class__.__name__, self.fp.peekline()))
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
509 res = self.state.consume(self.fp, self)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
510
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
511 # See if we reached the end of the file.
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
512 if not self.fp.peekline():
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
513 logger.debug("Reached end of line... ending parsing.")
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
514 res = EOF_STATE
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
515
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
516 # Figure out what to do next...
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
517
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
518 if res is None:
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
519 raise FontaineParserError(
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
520 self.line_no,
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
521 "State '%s' returned a `None` result. "
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
522 "States need to return `ANY_STATE`, one or more specific "
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
523 "states, or `EOF_STATE` if they reached the end of the "
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
524 "file." % self.state.__class__.__name__)
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
525
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
526 elif res is ANY_STATE or isinstance(res, list):
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
527 # State wants to exit, we need to figure out what is the
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
528 # next state.
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
529 pos = self.fp._fp.tell()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
530 next_states = res
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
531 if next_states is ANY_STATE:
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
532 next_states = ROOT_STATES
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
533 logger.debug("Trying to match next state from: %s" %
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
534 [t.__name__ for t in next_states])
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
535 for sc in next_states:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
536 s = sc()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
537 if s.match(self.fp, self):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
538 logger.debug("Matched state %s" %
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
539 s.__class__.__name__)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
540 self.fp._fp.seek(pos)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
541 res = s
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
542 break
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
543 else:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
544 raise Exception("Can't match following state after: %s" %
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
545 self.state)
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
546
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
547 # Handle the current state before we move on to the new one.
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
548 if self.state:
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
549 self.state.exit(self, res)
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
550 self.state = res
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
551
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
552 elif isinstance(res, FontaineState):
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
553 # State wants to exit, wants a specific state to be next.
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
554 if self.state:
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
555 self.state.exit(self, res)
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
556 self.state = res
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
557
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
558 elif res is EOF_STATE:
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
559 # Reached end of file.
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
560 if self.state:
2
59fe8cb6190d Add lots of tests, fix lots of bugs.
Ludovic Chabant <ludovic@chabant.com>
parents: 1
diff changeset
561 self.state.exit(self, res)
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
562 break
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
563
1
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
564 else:
74b83e3d921e Add more states, add more tests.
Ludovic Chabant <ludovic@chabant.com>
parents: 0
diff changeset
565 raise Exception("Unsupported state result: %s" % res)
0
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
566
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
567
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
568 class FontaineParser:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
569 def __init__(self):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
570 pass
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
571
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
572 def parse(self, filein):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
573 if isinstance(filein, str):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
574 with open(filein, 'r') as fp:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
575 return self._doParse(fp)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
576 else:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
577 return self._doParse(fp)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
578
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
579 def parseString(self, text):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
580 import io
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
581 with io.StringIO(text) as fp:
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
582 return self._doParse(fp)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
583
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
584 def _doParse(self, fp):
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
585 from .document import FontaineDocument
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
586 doc = FontaineDocument()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
587 machine = _FontaineStateMachine(fp, doc)
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
588 machine.run()
243401c49520 Initial commit.
Ludovic Chabant <ludovic@chabant.com>
parents:
diff changeset
589 return doc