1use crate::nom::{
2 IResult,
3 Err,
4 digit1,
5 line_ending,
6 one_of,
7 space0,
8 alphanumeric1,
9 multispace0,
10 is_digit,
11 is_alphabetic,
12 opt,
13 tag,
14 take_while1,
15 take_until,
16 escaped,
17 is_not,
18 alt,
19 many0,
20 many1,
21 tuple,
22};
23
24use crate::{
25 Error,
26 ErrorKind,
27 ScriptExpression,
28 ScriptField,
29 ScriptReference,
30 ScriptAccessor,
31 ScriptAccessorPath,
32 ScriptCall,
33 ScriptMarkup,
34 ScriptComment,
35 ScriptBinaryOp,
36 ScriptBinaryOpKind,
37 ScriptValue,
38 decode_bytes_as_utf8_string,
39 recover,
40};
41
42impl ScriptExpression {
43 pub fn decode_expression_list(input: &[u8]) -> IResult<&[u8], Vec<ScriptExpression>, Error> {
44 many0(Self::decode_expression_list_item)(input)
45 }
46
47 pub fn decode_expression_list_item(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
48 let rest = &input;
49 let (rest, expression) = recover(Self::decode_expression, input)(rest)?;
50 let (rest, expression) = match expression {
51 ScriptExpression::ScriptMarkup(i) => (rest, ScriptExpression::ScriptMarkup(i)),
52 ScriptExpression::ScriptComment(i) => (rest, ScriptExpression::ScriptComment(i)),
53 expression => {
54 let (rest, _) = recover(space0, input)(rest)?;
55 let (rest, _) = recover(tag(";"), input)(rest)?;
56 (rest, expression)
57 }
58 };
59 Ok((rest, expression))
60 }
61
62 pub fn decode_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
63 let (input, _) = multispace0(input)?;
64 let (input, expression) = alt((
66 Self::decode_comment_expression,
67 Self::decode_markup_expression,
68 Self::decode_bool_literal_expression,
69 Self::decode_float_literal_expression,
70 Self::decode_integer_literal_expression,
71 Self::decode_big_integer_literal_expression,
72 Self::decode_string_literal_expression,
73 Self::decode_call_expression,
74 Self::decode_binary_op_expression,
75 Self::decode_field_expression,
76 Self::decode_name_expression,
77 ))(input)?;
78 let (input, _) = multispace0(input)?;
80 Ok((input, expression))
81 }
82
83 pub fn decode_field_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
84 let (input, field) = ScriptField::decode_field(input)?;
85 Ok((input, ScriptExpression::ScriptField(field)))
86 }
87
88 pub fn decode_markup_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
89 let (input, markup) = ScriptMarkup::decode_markup(input)?;
90 Ok((input, ScriptExpression::ScriptMarkup(markup)))
91 }
92
93 pub fn decode_comment_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
94 let (input, comment) = ScriptComment::decode_comment(input)?;
95 Ok((input, ScriptExpression::ScriptComment(comment)))
96 }
97
98 pub fn decode_binary_op_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
99 let (input, binary_op) = ScriptBinaryOp::decode_binary_op(input)?;
100 Ok((input, ScriptExpression::ScriptBinaryOp(binary_op)))
101 }
102
103 pub fn decode_call_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
104 let (input, call) = ScriptCall::decode_call(input)?;
105 Ok((input, ScriptExpression::ScriptCall(call)))
106 }
107
108 pub fn decode_bool_literal_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
109 let (input, value) = ScriptValue::decode_bool_literal(input)?;
110 Ok((input, ScriptExpression::ScriptValue(value)))
111 }
112
113 pub fn decode_float_literal_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
114 let (input, value) = ScriptValue::decode_float_literal(input)?;
115 Ok((input, ScriptExpression::ScriptValue(value)))
116 }
117
118 pub fn decode_integer_literal_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
119 let (input, value) = ScriptValue::decode_integer_literal(input)?;
120 Ok((input, ScriptExpression::ScriptValue(value)))
121 }
122
123 pub fn decode_big_integer_literal_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
124 let (input, value) = ScriptValue::decode_big_integer_literal(input)?;
125 Ok((input, ScriptExpression::ScriptValue(value)))
126 }
127
128 pub fn decode_string_literal_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
129 let (input, value) = ScriptValue::decode_string_literal(input)?;
130 Ok((input, ScriptExpression::ScriptValue(value)))
131 }
132
133 pub fn decode_name_expression(input: &[u8]) -> IResult<&[u8], ScriptExpression, Error> {
134 let (input, value) = ScriptValue::decode_name(input)?;
135 Ok((input, ScriptExpression::ScriptValue(value)))
136 }
137}
138
139impl ScriptField {
140 pub fn decode_field(input: &[u8]) -> IResult<&[u8], ScriptField, Error> {
141 let (input, _line_ending) = many0(line_ending)(input)?;
142 let (input, reference) = ScriptReference::decode_reference(input)?;
143 let (input, _space) = space0(input)?;
144 let (input, expression) = ScriptExpression::decode_expression(input)?;
145 let (input, _line_ending) = multispace0(input)?;
146
147 Ok((input, ScriptField { reference: reference, value: Box::new(expression) }))
148 }
149
150 pub fn decode_field_named(name: &'static str) -> impl Fn(&[u8]) -> IResult<&[u8], ScriptField, Error> {
151 move |input: &[u8]| {
152 let (input, field) = Self::decode_field(input)?;
153
154 if field.reference != ScriptReference::Name(name.to_string()) {
160 return Err(nom::Err::Error(Error::Fable(ErrorKind::InvalidTagName)));
161 }
162
163 Ok((input, field))
164 }
165 }
166}
167
168impl ScriptReference {
169 pub fn decode_reference(input: &[u8]) -> IResult<&[u8], ScriptReference, Error> {
170 alt((
171 Self::decode_reference_accessor,
172 Self::decode_reference_name,
173 ))(input)
174 }
175
176 pub fn decode_reference_name(input: &[u8]) -> IResult<&[u8], ScriptReference, Error> {
177 let (input, name) = Self::decode_key_name(input)?;
178 Ok((input, ScriptReference::Name(name)))
179 }
180
181 pub fn decode_reference_accessor(input: &[u8]) -> IResult<&[u8], ScriptReference, Error> {
182 let (input, name) = Self::decode_key_name(input)?;
183 let (input, path) = many1(Self::decode_accessor_path)(input)?;
184 Ok((input, ScriptReference::ScriptAccessor(ScriptAccessor { name: name, path: path })))
185 }
186
187 pub fn decode_accessor_path(input: &[u8]) -> IResult<&[u8], ScriptAccessorPath, Error> {
188 let (input, accessor) = one_of(".[")(input)?;
189
190 match accessor {
191 '.' => Self::decode_accessor_path_name(input),
192 '[' => Self::decode_accessor_path_expression(input),
193 _ => Err(Err::Error(Error::Fable(ErrorKind::InvalidScriptProperty))),
194 }
195 }
196
197 pub fn decode_accessor_path_name(input: &[u8]) -> IResult<&[u8], ScriptAccessorPath, Error> {
198 let (input, name) = Self::decode_key_name(input)?;
199 Ok((input, ScriptAccessorPath::Name(name)))
200 }
201
202 pub fn decode_accessor_path_expression(input: &[u8]) -> IResult<&[u8], ScriptAccessorPath, Error> {
203 let (input, expression) = ScriptExpression::decode_expression(input)?;
204 let (input, _) = multispace0(input)?;
205 let (input, _) = tag("]")(input)?;
206 Ok((input, ScriptAccessorPath::Expression(expression)))
207 }
208
209 pub fn decode_key_name(input: &[u8]) -> IResult<&[u8], String, Error> {
210 let (input, key) = take_while1(|x| is_alphabetic(x) || is_digit(x) || x == 0x5f)(input)?;
211 let (_, key) = decode_bytes_as_utf8_string(key)?;
212 Ok((input, key))
213 }
214}
215
216impl ScriptValue {
217 pub fn decode_bool_literal(input: &[u8]) -> IResult<&[u8], ScriptValue, Error> {
218 let (input, value) = alt((tag("TRUE"), tag("FALSE")))(input)?;
219 let value = match value {
220 b"TRUE" => true,
221 b"FALSE" => false,
222 _ => return Err(Err::Error(Error::Fable(ErrorKind::InvalidScriptValue)))
223 };
224 Ok((input, ScriptValue::BoolLiteral(value)))
225 }
226
227 pub fn decode_float_literal(input: &[u8]) -> IResult<&[u8], ScriptValue, Error> {
228 let (input, sign) = opt(alt((tag("-"), tag("+"))))(input)?;
229 let (input, (integer_part, dot, fractional_part)) = tuple(( digit1, tag("."), digit1 ))(input)?;
230
231 let value = [ integer_part, dot, fractional_part ].concat();
232
233 let value = if let Some(sign) = sign {
234 [ sign, &value ].concat()
235 } else {
236 value.to_vec()
237 };
238
239 let value = match String::from_utf8(value.to_vec()) {
240 Ok(value) => value,
241 Err(_error) => return Err(nom::Err::Error(Error::Fable(ErrorKind::InvalidScriptValue))),
242 };
243
244 let value = match value.parse::<f32>() {
245 Ok(value) => value,
246 Err(_error) => return Err(nom::Err::Error(Error::Fable(ErrorKind::InvalidScriptValue))),
247 };
248
249 Ok((input, ScriptValue::FloatLiteral(value)))
250 }
251
252 pub fn decode_integer_literal(input: &[u8]) -> IResult<&[u8], ScriptValue, Error> {
253 let (input, sign) = opt(alt((tag("-"), tag("+"))))(input)?;
254 let (input, value) = digit1(input)?;
255
256 let value = if let Some(sign) = sign {
257 [ sign, value ].concat()
258 } else {
259 value.to_vec()
260 };
261
262 let value = match String::from_utf8(value) {
263 Ok(value) => value,
264 Err(_error) => return Err(nom::Err::Error(Error::Fable(ErrorKind::InvalidScriptValue))),
265 };
266
267 let value = match value.parse::<i32>() {
268 Ok(value) => value,
269 Err(_error) => return Err(nom::Err::Error(Error::Fable(ErrorKind::InvalidScriptValue))),
270 };
271
272 Ok((input, ScriptValue::IntegerLiteral(value)))
273 }
274
275 pub fn decode_big_integer_literal(input: &[u8]) -> IResult<&[u8], ScriptValue, Error> {
276 let (input, value) = digit1(input)?;
277
278 let value = match String::from_utf8(value.to_vec()) {
279 Ok(value) => value,
280 Err(_error) => return Err(nom::Err::Error(Error::Fable(ErrorKind::InvalidScriptValue))),
281 };
282
283 let value = match value.parse::<u64>() {
284 Ok(value) => value,
285 Err(_error) => return Err(nom::Err::Error(Error::Fable(ErrorKind::InvalidScriptValue))),
286 };
287
288 Ok((input, ScriptValue::BigIntegerLiteral(value)))
289 }
290
291 pub fn decode_string_literal(input: &[u8]) -> IResult<&[u8], ScriptValue, Error> {
292 let (input, _opener) = tag("\"")(input)?;
293 let (input, value) = opt(escaped(is_not("\""), '\\', one_of("\"\\")))(input)?;
294 let (input, _closer) = tag("\"")(input)?;
295
296 let value = match value {
297 Some(value) =>
298 match String::from_utf8(value.to_vec()) {
299 Ok(value) => value,
300 Err(_error) => return Err(nom::Err::Error(Error::Fable(ErrorKind::InvalidScriptValue))),
301 },
302 None => "".to_string(),
303 };
304
305 Ok((input, ScriptValue::StringLiteral(value)))
306 }
307
308 pub fn decode_name(input: &[u8]) -> IResult<&[u8], ScriptValue, Error> {
309 let (input, name) = take_while1(|x| (is_alphabetic(x) || is_digit(x) || x == 0x5f || x == 0x20))(input)?;
310
311 let name = match String::from_utf8(name.to_vec()) {
312 Ok(value) => value,
313 Err(_error) => return Err(nom::Err::Error(Error::Fable(ErrorKind::InvalidScriptValue))),
314 };
315
316 Ok((input, ScriptValue::Name(name)))
317 }
318}
319
320impl ScriptCall {
321 pub fn decode_call(input: &[u8]) -> IResult<&[u8], ScriptCall, Error> {
322 let (input, reference) = ScriptReference::decode_reference(input)?;
323 let (input, _) = tag("(")(input)?;
324
325 let mut arguments = Vec::new();
326 let mut last_input = input;
327
328 loop {
329 let (input, argument) = opt(ScriptExpression::decode_expression)(last_input)?;
330
331 if let Some(argument) = argument {
332 arguments.push(argument);
333
334 let (input, next) = opt(tag(","))(input)?;
335
336 if next.is_some() {
337 last_input = input;
338 continue
339 }
340 }
341
342 let (input, _) = tag(")")(input)?;
343 let (input, _) = space0(input)?;
344
345 last_input = input;
346
347 break
348 }
349
350 let input = last_input;
351
352 Ok((input, ScriptCall { reference: reference, arguments: arguments }))
353 }
354}
355
356impl ScriptMarkup {
357 pub fn decode_markup(input: &[u8]) -> IResult<&[u8], ScriptMarkup, Error> {
358 let (input, _) = space0(input)?;
359 let (input, _) = tag("<")(input)?;
360 let (input, name) = alphanumeric1(input)?;
361
362 let name = match String::from_utf8(name.to_vec()) {
363 Ok(s) => s,
364 _ => return Err(nom::Err::Error(Error::Utf8Error))
365 };
366
367 let (input, _) = tag(">")(input)?;
368
369 let (input, body) = ScriptExpression::decode_expression_list(input)?;
370
371 let (input, _) = multispace0(input)?;
372 let closer = &format!("<\\{}>", name)[..];
373 let (input, _) = tag(closer)(input)?;
374
375 Ok((input, ScriptMarkup { name: name, body: body }))
376 }
377}
378
379impl ScriptComment {
380 pub fn decode_comment(input: &[u8]) -> IResult<&[u8], ScriptComment, Error> {
381 alt((
382 Self::decode_line_comment,
383 Self::decode_block_comment
384 ))(input)
385 }
386
387 pub fn decode_line_comment(input: &[u8]) -> IResult<&[u8], ScriptComment, Error> {
388 let (input, _comment_symbol) = tag("//")(input)?;
389
390 let mut ending = 0;
393
394 loop {
395 if input[ending] == b'\n' {
396 if input[ending - 1] == b'\r' {
397 ending -= 1;
398 }
399 break
400 }
401 ending += 1;
402 }
403
404 let comment = &input[..ending];
405
406 let comment = match String::from_utf8(comment.to_vec()) {
407 Ok(s) => s,
408 _ => return Err(nom::Err::Error(Error::Utf8Error))
409 };
410
411 let input = &input[ending..];
412
413 Ok((input, ScriptComment::Line(comment)))
414 }
415
416 pub fn decode_block_comment(input: &[u8]) -> IResult<&[u8], ScriptComment, Error> {
417 let (input, _) = tag("/*")(input)?;
418 let (input, comment) = take_until("*/")(input)?;
419 let input = &input[2..];
420
421 let comment = match String::from_utf8(comment.to_vec()) {
422 Ok(s) => s,
423 _ => return Err(nom::Err::Error(Error::Utf8Error))
424 };
425
426 Ok((input, ScriptComment::Block(comment)))
427 }
428}
429
430impl ScriptBinaryOp {
431 pub fn decode_binary_op(input: &[u8]) -> IResult<&[u8], ScriptBinaryOp, Error> {
432 let (input, lhs) = alt((
434 ScriptExpression::decode_comment_expression,
435 ScriptExpression::decode_markup_expression,
436 ScriptExpression::decode_bool_literal_expression,
437 ScriptExpression::decode_float_literal_expression,
438 ScriptExpression::decode_integer_literal_expression,
439 ScriptExpression::decode_big_integer_literal_expression,
440 ScriptExpression::decode_string_literal_expression,
441 ScriptExpression::decode_call_expression,
442 ScriptExpression::decode_field_expression,
444 ScriptExpression::decode_name_expression,
445 ))(input)?;
446 let (input, _) = space0(input)?;
447 let (input, kind) = one_of("+-*/|")(input)?;
448 let kind = match kind {
449 '+' => ScriptBinaryOpKind::Add,
450 '-' => ScriptBinaryOpKind::Subtract,
451 '*' => ScriptBinaryOpKind::Multiply,
452 '/' => ScriptBinaryOpKind::Divide,
453 '|' => ScriptBinaryOpKind::BitOr,
454 _ => return Err(nom::Err::Error(Error::Fable(ErrorKind::InvalidScriptBinaryOp)))
455 };
456 let (input, _) = space0(input)?;
457 let (input, rhs) = ScriptExpression::decode_expression(input)?;
458 Ok((input, ScriptBinaryOp { kind: kind, lhs: Box::new(lhs), rhs: Box::new(rhs) }))
459 }
460}