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
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
use crate::bundle::FluentBundle;
use crate::memoizer::MemoizerKind;
use crate::resolver::{ResolveValue, ResolverError, WriteValue};
use crate::types::FluentValue;
use crate::{FluentArgs, FluentError, FluentResource};
use fluent_syntax::ast;
use std::borrow::Borrow;
use std::fmt;
pub struct Scope<'scope, 'errors, R, M> {
pub bundle: &'scope FluentBundle<R, M>,
pub(super) args: Option<&'scope FluentArgs<'scope>>,
pub(super) local_args: Option<FluentArgs<'scope>>,
pub(super) placeables: u8,
travelled: smallvec::SmallVec<[&'scope ast::Pattern<&'scope str>; 2]>,
pub errors: Option<&'errors mut Vec<FluentError>>,
pub dirty: bool,
}
impl<'scope, 'errors, R, M> Scope<'scope, 'errors, R, M> {
pub fn new(
bundle: &'scope FluentBundle<R, M>,
args: Option<&'scope FluentArgs>,
errors: Option<&'errors mut Vec<FluentError>>,
) -> Self {
Scope {
bundle,
args,
local_args: None,
placeables: 0,
travelled: Default::default(),
errors,
dirty: false,
}
}
pub fn add_error(&mut self, error: ResolverError) {
if let Some(errors) = self.errors.as_mut() {
errors.push(error.into());
}
}
pub fn maybe_track<W>(
&mut self,
w: &mut W,
pattern: &'scope ast::Pattern<&str>,
exp: &'scope ast::Expression<&str>,
) -> fmt::Result
where
R: Borrow<FluentResource>,
W: fmt::Write,
M: MemoizerKind,
{
if self.travelled.is_empty() {
self.travelled.push(pattern);
}
exp.write(w, self)?;
if self.dirty {
w.write_char('{')?;
exp.write_error(w)?;
w.write_char('}')
} else {
Ok(())
}
}
pub fn track<W>(
&mut self,
w: &mut W,
pattern: &'scope ast::Pattern<&str>,
exp: &ast::InlineExpression<&str>,
) -> fmt::Result
where
R: Borrow<FluentResource>,
W: fmt::Write,
M: MemoizerKind,
{
if self.travelled.contains(&pattern) {
self.add_error(ResolverError::Cyclic);
w.write_char('{')?;
exp.write_error(w)?;
w.write_char('}')
} else {
self.travelled.push(pattern);
let result = pattern.write(w, self);
self.travelled.pop();
result
}
}
pub fn write_ref_error<W>(
&mut self,
w: &mut W,
exp: &ast::InlineExpression<&str>,
) -> fmt::Result
where
W: fmt::Write,
{
self.add_error(exp.into());
w.write_char('{')?;
exp.write_error(w)?;
w.write_char('}')
}
pub fn get_arguments(
&mut self,
arguments: Option<&'scope ast::CallArguments<&'scope str>>,
) -> (Vec<FluentValue<'scope>>, FluentArgs<'scope>)
where
R: Borrow<FluentResource>,
M: MemoizerKind,
{
if let Some(ast::CallArguments { positional, named }) = arguments {
let positional = positional.iter().map(|expr| expr.resolve(self)).collect();
let named = named
.iter()
.map(|arg| (arg.name.name, arg.value.resolve(self)))
.collect();
(positional, named)
} else {
(Vec::new(), FluentArgs::new())
}
}
}