annotate fontaine/parser.py @ 1:74b83e3d921e

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