1 use super::errors::{ErrorKind, ParserError};
2 use super::{core::Parser, core::Result, slice::Slice};
3 use crate::ast;
4 
5 impl<'s, S> Parser<S>
6 where
7     S: Slice<'s>,
8 {
get_expression(&mut self) -> Result<ast::Expression<S>>9     pub(super) fn get_expression(&mut self) -> Result<ast::Expression<S>> {
10         let exp = self.get_inline_expression(false)?;
11 
12         self.skip_blank();
13 
14         if !self.is_current_byte(b'-') || !self.is_byte_at(b'>', self.ptr + 1) {
15             if let ast::InlineExpression::TermReference { ref attribute, .. } = exp {
16                 if attribute.is_some() {
17                     return error!(ErrorKind::TermAttributeAsPlaceable, self.ptr);
18                 }
19             }
20             return Ok(ast::Expression::Inline(exp));
21         }
22 
23         match exp {
24             ast::InlineExpression::MessageReference { ref attribute, .. } => {
25                 if attribute.is_none() {
26                     return error!(ErrorKind::MessageReferenceAsSelector, self.ptr);
27                 } else {
28                     return error!(ErrorKind::MessageAttributeAsSelector, self.ptr);
29                 }
30             }
31             ast::InlineExpression::TermReference { ref attribute, .. } => {
32                 if attribute.is_none() {
33                     return error!(ErrorKind::TermReferenceAsSelector, self.ptr);
34                 }
35             }
36             ast::InlineExpression::StringLiteral { .. }
37             | ast::InlineExpression::NumberLiteral { .. }
38             | ast::InlineExpression::VariableReference { .. }
39             | ast::InlineExpression::FunctionReference { .. } => {}
40             _ => {
41                 return error!(ErrorKind::ExpectedSimpleExpressionAsSelector, self.ptr);
42             }
43         };
44 
45         self.ptr += 2; // ->
46 
47         self.skip_blank_inline();
48         if !self.skip_eol() {
49             return error!(
50                 ErrorKind::ExpectedCharRange {
51                     range: "\n | \r\n".to_string()
52                 },
53                 self.ptr
54             );
55         }
56         self.skip_blank();
57 
58         let variants = self.get_variants()?;
59 
60         Ok(ast::Expression::Select {
61             selector: exp,
62             variants,
63         })
64     }
65 
get_inline_expression( &mut self, only_literal: bool, ) -> Result<ast::InlineExpression<S>>66     pub(super) fn get_inline_expression(
67         &mut self,
68         only_literal: bool,
69     ) -> Result<ast::InlineExpression<S>> {
70         match get_current_byte!(self) {
71             Some(b'"') => {
72                 self.ptr += 1; // "
73                 let start = self.ptr;
74                 while let Some(b) = get_current_byte!(self) {
75                     match b {
76                         b'\\' => match get_byte!(self, self.ptr + 1) {
77                             Some(b'\\') | Some(b'{') | Some(b'"') => self.ptr += 2,
78                             Some(b'u') => {
79                                 self.ptr += 2;
80                                 self.skip_unicode_escape_sequence(4)?;
81                             }
82                             Some(b'U') => {
83                                 self.ptr += 2;
84                                 self.skip_unicode_escape_sequence(6)?;
85                             }
86                             b => {
87                                 let seq = b.unwrap_or(&b' ').to_string();
88                                 return error!(ErrorKind::UnknownEscapeSequence(seq), self.ptr);
89                             }
90                         },
91                         b'"' => {
92                             break;
93                         }
94                         b'\n' => {
95                             return error!(ErrorKind::UnterminatedStringLiteral, self.ptr);
96                         }
97                         _ => self.ptr += 1,
98                     }
99                 }
100 
101                 self.expect_byte(b'"')?;
102                 let slice = self.source.slice(start..self.ptr - 1);
103                 Ok(ast::InlineExpression::StringLiteral { value: slice })
104             }
105             Some(b) if b.is_ascii_digit() => {
106                 let num = self.get_number_literal()?;
107                 Ok(ast::InlineExpression::NumberLiteral { value: num })
108             }
109             Some(b'-') if !only_literal => {
110                 self.ptr += 1; // -
111                 if self.is_identifier_start() {
112                     self.ptr += 1;
113                     let id = self.get_identifier_unchecked();
114                     let attribute = self.get_attribute_accessor()?;
115                     let arguments = self.get_call_arguments()?;
116                     Ok(ast::InlineExpression::TermReference {
117                         id,
118                         attribute,
119                         arguments,
120                     })
121                 } else {
122                     self.ptr -= 1;
123                     let num = self.get_number_literal()?;
124                     Ok(ast::InlineExpression::NumberLiteral { value: num })
125                 }
126             }
127             Some(b'$') if !only_literal => {
128                 self.ptr += 1; // $
129                 let id = self.get_identifier()?;
130                 Ok(ast::InlineExpression::VariableReference { id })
131             }
132             Some(b) if b.is_ascii_alphabetic() => {
133                 self.ptr += 1;
134                 let id = self.get_identifier_unchecked();
135                 let arguments = self.get_call_arguments()?;
136                 if let Some(arguments) = arguments {
137                     if !Self::is_callee(&id.name) {
138                         return error!(ErrorKind::ForbiddenCallee, self.ptr);
139                     }
140 
141                     Ok(ast::InlineExpression::FunctionReference { id, arguments })
142                 } else {
143                     let attribute = self.get_attribute_accessor()?;
144                     Ok(ast::InlineExpression::MessageReference { id, attribute })
145                 }
146             }
147             Some(b'{') if !only_literal => {
148                 self.ptr += 1; // {
149                 let exp = self.get_placeable()?;
150                 Ok(ast::InlineExpression::Placeable {
151                     expression: Box::new(exp),
152                 })
153             }
154             _ if only_literal => error!(ErrorKind::ExpectedLiteral, self.ptr),
155             _ => error!(ErrorKind::ExpectedInlineExpression, self.ptr),
156         }
157     }
158 
get_call_arguments(&mut self) -> Result<Option<ast::CallArguments<S>>>159     pub fn get_call_arguments(&mut self) -> Result<Option<ast::CallArguments<S>>> {
160         self.skip_blank();
161         if !self.take_byte_if(b'(') {
162             return Ok(None);
163         }
164 
165         let mut positional = vec![];
166         let mut named = vec![];
167         let mut argument_names = vec![];
168 
169         self.skip_blank();
170 
171         while self.ptr < self.length {
172             if self.is_current_byte(b')') {
173                 break;
174             }
175 
176             let expr = self.get_inline_expression(false)?;
177 
178             if let ast::InlineExpression::MessageReference {
179                 ref id,
180                 attribute: None,
181             } = expr
182             {
183                 self.skip_blank();
184                 if self.is_current_byte(b':') {
185                     if argument_names.contains(&id.name) {
186                         return error!(
187                             ErrorKind::DuplicatedNamedArgument(id.name.as_ref().to_owned()),
188                             self.ptr
189                         );
190                     }
191                     self.ptr += 1;
192                     self.skip_blank();
193                     let val = self.get_inline_expression(true)?;
194 
195                     argument_names.push(id.name.clone());
196                     named.push(ast::NamedArgument {
197                         name: ast::Identifier {
198                             name: id.name.clone(),
199                         },
200                         value: val,
201                     });
202                 } else {
203                     if !argument_names.is_empty() {
204                         return error!(ErrorKind::PositionalArgumentFollowsNamed, self.ptr);
205                     }
206                     positional.push(expr);
207                 }
208             } else {
209                 if !argument_names.is_empty() {
210                     return error!(ErrorKind::PositionalArgumentFollowsNamed, self.ptr);
211                 }
212                 positional.push(expr);
213             }
214 
215             self.skip_blank();
216             self.take_byte_if(b',');
217             self.skip_blank();
218         }
219 
220         self.expect_byte(b')')?;
221 
222         Ok(Some(ast::CallArguments { positional, named }))
223     }
224 }
225