1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
|
use super::scope::Scope;
use super::{ResolverError, WriteValue};
use std::borrow::Borrow;
use std::fmt;
use fluent_syntax::ast;
use crate::memoizer::MemoizerKind;
use crate::resolver::ResolveValue;
use crate::resource::FluentResource;
use crate::types::FluentValue;
const MAX_PLACEABLES: u8 = 100;
impl<'p> WriteValue for ast::Pattern<&'p str> {
fn write<'scope, 'errors, W, R, M>(
&'scope self,
w: &mut W,
scope: &mut Scope<'scope, 'errors, R, M>,
) -> fmt::Result
where
W: fmt::Write,
R: Borrow<FluentResource>,
M: MemoizerKind,
{
let len = self.elements.len();
for elem in &self.elements {
if scope.dirty {
return Ok(());
}
match elem {
ast::PatternElement::TextElement { value } => {
if let Some(ref transform) = scope.bundle.transform {
w.write_str(&transform(value))?;
} else {
w.write_str(value)?;
}
}
ast::PatternElement::Placeable { ref expression } => {
scope.placeables += 1;
if scope.placeables > MAX_PLACEABLES {
scope.dirty = true;
scope.add_error(ResolverError::TooManyPlaceables);
return Ok(());
}
let needs_isolation = scope.bundle.use_isolating
&& len > 1
&& !matches!(
expression,
ast::Expression::Inline(ast::InlineExpression::MessageReference { .. },)
| ast::Expression::Inline(
ast::InlineExpression::TermReference { .. },
)
| ast::Expression::Inline(
ast::InlineExpression::StringLiteral { .. },
)
);
if needs_isolation {
w.write_char('\u{2068}')?;
}
scope.maybe_track(w, self, expression)?;
if needs_isolation {
w.write_char('\u{2069}')?;
}
}
}
}
Ok(())
}
fn write_error<W>(&self, _w: &mut W) -> fmt::Result
where
W: fmt::Write,
{
unreachable!()
}
}
impl<'p> ResolveValue for ast::Pattern<&'p str> {
fn resolve<'source, 'errors, R, M>(
&'source self,
scope: &mut Scope<'source, 'errors, R, M>,
) -> FluentValue<'source>
where
R: Borrow<FluentResource>,
M: MemoizerKind,
{
let len = self.elements.len();
if len == 1 {
if let ast::PatternElement::TextElement { value } = self.elements[0] {
return scope
.bundle
.transform
.map_or_else(|| value.into(), |transform| transform(value).into());
}
}
let mut result = String::new();
self.write(&mut result, scope)
.expect("Failed to write to a string.");
result.into()
}
}
|