Skip to content

Commit 9c56917

Browse files
combine Write and Resolve implementations
1 parent 4370cf4 commit 9c56917

File tree

5 files changed

+211
-144
lines changed

5 files changed

+211
-144
lines changed

fluent-bundle/src/resolver/expression.rs

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,31 +1,31 @@
11
use super::scope::Scope;
2-
use super::WriteValue;
2+
use super::{ResolveContext, WriteOrResolve, WriteOrResolveContext};
33

44
use std::borrow::Borrow;
55
use std::fmt;
66

77
use fluent_syntax::ast;
88

99
use crate::memoizer::MemoizerKind;
10-
use crate::resolver::{ResolveValue, ResolverError};
10+
use crate::resolver::ResolverError;
1111
use crate::resource::FluentResource;
1212
use crate::types::FluentValue;
1313

14-
impl<'bundle> WriteValue<'bundle> for ast::Expression<&'bundle str> {
15-
fn write<'ast, 'args, 'errors, W, R, M>(
14+
impl<'bundle> WriteOrResolve<'bundle> for ast::Expression<&'bundle str> {
15+
fn write_or_resolve<'ast, 'args, 'errors, R, M, T>(
1616
&'ast self,
17-
w: &mut W,
1817
scope: &mut Scope<'bundle, 'ast, 'args, 'errors, R, M>,
19-
) -> fmt::Result
18+
context: &mut T,
19+
) -> T::Result
2020
where
21-
W: fmt::Write,
2221
R: Borrow<FluentResource>,
2322
M: MemoizerKind,
23+
T: WriteOrResolveContext<'bundle>,
2424
{
2525
match self {
26-
Self::Inline(exp) => exp.write(w, scope),
26+
Self::Inline(exp) => exp.write_or_resolve(scope, context),
2727
Self::Select { selector, variants } => {
28-
let selector = selector.resolve(scope);
28+
let selector = selector.write_or_resolve(scope, &mut ResolveContext);
2929
match selector {
3030
FluentValue::String(_) | FluentValue::Number(_) => {
3131
for variant in variants {
@@ -36,7 +36,7 @@ impl<'bundle> WriteValue<'bundle> for ast::Expression<&'bundle str> {
3636
}
3737
};
3838
if key.matches(&selector, scope) {
39-
return variant.value.write(w, scope);
39+
return context.resolve_pattern(scope, &variant.value);
4040
}
4141
}
4242
}
@@ -45,11 +45,11 @@ impl<'bundle> WriteValue<'bundle> for ast::Expression<&'bundle str> {
4545

4646
for variant in variants {
4747
if variant.default {
48-
return variant.value.write(w, scope);
48+
return context.resolve_pattern(scope, &variant.value);
4949
}
5050
}
5151
scope.add_error(ResolverError::MissingDefault);
52-
Ok(())
52+
context.error(self, true)
5353
}
5454
}
5555
}
Lines changed: 44 additions & 87 deletions
Original file line numberDiff line numberDiff line change
@@ -1,59 +1,60 @@
11
use super::scope::Scope;
2-
use super::{ResolveValue, ResolverError, WriteValue};
3-
4-
use std::borrow::Borrow;
5-
use std::fmt;
6-
7-
use fluent_syntax::ast;
8-
use fluent_syntax::unicode::{unescape_unicode, unescape_unicode_to_string};
2+
use super::{ResolverError, WriteOrResolve, WriteOrResolveContext};
93

104
use crate::entry::GetEntry;
115
use crate::memoizer::MemoizerKind;
126
use crate::resource::FluentResource;
137
use crate::types::FluentValue;
8+
use fluent_syntax::ast;
9+
use std::borrow::{Borrow, Cow};
10+
use std::fmt;
1411

