fable_data/script/
decode.rs

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        // println!("expression {:?}", String::from_utf8(input[..10].to_vec()));
65        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        // println!("expression {:?}", expression);
79        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            // let field_name = match field.reference {
155            //     ScriptReference::Name(x) => x,
156            //     ScriptReference::Property(_) => return Err(nom::Err::Error(Error::Fable(ErrorKind::InvalidInstruction))),
157            // };
158
159            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        // Searches for a line ending then backtracks before it.
391
392        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        // A variation of `ScriptExpression::decode_expression` that omits `ScriptExpression::decode_binary_op_expression`.
433        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_binary_op_expression,
443            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}