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
use crate::bundle::FluentBundleBase;
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 FluentBundleBase<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: MemoizerKind> Scope<'scope, 'errors, R, M> {
pub fn new(
bundle: &'scope FluentBundleBase<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,
{
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,
{
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: &'scope Option<ast::CallArguments<&'scope str>>,
) -> (Vec<FluentValue<'scope>>, FluentArgs<'scope>)
where
R: Borrow<FluentResource>,
{
let mut resolved_positional_args = Vec::new();
let mut resolved_named_args = FluentArgs::new();
if let Some(ast::CallArguments { named, positional }) = arguments {
for expression in positional {
resolved_positional_args.push(expression.resolve(self));
}
for arg in named {
resolved_named_args.add(arg.name.name, arg.value.resolve(self));
}
}
(resolved_positional_args, resolved_named_args)
}
}