Skip to content

Commit cf564c3

Browse files
authored
Require = after the identifier (#36)
1 parent 6a04f74 commit cf564c3

22 files changed

+578
-115
lines changed

fluent/syntax/ast.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@ def to_json(value):
88
return value.to_json()
99
if isinstance(value, list):
1010
return list(map(to_json, value))
11+
if isinstance(value, tuple):
12+
return list(map(to_json, value))
1113
else:
1214
return value
1315

fluent/syntax/ftlstream.py

Lines changed: 25 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -4,11 +4,18 @@
44

55

66
INLINE_WS = (' ', '\t')
7+
SPECIAL_LINE_START_CHARS = ('}', '.', '[', '*')
78

89

910
class FTLParserStream(ParserStream):
1011
last_comment_zero_four_syntax = False
1112

13+
def skip_inline_ws(self):
14+
while self.ch:
15+
if self.ch not in INLINE_WS:
16+
break
17+
self.next()
18+
1219
def peek_inline_ws(self):
1320
ch = self.current_peek()
1421
while ch:
@@ -39,11 +46,9 @@ def peek_blank_lines(self):
3946
self.reset_peek(line_start)
4047
break
4148

42-
def skip_inline_ws(self):
43-
while self.ch:
44-
if self.ch not in INLINE_WS:
45-
break
46-
self.next()
49+
def skip_indent(self):
50+
self.skip_blank_lines()
51+
self.skip_inline_ws()
4752

4853
def expect_char(self, ch):
4954
if self.ch == ch:
@@ -101,6 +106,19 @@ def is_number_start(self):
101106
self.reset_peek()
102107
return is_digit
103108

109+
def is_char_pattern_start(self, ch):
110+
return ch not in SPECIAL_LINE_START_CHARS
111+
112+
def is_peek_pattern_start(self):
113+
self.peek_inline_ws()
114+
115+
if self.current_peek_is('\n'):
116+
return self.is_peek_next_line_pattern_start()
117+
118+
is_pattern = self.is_char_pattern_start(self.current_peek())
119+
self.reset_peek()
120+
return is_pattern
121+
104122
def is_peek_next_line_zero_four_style_comment(self):
105123
if not self.current_peek_is('\n'):
106124
return False
@@ -193,7 +211,7 @@ def is_peek_next_line_attribute_start(self):
193211
self.reset_peek()
194212
return False
195213

196-
def is_peek_next_non_blank_line_pattern(self):
214+
def is_peek_next_line_pattern_start(self):
197215
if not self.current_peek_is('\n'):
198216
return False
199217

@@ -209,10 +227,7 @@ def is_peek_next_non_blank_line_pattern(self):
209227
self.reset_peek()
210228
return False
211229

212-
if (self.current_peek_is('}') or
213-
self.current_peek_is('.') or
214-
self.current_peek_is('[') or
215-
self.current_peek_is('*')):
230+
if not self.is_char_pattern_start(self.current_peek()):
216231
self.reset_peek()
217232
return False
218233

fluent/syntax/parser.py

Lines changed: 19 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -56,8 +56,6 @@ def parse(self, source):
5656
entries.append(entry)
5757

5858
ps.last_comment_zero_four_syntax = False
59-
60-
ps.skip_inline_ws()
6159
ps.skip_blank_lines()
6260

6361
res = ast.Resource(entries)
@@ -209,12 +207,13 @@ def get_message(self, ps, comment):
209207
pattern = None
210208
attrs = None
211209

210+
# XXX Syntax 0.4 compat
212211
if ps.current_is('='):
213212
ps.next()
214-
ps.skip_inline_ws()
215-
ps.skip_blank_lines()
216213

217-
pattern = self.get_pattern(ps)
214+
if ps.is_peek_pattern_start():
215+
ps.skip_indent()
216+
pattern = self.get_pattern(ps)
218217

219218
if ps.is_peek_next_line_attribute_start():
220219
attrs = self.get_attributes(ps)
@@ -226,27 +225,25 @@ def get_message(self, ps, comment):
226225

227226
@with_span
228227
def get_attribute(self, ps):
228+
ps.expect_indent()
229229
ps.expect_char('.')
230230

231231
key = self.get_public_identifier(ps)
232232

233233
ps.skip_inline_ws()
234234
ps.expect_char('=')
235-
ps.skip_inline_ws()
236235

237-
value = self.get_pattern(ps)
236+
if ps.is_peek_pattern_start():
237+
ps.skip_indent()
238+
value = self.get_pattern(ps)
239+
return ast.Attribute(key, value)
238240

239-
if value is None:
240-
raise ParseError('E0006', 'value')
241-
242-
return ast.Attribute(key, value)
241+
raise ParseError('E0006', 'value')
243242

244243
def get_attributes(self, ps):
245244
attrs = []
246245

247246
while True:
248-
ps.expect_indent()
249-
250247
attr = self.get_attribute(ps)
251248
attrs.append(attr)
252249

@@ -288,6 +285,8 @@ def get_variant_key(self, ps):
288285

289286
@with_span
290287
def get_variant(self, ps, has_default):
288+
ps.expect_indent()
289+
291290
default_index = False
292291

293292
if ps.current_is('*'):
@@ -302,22 +301,18 @@ def get_variant(self, ps, has_default):
302301

303302
ps.expect_char(']')
304303

305-
ps.skip_inline_ws()
306-
307-
value = self.get_pattern(ps)
308-
309-
if value is None:
310-
raise ParseError('E0006', 'value')
304+
if ps.is_peek_pattern_start():
305+
ps.skip_indent()
306+
value = self.get_pattern(ps)
307+
return ast.Variant(key, value, default_index)
311308

312-
return ast.Variant(key, value, default_index)
309+
raise ParseError('E0006', 'value')
313310

314311
def get_variants(self, ps):
315312
variants = []
316313
has_default = False
317314

318315
while True:
319-
ps.expect_indent()
320-
321316
variant = self.get_variant(ps, has_default)
322317

323318
if variant.default:
@@ -383,17 +378,12 @@ def get_pattern(self, ps):
383378
elements = []
384379
ps.skip_inline_ws()
385380

386-
# Special-case: trim leading whitespace and newlines.
387-
if ps.is_peek_next_non_blank_line_pattern():
388-
ps.skip_blank_lines()
389-
ps.skip_inline_ws()
390-
391381
while ps.current():
392382
ch = ps.current()
393383

394384
# The end condition for get_pattern's while loop is a newline
395385
# which is not followed by a valid pattern continuation.
396-
if ch == '\n' and not ps.is_peek_next_non_blank_line_pattern():
386+
if ch == '\n' and not ps.is_peek_next_line_pattern_start():
397387
break
398388

399389
if ch == '{':
@@ -416,7 +406,7 @@ def get_text_element(self, ps):
416406
return ast.TextElement(buf)
417407

418408
if ch == '\n':
419-
if not ps.is_peek_next_non_blank_line_pattern():
409+
if not ps.is_peek_next_line_pattern_start():
420410
return ast.TextElement(buf)
421411

422412
ps.next()

fluent/syntax/serializer.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,9 +98,9 @@ def serialize_message(message):
9898
parts.append("\n")
9999

100100
parts.append(serialize_identifier(message.id))
101+
parts.append(" =")
101102

102103
if message.value:
103-
parts.append(" =")
104104
parts.append(serialize_value(message.value))
105105

106106
if message.attributes:

tests/migrate/fixtures/en-US/aboutDownloads.ftl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -7,19 +7,19 @@ header = Your Downloads
77
empty = No Downloads
88
about = About Downloads
99
10-
open-menuitem
10+
open-menuitem =
1111
.label = Open
12-
retry-menuitem
12+
retry-menuitem =
1313
.label = Retry
14-
remove-menuitem
14+
remove-menuitem =
1515
.label = Delete
16-
pause-menuitem
16+
pause-menuitem =
1717
.label = Pause
18-
resume-menuitem
18+
resume-menuitem =
1919
.label = Resume
20-
cancel-menuitem
20+
cancel-menuitem =
2121
.label = Cancel
22-
remove-all-menuitem
22+
remove-all-menuitem =
2323
.label = Delete All
2424
2525
delete-all-title = Delete All

tests/migrate/fixtures/en-US/toolbar.ftl

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,23 @@
22
# License, v. 2.0. If a copy of the MPL was not distributed with this
33
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
44

5-
urlbar-textbox
5+
urlbar-textbox =
66
.placeholder = Search or enter address
77
.accesskey = d
88
99
1010
## Toolbar items
1111

12-
view-bookmarks-broadcaster
12+
view-bookmarks-broadcaster =
1313
.label = Bookmarks
14-
view-bookmarks-command
14+
view-bookmarks-command =
1515
.key = b
16-
view-bookmarks-command-win
16+
view-bookmarks-command-win =
1717
.key = i
1818
19-
view-history-broadcaster
19+
view-history-broadcaster =
2020
.label = History
21-
view-history-command
21+
view-history-command =
2222
.key = h
23-
view-tabs-broadcaster
23+
view-tabs-broadcaster =
2424
.label = Synced Tabs

tests/migrate/test_context_real_examples.py

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -215,19 +215,19 @@ def test_merge_context_all_messages(self):
215215
header = Twoje pobrane pliki
216216
empty = Brak pobranych plików
217217
218-
open-menuitem
218+
open-menuitem =
219219
.label = Otwórz
220-
retry-menuitem
220+
retry-menuitem =
221221
.label = Spróbuj ponownie
222-
remove-menuitem
222+
remove-menuitem =
223223
.label = Usuń
224-
pause-menuitem
224+
pause-menuitem =
225225
.label = Wstrzymaj
226-
resume-menuitem
226+
resume-menuitem =
227227
.label = Wznów
228-
cancel-menuitem
228+
cancel-menuitem =
229229
.label = Anuluj
230-
remove-all-menuitem
230+
remove-all-menuitem =
231231
.label = Usuń wszystko
232232
233233
delete-all-title = Usuń wszystko

0 commit comments

Comments
 (0)