summaryrefslogtreecommitdiffstats
path: root/intl/l10n/rust/fluent-ffi/src/text_elements.rs
diff options
context:
space:
mode:
Diffstat (limited to 'intl/l10n/rust/fluent-ffi/src/text_elements.rs')
-rw-r--r--intl/l10n/rust/fluent-ffi/src/text_elements.rs164
1 files changed, 164 insertions, 0 deletions
diff --git a/intl/l10n/rust/fluent-ffi/src/text_elements.rs b/intl/l10n/rust/fluent-ffi/src/text_elements.rs
new file mode 100644
index 0000000000..0ffeffd4c7
--- /dev/null
+++ b/intl/l10n/rust/fluent-ffi/src/text_elements.rs
@@ -0,0 +1,164 @@
+/* This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this file,
+ * You can obtain one at http://mozilla.org/MPL/2.0/. */
+
+use fluent::FluentResource;
+use fluent_syntax::ast;
+use nsstring::nsCString;
+use thin_vec::ThinVec;
+
+#[repr(C)]
+pub struct TextElementInfo {
+ id: nsCString,
+ attr: nsCString,
+ text: nsCString,
+}
+
+struct TextElementsCollector<'a> {
+ current_id: Option<String>,
+ current_attr: Option<String>,
+ elements: &'a mut ThinVec<TextElementInfo>,
+}
+
+impl<'a> TextElementsCollector<'a> {
+ pub fn new(elements: &'a mut ThinVec<TextElementInfo>) -> Self {
+ Self {
+ current_id: None,
+ current_attr: None,
+ elements: elements,
+ }
+ }
+
+ fn collect_inline_expression(&mut self, x: &ast::InlineExpression<&str>) {
+ match x {
+ ast::InlineExpression::StringLiteral { .. } => {}
+ ast::InlineExpression::NumberLiteral { .. } => {}
+ ast::InlineExpression::FunctionReference { arguments, .. } => {
+ self.collect_call_arguments(arguments);
+ }
+ ast::InlineExpression::MessageReference { .. } => {}
+ ast::InlineExpression::TermReference { arguments, .. } => {
+ if let Some(y) = arguments {
+ self.collect_call_arguments(y);
+ }
+ }
+ ast::InlineExpression::VariableReference { .. } => {}
+ ast::InlineExpression::Placeable { expression } => {
+ self.collect_expression(expression.as_ref());
+ }
+ }
+ }
+
+ fn collect_named_argument(&mut self, x: &ast::NamedArgument<&str>) {
+ self.collect_inline_expression(&x.value);
+ }
+
+ fn collect_call_arguments(&mut self, x: &ast::CallArguments<&str>) {
+ for y in x.positional.iter() {
+ self.collect_inline_expression(y);
+ }
+ for y in x.named.iter() {
+ self.collect_named_argument(y);
+ }
+ }
+
+ fn collect_variant(&mut self, x: &ast::Variant<&str>) {
+ self.collect_pattern(&x.value);
+ }
+
+ fn collect_expression(&mut self, x: &ast::Expression<&str>) {
+ match x {
+ ast::Expression::Select { selector, variants } => {
+ self.collect_inline_expression(selector);
+ for y in variants.iter() {
+ self.collect_variant(y);
+ }
+ }
+ ast::Expression::Inline(i) => {
+ self.collect_inline_expression(i);
+ }
+ }
+ }
+
+ fn collect_pattern_element(&mut self, x: &ast::PatternElement<&str>) {
+ match x {
+ ast::PatternElement::TextElement { value } => {
+ self.elements.push(TextElementInfo {
+ id: self
+ .current_id
+ .as_ref()
+ .map_or_else(|| nsCString::new(), nsCString::from),
+ attr: self
+ .current_attr
+ .as_ref()
+ .map_or_else(|| nsCString::new(), nsCString::from),
+ text: nsCString::from(*value),
+ });
+ }
+ ast::PatternElement::Placeable { expression } => {
+ self.collect_expression(expression);
+ }
+ }
+ }
+
+ fn collect_pattern(&mut self, x: &ast::Pattern<&str>) {
+ for y in x.elements.iter() {
+ self.collect_pattern_element(y);
+ }
+ }
+
+ fn collect_attribute(&mut self, x: &ast::Attribute<&str>) {
+ self.current_attr = Some(x.id.name.to_string());
+
+ self.collect_pattern(&x.value);
+ }
+
+ fn collect_message(&mut self, x: &ast::Message<&str>) {
+ self.current_id = Some(x.id.name.to_string());
+ self.current_attr = None;
+
+ if let Some(ref y) = x.value {
+ self.collect_pattern(y);
+ }
+ for y in x.attributes.iter() {
+ self.collect_attribute(y);
+ }
+ }
+
+ fn collect_term(&mut self, x: &ast::Term<&str>) {
+ self.current_id = Some(x.id.name.to_string());
+ self.current_attr = None;
+
+ self.collect_pattern(&x.value);
+ for y in x.attributes.iter() {
+ self.collect_attribute(y);
+ }
+ }
+
+ pub fn collect_entry(&mut self, x: &ast::Entry<&str>) {
+ match x {
+ ast::Entry::Message(m) => {
+ self.collect_message(m);
+ }
+ ast::Entry::Term(t) => {
+ self.collect_term(t);
+ }
+ ast::Entry::Comment(_) => {}
+ ast::Entry::GroupComment(_) => {}
+ ast::Entry::ResourceComment(_) => {}
+ ast::Entry::Junk { .. } => {}
+ }
+ }
+}
+
+#[no_mangle]
+pub extern "C" fn fluent_resource_get_text_elements(
+ res: &FluentResource,
+ elements: &mut ThinVec<TextElementInfo>,
+) {
+ let mut collector = TextElementsCollector::new(elements);
+
+ for entry in res.entries() {
+ collector.collect_entry(entry);
+ }
+}