Skip to content

Commit 77eb75d

Browse files
authored
Merge pull request #9 from alerque/place-for-placables
2 parents 3bddc92 + 716476f commit 77eb75d

File tree

4 files changed

+87
-49
lines changed

4 files changed

+87
-49
lines changed

fluent/parser.lua

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -48,12 +48,12 @@ local ftl_grammar = epnf.define(function (_ENV)
4848
Variant = line_end * blank^-1 * V"VariantKey" * blank_inline^-1 * V"Pattern"
4949
DefaultVariant = line_end * blank^-1 * P"*" * V"VariantKey" * blank_inline^-1 * V"Pattern"
5050
VariantKey = P"[" * blank^-1 * (V"NumberLiteral" + V"Identifier") * blank^-1 * P"]"
51-
NumberLiteral = P"-"^-1 * digits * (P"." * digits)^-1
51+
NumberLiteral = Cg(C(P"-"^-1 * digits * (P"." * digits)^-1), "value")
5252
local inline_placeable = P"{" * blank^-1 * (V"SelectExpression" + V"InlineExpression") * blank^-1 * P"}"
5353
local block_placeable = blank_block * blank_inline^-1 * inline_placeable
5454
local inline_text = text_char^1
5555
local block_text = blank_block * blank_inline * indented_char * inline_text^-1
56-
StringLiteral = P'"' * quoted_char^0 * P'"'
56+
StringLiteral = P'"' * Cg(C(quoted_char^0), "value") * P'"'
5757
FunctionReference = V"Identifier" * V"CallArguments"
5858
MessageReference = V"Identifier" * V"AttributeAccessor"^-1
5959
TermReference = P"-" * V"Identifier" * V"AttributeAccessor"^-1 * V"CallArguments"^-1
@@ -65,10 +65,10 @@ local ftl_grammar = epnf.define(function (_ENV)
6565
CallArguments = blank^-1 * P"(" * blank^-1 * argument_list * blank^-1 * P")"
6666
SelectExpression = V"InlineExpression" * blank^-1 * P"->" * blank_inline^-1 * variant_list
6767
InlineExpression = V"StringLiteral" + V"NumberLiteral" + V"FunctionReference" + V"MessageReference" + V"TermReference" + V"VariableReference" + inline_placeable
68-
PatternElement = Cg(C(inline_text + block_text + inline_placeable + block_placeable), "value")
68+
PatternElement = Cg(C(inline_text + block_text), "value") + Cg(inline_placeable + block_placeable, "expression")
6969
Pattern = V"PatternElement"^1
7070
Attribute = line_end * blank^-1 * P"." * V"Identifier" * blank_inline^-1 * "=" * blank_inline^-1 * V"Pattern"
71-
local junk_line = (1-line_end)^0 * (P"\n" + P(nulleof))
71+
local junk_line = (1-line_end)^0 * (P"\n" + P(nulleof))
7272
Junk = Cg(junk_line * (junk_line - P"#" - P"-" - R("az","AZ"))^0, "content")
7373
local comment_char = any_char - line_end
7474
CommentLine = Cg(P"###" + P"##" + P"#", "sigil") * (" " * Cg(C(comment_char^0), "content"))^-1 * line_end

fluent/resource.lua

Lines changed: 62 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -22,39 +22,33 @@ local FluentNode = class({
2222
end
2323
end
2424
end
25-
if (node[1] and #node > 0) then
26-
self.elements = {}
27-
tablex.insertvalues(self.elements, tablex.imap(node_to_type, node))
25+
tablex.foreachi(node, function (n) self:insert(node_to_type(n)) end)
26+
end,
27+
28+
insert = function (self, node)
29+
if type(node) ~= "table" then return nil end
30+
if node:is_a(node_types.Identifier) then
31+
self.id = node
32+
elseif node:is_a(node_types.Pattern) then
33+
self.value = node
34+
else
35+
if not self.elements then self.elements = {} end
36+
table.insert(self.elements, node)
2837
end
2938
end,
3039

3140
dump_ast = function (self)
3241
local ast = { type = self.type }
3342
for k, v in pairs(self) do ast[k] = v end
34-
ast.identifier = nil
3543
return ast
3644
end,
3745

3846
append = function (self, node)
39-
if type(self.__add) == "function"
40-
and self.appendable
41-
and node.appendable
42-
and self:is_a(node:is_a())
43-
then
44-
return self + node
45-
else
46-
return false
47-
end
47+
return node and type(node.__add) == "function" and self + node
4848
end,
4949

5050
attach = function (self, node)
51-
if node and
52-
type(node.__mul) == "function"
53-
then
54-
return node * self
55-
else
56-
return false
57-
end
51+
return node and type(node.__mul) == "function" and self * node
5852
end
5953

6054
})
@@ -84,17 +78,6 @@ node_types.Message = class({
8478
_base = FluentNode,
8579
_init = function (self, node)
8680
self:super(node)
87-
for key, value in ipairs(self.elements) do
88-
if value:is_a(node_types.Identifier) then
89-
self.identifier = value.name
90-
self.id = value
91-
self.elements[key] = nil
92-
elseif value:is_a(node_types.Pattern) then
93-
self.value = value
94-
self.elements[key] = nil
95-
end
96-
end
97-
if #self.elements == 0 then self.elements = nil end
9881
self.attributes = {}
9982
end,
10083
format = function (self, parameters)
@@ -145,24 +128,63 @@ node_types.TextElement = class({
145128
appendable = true,
146129
_base = FluentNode,
147130
_init = function (self, node)
131+
node.id = "TextElement"
148132
self:super(node)
149133
end
150134
})
151135

136+
node_types.Placeable = class({
137+
appendable = true,
138+
_base = FluentNode,
139+
_init = function (self, node)
140+
node.id = "Placeable"
141+
self:super(node)
142+
if node.expression then
143+
self.expression = node_to_type(node.expression[1])
144+
end
145+
end
146+
})
147+
152148
node_types.PatternElement = function (node)
153-
node.id = "TextElement"
154-
return node_types.TextElement(node)
149+
if node.value then
150+
return node_types.TextElement(node)
151+
else
152+
return node_types.Placeable(node)
153+
end
155154
end
156155

156+
node_types.StringLiteral = class({
157+
_base = FluentNode,
158+
_init = function (self, node)
159+
self:super(node)
160+
end
161+
})
162+
163+
node_types.NumberLiteral = class({
164+
_base = FluentNode,
165+
_init = function (self, node)
166+
self:super(node)
167+
end
168+
})
169+
170+
node_types.VariableReference = class({
171+
_base = FluentNode,
172+
_init = function (self, node)
173+
self:super(node)
174+
end
175+
})
176+
157177
node_types.Comment = class({
158178
appendable = true,
159179
_base = FluentNode,
160180
_init = function (self, node)
161181
self:super(node)
162182
end,
163183
__add = function (self, node)
164-
self.content = (self.content or "") .. "\n" .. (node.content or "")
165-
return self
184+
if self:is_a(node:is_a()) and self.appendable and node.appendable then
185+
self.content = (self.content or "") .. "\n" .. (node.content or "")
186+
return self
187+
end
166188
end,
167189
__mul = function (self, node)
168190
if self:is_a(node_types.Message) then
@@ -208,8 +230,9 @@ node_types.CommentLine = function(node)
208230
end
209231

210232
node_to_type = function (node)
211-
if type(node.id) ~= "string" then return nil end
212-
return node_types[node.id](node)
233+
if type(node) == "table" and type(node.id) == "string" then
234+
return node_types[node.id](node)
235+
end
213236
end
214237

215238
dedent = function (content)
@@ -273,7 +296,7 @@ local FluentResource = class({
273296
insert = function (self, node)
274297
table.insert(self.body, node)
275298
if node:is_a(node_types.Message) then
276-
self.index[node.identifier] = #self.body
299+
self.index[node.id.name] = #self.body
277300
end
278301
end,
279302

@@ -288,6 +311,7 @@ local FluentResource = class({
288311
end,
289312

290313
__add = function (self, resource)
314+
if not self:is_a(resource:is_a()) then error("Cannot merge unlike types") end
291315
for _, node in ipairs(resource.body) do
292316
self:insert(node)
293317
end

spec/fixtures_spec.lua

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ describe('upstream reference fixture', function ()
3636
-- or fname:match("/escaped_characters.ftl$")
3737
or fname:match("/junk.ftl$")
3838
-- or fname:match("/leading_dots.ftl$")
39-
-- or fname:match("/literal_expressions.ftl$")
39+
or fname:match("/literal_expressions.ftl$")
4040
-- or fname:match("/member_expressions.ftl$")
4141
-- or fname:match("/messages.ftl$")
4242
-- or fname:match("/mixed_entries.ftl$")
@@ -51,7 +51,7 @@ describe('upstream reference fixture', function ()
5151
or fname:match("/tab.ftl$")
5252
-- or fname:match("/term_parameters.ftl$")
5353
-- or fname:match("/terms.ftl$")
54-
-- or fname:match("/variables.ftl$")
54+
or fname:match("/variables.ftl$")
5555
-- or fname:match("/variant_keys.ftl$")
5656
-- or fname:match("/whitespace_in_value.ftl$")
5757
or fname:match("/zero_length.ftl$")
@@ -143,7 +143,7 @@ describe('upstream structure fixture', function ()
143143
-- or fname:match("/term.ftl")
144144
or fname:match("/term_with_empty_pattern.ftl")
145145
or fname:match("/unclosed_empty_placeable_error.ftl")
146-
-- or fname:match("/unclosed.ftl")
146+
-- -- or fname:match("/unclosed.ftl") -- see https://github.com/projectfluent/fluent/issues/296
147147
or fname:match("/unknown_entry_start.ftl")
148148
or fname:match("/variant_ends_abruptly.ftl")
149149
-- or fname:match("/variant_keys.ftl")

spec/fluent_syntax_spec.lua

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -49,15 +49,29 @@ describe('fluent.syntax', function ()
4949
assert.equals("Pattern", foobaz.body[1].value.type)
5050
end)
5151

52-
it('should handle complex term entries', function ()
52+
it('should handle multiline entries', function ()
5353
local foo = syntax:parsestring("foo = türkçe\n görüşürüz")
5454
assert.equals("Pattern", foo.body[1].value.type)
5555
end)
5656

57+
it('should handle literal string placables', function ()
58+
local foo = syntax:parsestring('foo = bar {"baz"}')
59+
assert.equals(2, #foo.body[1].value.elements)
60+
assert.equals("TextElement", foo.body[1].value.elements[1].type)
61+
assert.equals("Placeable", foo.body[1].value.elements[2].type)
62+
end)
63+
64+
it('should handle literal number placables', function ()
65+
local foo = syntax:parsestring('foo = bar {-54.3}')
66+
assert.equals(2, #foo.body[1].value.elements)
67+
assert.equals("TextElement", foo.body[1].value.elements[1].type)
68+
assert.equals("Placeable", foo.body[1].value.elements[2].type)
69+
end)
70+
5771
it('should handle simple comments', function ()
58-
assert.same("Comment", syntax:parsestring("# foo").body[1].type)
59-
assert.same("GroupComment", syntax:parsestring("## foo").body[1].type)
60-
assert.same("ResourceComment", syntax:parsestring("### foo").body[1].type)
72+
assert.equals("Comment", syntax:parsestring("# foo").body[1].type)
73+
assert.equals("GroupComment", syntax:parsestring("## foo").body[1].type)
74+
assert.equals("ResourceComment", syntax:parsestring("### foo").body[1].type)
6175
end)
6276

6377
it('should handle junk', function ()

0 commit comments

Comments
 (0)