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