text_elements.rs (5059B)
1 /* This Source Code Form is subject to the terms of the Mozilla Public 2 * License, v. 2.0. If a copy of the MPL was not distributed with this file, 3 * You can obtain one at http://mozilla.org/MPL/2.0/. */ 4 5 use fluent::FluentResource; 6 use fluent_syntax::ast; 7 use nsstring::nsCString; 8 use thin_vec::ThinVec; 9 10 #[repr(C)] 11 pub struct TextElementInfo { 12 id: nsCString, 13 attr: nsCString, 14 text: nsCString, 15 } 16 17 struct TextElementsCollector<'a> { 18 current_id: Option<String>, 19 current_attr: Option<String>, 20 elements: &'a mut ThinVec<TextElementInfo>, 21 } 22 23 impl<'a> TextElementsCollector<'a> { 24 pub fn new(elements: &'a mut ThinVec<TextElementInfo>) -> Self { 25 Self { 26 current_id: None, 27 current_attr: None, 28 elements, 29 } 30 } 31 32 fn collect_inline_expression(&mut self, x: &ast::InlineExpression<&str>) { 33 match x { 34 ast::InlineExpression::StringLiteral { .. } => {} 35 ast::InlineExpression::NumberLiteral { .. } => {} 36 ast::InlineExpression::FunctionReference { arguments, .. } => { 37 self.collect_call_arguments(arguments); 38 } 39 ast::InlineExpression::MessageReference { .. } => {} 40 ast::InlineExpression::TermReference { arguments, .. } => { 41 if let Some(y) = arguments { 42 self.collect_call_arguments(y); 43 } 44 } 45 ast::InlineExpression::VariableReference { .. } => {} 46 ast::InlineExpression::Placeable { expression } => { 47 self.collect_expression(expression.as_ref()); 48 } 49 } 50 } 51 52 fn collect_named_argument(&mut self, x: &ast::NamedArgument<&str>) { 53 self.collect_inline_expression(&x.value); 54 } 55 56 fn collect_call_arguments(&mut self, x: &ast::CallArguments<&str>) { 57 for y in x.positional.iter() { 58 self.collect_inline_expression(y); 59 } 60 for y in x.named.iter() { 61 self.collect_named_argument(y); 62 } 63 } 64 65 fn collect_variant(&mut self, x: &ast::Variant<&str>) { 66 self.collect_pattern(&x.value); 67 } 68 69 fn collect_expression(&mut self, x: &ast::Expression<&str>) { 70 match x { 71 ast::Expression::Select { selector, variants } => { 72 self.collect_inline_expression(selector); 73 for y in variants.iter() { 74 self.collect_variant(y); 75 } 76 } 77 ast::Expression::Inline(i) => { 78 self.collect_inline_expression(i); 79 } 80 } 81 } 82 83 fn collect_pattern_element(&mut self, x: &ast::PatternElement<&str>) { 84 match x { 85 ast::PatternElement::TextElement { value } => { 86 self.elements.push(TextElementInfo { 87 id: self 88 .current_id 89 .as_ref() 90 .map_or_else(nsCString::new, nsCString::from), 91 attr: self 92 .current_attr 93 .as_ref() 94 .map_or_else(nsCString::new, nsCString::from), 95 text: nsCString::from(*value), 96 }); 97 } 98 ast::PatternElement::Placeable { expression } => { 99 self.collect_expression(expression); 100 } 101 } 102 } 103 104 fn collect_pattern(&mut self, x: &ast::Pattern<&str>) { 105 for y in x.elements.iter() { 106 self.collect_pattern_element(y); 107 } 108 } 109 110 fn collect_attribute(&mut self, x: &ast::Attribute<&str>) { 111 self.current_attr = Some(x.id.name.to_string()); 112 113 self.collect_pattern(&x.value); 114 } 115 116 fn collect_message(&mut self, x: &ast::Message<&str>) { 117 self.current_id = Some(x.id.name.to_string()); 118 self.current_attr = None; 119 120 if let Some(ref y) = x.value { 121 self.collect_pattern(y); 122 } 123 for y in x.attributes.iter() { 124 self.collect_attribute(y); 125 } 126 } 127 128 fn collect_term(&mut self, x: &ast::Term<&str>) { 129 self.current_id = Some(x.id.name.to_string()); 130 self.current_attr = None; 131 132 self.collect_pattern(&x.value); 133 for y in x.attributes.iter() { 134 self.collect_attribute(y); 135 } 136 } 137 138 pub fn collect_entry(&mut self, x: &ast::Entry<&str>) { 139 match x { 140 ast::Entry::Message(m) => { 141 self.collect_message(m); 142 } 143 ast::Entry::Term(t) => { 144 self.collect_term(t); 145 } 146 ast::Entry::Comment(_) => {} 147 ast::Entry::GroupComment(_) => {} 148 ast::Entry::ResourceComment(_) => {} 149 ast::Entry::Junk { .. } => {} 150 } 151 } 152 } 153 154 #[no_mangle] 155 pub extern "C" fn fluent_resource_get_text_elements( 156 res: &FluentResource, 157 elements: &mut ThinVec<TextElementInfo>, 158 ) { 159 let mut collector = TextElementsCollector::new(elements); 160 161 for entry in res.entries() { 162 collector.collect_entry(entry); 163 } 164 }