1use super::errors::{ErrorKind, ParserError};
2use super::{core::Parser, core::Result, slice::Slice};
3use crate::ast;
4
5impl<'s, S> Parser<S>
6where
7 S: Slice<'s>,
8{
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
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
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