15-
impl<'bundle> WriteValue<'bundle> for ast::InlineExpression<&'bundle str> {
16-
fn write<'ast, 'args, 'errors, W, R, M>(
12+
impl<'bundle> WriteOrResolve<'bundle> for ast::InlineExpression<&'bundle str> {
13+
fn write_or_resolve<'ast, 'args, 'errors, R, M, T>(
1714
&'ast self,
18-
w: &mut W,
1915
scope: &mut Scope<'bundle, 'ast, 'args, 'errors, R, M>,
20-
) -> fmt::Result
16+
context: &mut T,
17+
) -> T::Result
2118
where
22-
W: fmt::Write,
2319
R: Borrow<FluentResource>,
2420
M: MemoizerKind,
21+
T: WriteOrResolveContext<'bundle>,
2522
{
2623
match self {
27-
Self::StringLiteral { value } => unescape_unicode(w, value),
24+
Self::StringLiteral { value } => context.unescape(value),
2825
Self::MessageReference { id, attribute } => {
2926
if let Some(msg) = scope.bundle.get_entry_message(id.name) {
3027
if let Some(attr) = attribute {
3128
msg.attributes
3229
.iter()
3330
.find_map(|a| {
3431
if a.id.name == attr.name {
35-
Some(scope.track(w, &a.value, self))
32+
Some(scope.track(context, &a.value, self))
3633
} else {
3734
None
3835
}
3936
})
40-
.unwrap_or_else(|| scope.write_ref_error(w, self))
37+
.unwrap_or_else(|| {
38+
scope.add_error(self.into());
39+
context.error(self, true)
40+
})
4141
} else {
4242
msg.value
4343
.as_ref()
44-
.map(|value| scope.track(w, value, self))
44+
.map(|value| scope.track(context, value, self))
4545
.unwrap_or_else(|| {
4646
scope.add_error(ResolverError::NoValue(id.name.to_string()));
47-
w.write_char('{')?;
48-
self.write_error(w)?;
49-
w.write_char('}')
47+
context.error(self, true)
5048
})
5149
}
5250
} else {
53-
scope.write_ref_error(w, self)
51+
scope.add_error(self.into());
52+
context.error(self, true)
5453
}
5554
}
56-
Self::NumberLiteral { value } => FluentValue::try_number(value).write(w, scope),
55+
Self::NumberLiteral { value } => {
56+
context.value(scope, Cow::Owned(FluentValue::try_number(value)))
57+
}
5758
Self::TermReference {
5859
id,
5960
attribute,
@@ -69,16 +70,19 @@ impl<'bundle> WriteValue<'bundle> for ast::InlineExpression<&'bundle str> {
6970
if let Some(attr) = attribute {
7071
term.attributes.iter().find_map(|a| {
7172
if a.id.name == attr.name {
72-
Some(scope.track(w, &a.value, self))
73+
Some(scope.track(context, &a.value, self))
7374
} else {
7475
None
7576
}
7677
})
7778
} else {
78-
Some(scope.track(w, &term.value, self))
79+
Some(scope.track(context, &term.value, self))
7980
}
8081
})
81-
.unwrap_or_else(|| scope.write_ref_error(w, self));
82+
.unwrap_or_else(|| {
83+
scope.add_error(self.into());
84+
context.error(self, true)
85+
});
8286
scope.local_args = None;
8387
result
8488
}
@@ -90,30 +94,31 @@ impl<'bundle> WriteValue<'bundle> for ast::InlineExpression<&'bundle str> {
9094

9195
if let Some(func) = func {
9296
let result = func(resolved_positional_args.as_slice(), &resolved_named_args);
93-
if let FluentValue::Error = result {
94-
self.write_error(w)
97+
if matches!(result, FluentValue::Error) {
98+
context.error(self, false)
9599
} else {
96-
w.write_str(&result.into_string(scope))
100+
context.value(scope, Cow::Owned(result))
97101
}
98102
} else {
99-
scope.write_ref_error(w, self)
103+
scope.add_error(self.into());
104+
context.error(self, true)
100105
}
101106
}
102107
Self::VariableReference { id } => {
103-
let args = scope.local_args.as_ref().or(scope.args);
104-
105-
if let Some(arg) = args.and_then(|args| args.get(id.name)) {
106-
arg.write(w, scope)
107-
} else {
108-
if scope.local_args.is_none() {
109-
scope.add_error(self.into());
108+
if let Some(local_args) = &scope.local_args {
109+
if let Some(arg) = local_args.get(id.name) {
110+
return context.value(scope, Cow::Borrowed(arg));
110111
}
111-
w.write_char('{')?;
112-
self.write_error(w)?;
113-
w.write_char('}')
112+
} else if let Some(arg) = scope.args.and_then(|args| args.get(id.name)) {
113+
return context.value(scope, Cow::Owned(arg.into_owned()));
114+
}
115+
116+
if scope.local_args.is_none() {
117+
scope.add_error(self.into());
114118
}
119+
context.error(self, true)
115120
}
116-
Self::Placeable { expression } => expression.write(w, scope),
121+
Self::Placeable { expression } => expression.write_or_resolve(scope, context),
117122
}
118123
}
119124

@@ -146,51 +151,3 @@ impl<'bundle> WriteValue<'bundle> for ast::InlineExpression<&'bundle str> {
146151
}
147152
}
148153
}
149-
150-
impl<'bundle> ResolveValue<'bundle> for ast::InlineExpression<&'bundle str> {
151-
fn resolve<'ast, 'args, 'errors, R, M>(
152-
&'ast self,
153-
scope: &mut Scope<'bundle, 'ast, 'args, 'errors, R, M>,
154-
) -> FluentValue<'bundle>
155-
where
156-
R: Borrow<FluentResource>,
157-
M: MemoizerKind,
158-
{
159-
match self {
160-
Self::StringLiteral { value } => unescape_unicode_to_string(value).into(),
161-
Self::NumberLiteral { value } => FluentValue::try_number(value),
162-
Self::VariableReference { id } => {
163-
if let Some(local_args) = &scope.local_args {
164-
if let Some(arg) = local_args.get(id.name) {
165-
return arg.clone();
166-
}
167-
} else if let Some(arg) = scope.args.and_then(|args| args.get(id.name)) {
168-
return arg.into_owned();
169-
}
170-
171-
if scope.local_args.is_none() {
172-
scope.add_error(self.into());
173-
}
174-
FluentValue::Error
175-
}
176-
Self::FunctionReference { id, arguments } => {
177-
let (resolved_positional_args, resolved_named_args) =
178-
scope.get_arguments(Some(arguments));
179-
180-
let func = scope.bundle.get_entry_function(id.name);
181-
182-
if let Some(func) = func {
183-
let result = func(resolved_positional_args.as_slice(), &resolved_named_args);
184-
result
185-
} else {
186-
FluentValue::Error
187-
}
188-
}
189-
_ => {
190-
let mut result = String::new();
191-
self.write(&mut result, scope).expect("Failed to write");
192-
result.into()
193-
}
194-
}
195-
}
196-
}

0 commit comments

Comments
 (0)