Using fluent.syntax¶
The fluent.syntax
package provides a parser, a serializer, and libraries
for analysis and processing of Fluent files.
Parsing¶
To parse a full resource, you can use the fluent.syntax.parse()
shorthand:
from fluent.syntax import parse
resource = parse("""
### Fluent resource comment
first = creating a { $thing }
second = more content
""")
To parse a single fluent.syntax.ast.Message
or fluent.syntax.ast.Term
, use
fluent.syntax.parser.FluentParser.parse_entry()
:
from fluent.syntax.parser import FluentParser
parser = FluentParser()
key_message = parser.parse_entry("""
### Fluent resource comment
key = value
""")
Serialization¶
To create Fluent syntax from AST objects, use fluent.syntax.serialize()
or
fluent.syntax.serializer.FluentSerializer
.
from fluent.syntax import serialize
from fluent.syntax.serializer import FluentSerializer
serialize(resource)
serializer = FluentSerializer()
serializer.serialize(resource)
serializer.serialize_entry(key_message)
Analysis (Visitor)¶
To analyze an AST tree in a read-only fashion, you can subclass
fluent.syntax.visitor.Visitor
.
You overload individual visit_NodeName()
methods to
handle nodes of that type, and then call into :py:func`self.generic_visit`
to continue iteration.
from fluent.syntax import visitor
import re
class WordCounter(visitor.Visitor):
COUNTER = re.compile(r"[\w,.-]+")
@classmethod
def count(cls, node):
wordcounter = cls()
wordcounter.visit(node)
return wordcounter.word_count
def __init__(self):
super()
self.word_count = 0
def visit_TextElement(self, node):
self.word_count += len(self.COUNTER.findall(node.value))
self.generic_visit(node)
WordCounter.count(resource)
WordCounter.count(key_message)
In-place Modification (Transformer)¶
Manipulation of an AST tree can be done in-place with a subclass of
fluent.syntax.visitor.Transformer
. The coding pattern matches that
of visitor.Visitor
, but you can modify the node in-place.
You can even return different types, or remove nodes alltogether.
class Skeleton(visitor.Transformer):
def visit_SelectExpression(self, node):
# This should do more checks, good enough for docs
for variant in node.variants:
if variant.default:
default_variant = variant
break
template_variant = self.visit(default_variant)
template_variant.default = False
node.variants[:] = []
for key in ('one', 'few', 'many'):
variant = template_variant.clone()
variant.key.name = key
node.variants.append(variant)
node.variants[-1].default = True
return node
def visit_TextElement(self, node):
return None
skeleton = Skeleton()
skeleton.visit(key_message)
WordCounter.count(key_message)
# Returns 0.
new_plural = skeleton.visit(parser.parse_entry("""
with-plural = { $num ->
[one] Using { -one-term-reference } to hide
*[other] Using { $num } {-term-reference} as template
}
"""))
print(serializer.serialize_entry(new_plural))
This returns
with-plural =
{ $num ->
[one] { $num }{ -term-reference }
[few] { $num }{ -term-reference }
*[many] { $num }{ -term-reference }
}
Warning
Serializing an AST tree that was created like this might not produce valid Fluent content.