Skip to content

Commit 3c7cd30

Browse files
Pikestasm
authored andcommitted
(WIP) Parse TextElement line by line (#171)
In order to be able to preserve the indent of multiline text values for AST generation, we start by parsing TextElements line by line.
1 parent 4f861fd commit 3c7cd30

File tree

2 files changed

+53
-35
lines changed

2 files changed

+53
-35
lines changed

spec/fluent.ebnf

Lines changed: 15 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -29,11 +29,19 @@ Value ::= Pattern
2929
| VariantList
3030
Pattern ::= PatternElement+
3131
VariantList ::= blank? "{" variant_list blank? "}"
32-
PatternElement ::= TextElement
33-
| Placeable
34-
| (blank_block blank_inline? Placeable)
35-
TextElement ::= (text_char | text_cont)+
36-
Placeable ::= "{" blank? (SelectExpression | InlineExpression) blank? "}"
32+
33+
/* TextElement and Placeable can occur inline or as block.
34+
* Text needs to be indented and start with a non-special character.
35+
* Placeables can start at the beginning of the line or be indented.
36+
* Adjacent TextElements are joined in AST creation. */
37+
PatternElement ::= inline_text
38+
| block_text
39+
| inline_placeable
40+
| block_placeable
41+
inline_text ::= text_char+
42+
block_text ::= blank_block blank_inline indented_char inline_text?
43+
inline_placeable ::= "{" blank? (SelectExpression | InlineExpression) blank? "}"
44+
block_placeable ::= blank_block blank_inline? inline_placeable
3745

3846
/* Rules for validating expressions in Placeables and as selectors of
3947
* SelectExpressions are documented in spec/valid.md and enforced in
@@ -46,7 +54,7 @@ InlineExpression ::= StringLiteral
4654
| VariantExpression
4755
| MessageReference
4856
| TermReference
49-
| Placeable
57+
| inline_placeable
5058

5159
/* Literals */
5260
StringLiteral ::= quote quoted_text_char* quote
@@ -97,7 +105,7 @@ text_char ::= blank_inline
97105
| (backslash backslash)
98106
| (backslash "{")
99107
| (regular_char - "{" - backslash)
100-
text_cont ::= blank_block blank_inline (text_char - "}" - "[" - "*" - ".")
108+
indented_char ::= text_char - "}" - "[" - "*" - "."
101109
quoted_text_char ::= (text_char - quote)
102110
| (backslash quote)
103111
digit ::= [0-9]

syntax/grammar.mjs

Lines changed: 38 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -117,7 +117,7 @@ let Value = defer(() =>
117117
let Pattern = defer(() =>
118118
repeat1(
119119
PatternElement)
120-
// Flatten indented Placeables.
120+
// Flatten block_text and block_placeable which return lists.
121121
.map(flatten(1))
122122
.chain(list_into(FTL.Pattern)));
123123

@@ -131,26 +131,34 @@ let VariantList = defer(() =>
131131
.map(keep_abstract)
132132
.chain(list_into(FTL.VariantList)));
133133

134+
/* ----------------------------------------------------------------- */
135+
/* TextElement and Placeable can occur inline or as block.
136+
* Text needs to be indented and start with a non-special character.
137+
* Placeables can start at the beginning of the line or be indented.
138+
* Adjacent TextElements are joined in AST creation. */
139+
134140
let PatternElement = defer(() =>
135141
either(
136-
TextElement,
137-
Placeable,
138-
sequence(
139-
// Joined with preceding TextElements during AST construction.
140-
blank_block.chain(into(FTL.TextElement)).abstract,
141-
maybe(blank_inline),
142-
Placeable.abstract)
143-
.map(keep_abstract)));
142+
inline_text,
143+
block_text,
144+
inline_placeable,
145+
block_placeable));
144146

145-
let TextElement = defer(() =>
146-
repeat1(
147-
either(
148-
text_char,
149-
text_cont))
147+
let inline_text = defer(() =>
148+
repeat1(text_char)
150149
.map(join)
151150
.chain(into(FTL.TextElement)));
152151

153-
let Placeable = defer(() =>
152+
let block_text = defer(() =>
153+
sequence(
154+
blank_block.chain(into(FTL.TextElement)).abstract,
155+
blank_inline,
156+
indented_char.chain(into(FTL.TextElement)).abstract,
157+
maybe(inline_text.abstract)
158+
)
159+
.map(keep_abstract));
160+
161+
let inline_placeable = defer(() =>
154162
sequence(
155163
string("{"),
156164
maybe(blank),
@@ -163,6 +171,13 @@ let Placeable = defer(() =>
163171
.map(element_at(2))
164172
.chain(into(FTL.Placeable)));
165173

174+
let block_placeable = defer(() =>
175+
sequence(
176+
blank_block.chain(into(FTL.TextElement)).abstract,
177+
maybe(blank_inline),
178+
inline_placeable.abstract)
179+
.map(keep_abstract));
180+
166181
/* ------------------------------------------------------------------- */
167182
/* Rules for validating expressions in Placeables and as selectors of
168183
* SelectExpressions are documented in spec/valid.md and enforced in
@@ -177,7 +192,7 @@ let InlineExpression = defer(() =>
177192
VariantExpression,
178193
MessageReference,
179194
TermReference,
180-
Placeable));
195+
inline_placeable));
181196

182197
/* -------- */
183198
/* Literals */
@@ -417,18 +432,13 @@ let text_char = defer(() =>
417432
not(string("{")),
418433
regular_char)));
419434

420-
let text_cont = defer(() =>
421-
sequence(
422-
blank_block.abstract,
423-
blank_inline,
424-
and(
425-
not(string(".")),
426-
not(string("*")),
427-
not(string("[")),
428-
not(string("}")),
429-
text_char).abstract)
430-
.map(keep_abstract)
431-
.map(join));
435+
let indented_char = defer(() =>
436+
and(
437+
not(string(".")),
438+
not(string("*")),
439+
not(string("[")),
440+
not(string("}")),
441+
text_char));
432442

433443
let quoted_text_char =
434444
either(

0 commit comments

Comments
 (0)