Skip to content

Commit 061c3ca

Browse files
committed
Convert resolver to a pre-evaluated tree
1 parent a13ef99 commit 061c3ca

File tree

3 files changed

+228
-198
lines changed

3 files changed

+228
-198
lines changed

fluent.runtime/fluent/runtime/__init__.py

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,8 @@
88
from fluent.syntax.ast import Message, Term
99

1010
from .builtins import BUILTINS
11-
from .resolver import resolve
11+
from .prepare import Compiler
12+
from .resolver import ResolverEnvironment, CurrentEnvironment
1213
from .utils import ATTRIBUTE_SEPARATOR, TERM_SIGIL, add_message_and_attrs_to_store, ast_to_id
1314

1415

@@ -33,6 +34,8 @@ def __init__(self, locales, functions=None, use_isolating=True):
3334
self._functions = _functions
3435
self._use_isolating = use_isolating
3536
self._messages_and_terms = {}
37+
self._compiled = {}
38+
self._compiler = Compiler()
3639
self._babel_locale = self._get_babel_locale()
3740
self._plural_form = babel.plural.to_python(self._babel_locale.plural_form)
3841

@@ -56,10 +59,17 @@ def has_message(self, message_id):
5659
def format(self, message_id, args=None):
5760
if message_id.startswith(TERM_SIGIL):
5861
raise LookupError(message_id)
59-
message = self._messages_and_terms[message_id]
6062
if args is None:
6163
args = {}
62-
return resolve(self, message, args)
64+
if message_id not in self._compiled:
65+
message = self._messages_and_terms[message_id]
66+
self._compiled[message_id] = self._compiler(message.value)
67+
resolve = self._compiled[message_id]
68+
errors = []
69+
env = ResolverEnvironment(context=self,
70+
current=CurrentEnvironment(args=args),
71+
errors=errors)
72+
return [resolve(env), errors]
6373

6474
def _get_babel_locale(self):
6575
for l in self.locales:
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
from __future__ import absolute_import, unicode_literals
2+
from fluent.syntax import ast as FTL
3+
from . import resolver
4+
5+
6+
class Compiler(object):
7+
def __init__(self, bundle=None):
8+
self.bundle = None
9+
10+
def __call__(self, item):
11+
if isinstance(item, FTL.BaseNode):
12+
return self.compile(item)
13+
if isinstance(item, (tuple, list)):
14+
return [self(elem) for elem in item]
15+
return item
16+
17+
def compile(self, node):
18+
nodename = type(node).__name__
19+
if not hasattr(resolver, nodename):
20+
return node
21+
kwargs = vars(node).copy()
22+
for propname, propvalue in kwargs.items():
23+
kwargs[propname] = self(propvalue)
24+
handler = getattr(self, 'compile_' + nodename, self.compile_generic)
25+
return handler(nodename, **kwargs)
26+
27+
def compile_generic(self, nodename, **kwargs):
28+
return getattr(resolver, nodename)(**kwargs)
29+
30+
def compile_Placeable(self, _, expression, **kwargs):
31+
if isinstance(expression, resolver.Literal):
32+
return expression
33+
return resolver.Placeable(expression=expression, **kwargs)
34+
35+
def compile_Pattern(self, _, elements, **kwargs):
36+
if any(
37+
not isinstance(child, resolver.Literal)
38+
for child in elements
39+
):
40+
return resolver.Pattern(elements=elements, **kwargs)
41+
if len(elements) == 1:
42+
return elements[0]
43+
return resolver.TextElement(
44+
''.join(child(None) for child in elements)
45+
)

0 commit comments

Comments
 (0)