bind/parser/
bind_library.rs

1// Copyright 2019 The Fuchsia Authors. All rights reserved.
2// Use of this source code is governed by a BSD-style license that can be
3// found in the LICENSE file.
4
5use crate::parser::common::{
6    bool_literal, compound_identifier, identifier, many_until_eof, map_err, numeric_literal,
7    string_literal, using_list, ws, BindParserError, CompoundIdentifier, Include, NomSpan,
8};
9use nom::branch::alt;
10use nom::bytes::complete::{tag, take_until};
11use nom::combinator::{map, opt, value};
12use nom::multi::separated_list1;
13use nom::sequence::{delimited, separated_pair, terminated};
14use nom::{IResult, Parser};
15
16#[derive(Debug, PartialEq)]
17pub struct Ast {
18    pub name: CompoundIdentifier,
19    pub using: Vec<Include>,
20    pub declarations: Vec<Declaration>,
21}
22
23#[derive(Clone, Debug, PartialEq)]
24pub struct Declaration {
25    pub identifier: CompoundIdentifier,
26    pub value_type: ValueType,
27    pub extends: bool,
28    pub values: Vec<Value>,
29}
30
31#[derive(Debug, Copy, Clone, PartialEq, Eq, Hash, serde::Deserialize, serde::Serialize)]
32pub enum ValueType {
33    Number,
34    Str,
35    Bool,
36    Enum,
37}
38
39#[derive(Clone, Debug, PartialEq)]
40pub enum Value {
41    Number(String, u64),
42    Str(String, String),
43    Bool(String, bool),
44    Enum(String),
45}
46
47impl TryFrom<&str> for Ast {
48    type Error = BindParserError;
49
50    fn try_from(input: &str) -> Result<Self, Self::Error> {
51        match library(NomSpan::new(input)) {
52            Ok((_, ast)) => Ok(ast),
53            Err(nom::Err::Error(e)) => Err(e),
54            Err(nom::Err::Failure(e)) => Err(e),
55            Err(nom::Err::Incomplete(_)) => {
56                unreachable!("Parser should never generate Incomplete errors")
57            }
58        }
59    }
60}
61
62impl Value {
63    pub fn identifier(&self) -> &str {
64        match self {
65            Value::Number(identifier, _)
66            | Value::Str(identifier, _)
67            | Value::Bool(identifier, _)
68            | Value::Enum(identifier) => &identifier,
69        }
70    }
71}
72
73fn keyword_extend(input: NomSpan) -> IResult<NomSpan, NomSpan, BindParserError> {
74    ws(tag("extend")).parse(input)
75}
76
77fn keyword_uint(input: NomSpan) -> IResult<NomSpan, ValueType, BindParserError> {
78    value(ValueType::Number, ws(map_err(tag("uint"), BindParserError::Type))).parse(input)
79}
80
81fn keyword_string(input: NomSpan) -> IResult<NomSpan, ValueType, BindParserError> {
82    value(ValueType::Str, ws(map_err(tag("string"), BindParserError::Type))).parse(input)
83}
84
85fn keyword_bool(input: NomSpan) -> IResult<NomSpan, ValueType, BindParserError> {
86    value(ValueType::Bool, ws(map_err(tag("bool"), BindParserError::Type))).parse(input)
87}
88
89fn keyword_enum(input: NomSpan) -> IResult<NomSpan, ValueType, BindParserError> {
90    value(ValueType::Enum, ws(map_err(tag("enum"), BindParserError::Type))).parse(input)
91}
92
93fn value_list<'a, O, F>(
94    mut f: F,
95) -> impl Parser<NomSpan<'a>, Output = Vec<O>, Error = BindParserError>
96where
97    F: Parser<NomSpan<'a>, Output = O, Error = BindParserError>,
98{
99    move |input: NomSpan<'a>| {
100        let separator = || ws(map_err(tag(","), BindParserError::ListSeparator));
101        let values = separated_list1(separator(), |s| f.parse(s));
102
103        // Lists may optionally be terminated by an additional trailing separator.
104        let values = terminated(values, opt(separator()));
105
106        // First consume all input until ';'. This simplifies the error handling since a semicolon
107        // is mandatory, but a list of values is optional.
108        let (input, vals_input) =
109            map_err(terminated(take_until(";"), tag(";")), BindParserError::Semicolon)
110                .parse(input)?;
111
112        if vals_input.fragment().is_empty() {
113            return Ok((input, Vec::new()));
114        }
115
116        let list_start = map_err(tag("{"), BindParserError::ListStart);
117        let list_end = map_err(tag("}"), BindParserError::ListEnd);
118        let (_, result) = delimited(ws(list_start), ws(values), ws(list_end)).parse(vals_input)?;
119
120        Ok((input, result))
121    }
122}
123
124fn number_value_list(input: NomSpan) -> IResult<NomSpan, Vec<Value>, BindParserError> {
125    let token = map_err(tag("="), BindParserError::Assignment);
126    let value = separated_pair(ws(identifier), ws(token), ws(numeric_literal));
127    value_list(map(value, |(ident, val)| Value::Number(ident, val))).parse(input)
128}
129
130fn string_value_list(input: NomSpan) -> IResult<NomSpan, Vec<Value>, BindParserError> {
131    let token = map_err(tag("="), BindParserError::Assignment);
132    let value = separated_pair(ws(identifier), ws(token), ws(string_literal));
133    value_list(map(value, |(ident, val)| Value::Str(ident, val))).parse(input)
134}
135
136fn bool_value_list(input: NomSpan) -> IResult<NomSpan, Vec<Value>, BindParserError> {
137    let token = map_err(tag("="), BindParserError::Assignment);
138    let value = separated_pair(ws(identifier), ws(token), ws(bool_literal));
139    value_list(map(value, |(ident, val)| Value::Bool(ident, val))).parse(input)
140}
141
142fn enum_value_list(input: NomSpan) -> IResult<NomSpan, Vec<Value>, BindParserError> {
143    value_list(map(ws(identifier), Value::Enum)).parse(input)
144}
145
146fn declaration(input: NomSpan) -> IResult<NomSpan, Declaration, BindParserError> {
147    let (input, extends) = opt(keyword_extend).parse(input)?;
148
149    let (input, value_type) =
150        alt((keyword_uint, keyword_string, keyword_bool, keyword_enum)).parse(input)?;
151
152    let (input, identifier) = ws(compound_identifier).parse(input)?;
153
154    let value_parser = match value_type {
155        ValueType::Number => number_value_list,
156        ValueType::Str => string_value_list,
157        ValueType::Bool => bool_value_list,
158        ValueType::Enum => enum_value_list,
159    };
160
161    let (input, vals) = value_parser(input)?;
162
163    Ok((input, Declaration { identifier, value_type, extends: extends.is_some(), values: vals }))
164}
165
166fn library_name(input: NomSpan) -> IResult<NomSpan, CompoundIdentifier, BindParserError> {
167    let keyword = ws(map_err(tag("library"), BindParserError::LibraryKeyword));
168    let terminator = ws(map_err(tag(";"), BindParserError::Semicolon));
169    delimited(keyword, ws(compound_identifier), terminator).parse(input)
170}
171
172fn library(input: NomSpan) -> IResult<NomSpan, Ast, BindParserError> {
173    map(
174        (ws(library_name), ws(using_list), many_until_eof(ws(declaration))),
175        |(name, using, declarations)| Ast { name, using, declarations },
176    )
177    .parse(input)
178}
179
180#[cfg(test)]
181mod test {
182    use super::*;
183    use crate::make_identifier;
184    use crate::parser::common::test::check_result;
185
186    mod number_value_lists {
187        use super::*;
188
189        #[test]
190        fn single_value() {
191            check_result(
192                number_value_list(NomSpan::new("{abc = 123};")),
193                "",
194                vec![Value::Number("abc".to_string(), 123)],
195            );
196        }
197
198        #[test]
199        fn multiple_values() {
200            // Matches multiple string values.
201            check_result(
202                number_value_list(NomSpan::new("{abc = 123, DEF = 456};")),
203                "",
204                vec![Value::Number("abc".to_string(), 123), Value::Number("DEF".to_string(), 456)],
205            );
206            check_result(
207                number_value_list(NomSpan::new("{abc = 123, DEF = 456, ghi = 0xabc};")),
208                "",
209                vec![
210                    Value::Number("abc".to_string(), 123),
211                    Value::Number("DEF".to_string(), 456),
212                    Value::Number("ghi".to_string(), 0xabc),
213                ],
214            );
215        }
216
217        #[test]
218        fn whitespace() {
219            // Handles whitespace.
220            check_result(
221                number_value_list(NomSpan::new("{  abc=123,\n\tDEF\t =  0xdef\n};")),
222                "",
223                vec![
224                    Value::Number("abc".to_string(), 123),
225                    Value::Number("DEF".to_string(), 0xdef),
226                ],
227            );
228        }
229
230        #[test]
231        fn invalid_values() {
232            // Does not match non-number values.
233            assert_eq!(
234                number_value_list(NomSpan::new("{abc = \"string\"};")),
235                Err(nom::Err::Error(BindParserError::NumericLiteral("\"string\"}".to_string())))
236            );
237            assert_eq!(
238                number_value_list(NomSpan::new("{abc = true};")),
239                Err(nom::Err::Error(BindParserError::NumericLiteral("true}".to_string())))
240            );
241        }
242
243        #[test]
244        fn trailing_comma() {
245            // Matches trailing ','.
246            check_result(
247                number_value_list(NomSpan::new("{abc = 123,};")),
248                "",
249                vec![Value::Number("abc".to_string(), 123)],
250            );
251        }
252
253        #[test]
254        fn empty_list() {
255            // Does not match empty list.
256            assert_eq!(
257                number_value_list(NomSpan::new("{};")),
258                Err(nom::Err::Error(BindParserError::Identifier("}".to_string())))
259            );
260        }
261
262        #[test]
263        fn invalid_list() {
264            // Must have list start and end braces.
265            assert_eq!(
266                number_value_list(NomSpan::new("abc = 123};")),
267                Err(nom::Err::Error(BindParserError::ListStart("abc = 123}".to_string())))
268            );
269            assert_eq!(
270                number_value_list(NomSpan::new("{abc = 123;")),
271                Err(nom::Err::Error(BindParserError::ListEnd("".to_string())))
272            );
273
274            // Must have assignment operator.
275            assert_eq!(
276                number_value_list(NomSpan::new("{abc 123};")),
277                Err(nom::Err::Error(BindParserError::Assignment("123}".to_string())))
278            );
279        }
280
281        #[test]
282        fn no_list() {
283            // Matches no list.
284            check_result(number_value_list(NomSpan::new(";")), "", vec![]);
285        }
286    }
287
288    mod string_value_lists {
289        use super::*;
290
291        #[test]
292        fn single_value() {
293            check_result(
294                string_value_list(NomSpan::new(r#"{abc = "xyz"};"#)),
295                "",
296                vec![Value::Str("abc".to_string(), "xyz".to_string())],
297            );
298        }
299
300        #[test]
301        fn multiple_values() {
302            // Matches multiple string values.
303            check_result(
304                string_value_list(NomSpan::new(r#"{abc = "xyz", DEF = "UVW"};"#)),
305                "",
306                vec![
307                    Value::Str("abc".to_string(), "xyz".to_string()),
308                    Value::Str("DEF".to_string(), "UVW".to_string()),
309                ],
310            );
311            check_result(
312                string_value_list(NomSpan::new(r#"{abc = "xyz", DEF = "UVW", ghi = "rst"};"#)),
313                "",
314                vec![
315                    Value::Str("abc".to_string(), "xyz".to_string()),
316                    Value::Str("DEF".to_string(), "UVW".to_string()),
317                    Value::Str("ghi".to_string(), "rst".to_string()),
318                ],
319            );
320        }
321
322        #[test]
323        fn whitespace() {
324            // Handles whitespace.
325            check_result(
326                string_value_list(NomSpan::new("{  abc=\"xyz\",\n\tDEF\t =  \"UVW\"\n};")),
327                "",
328                vec![
329                    Value::Str("abc".to_string(), "xyz".to_string()),
330                    Value::Str("DEF".to_string(), "UVW".to_string()),
331                ],
332            );
333        }
334
335        #[test]
336        fn invalid_values() {
337            // Does not match non-string values.
338            assert_eq!(
339                string_value_list(NomSpan::new("{abc = 123};")),
340                Err(nom::Err::Error(BindParserError::StringLiteral("123}".to_string())))
341            );
342            assert_eq!(
343                string_value_list(NomSpan::new("{abc = true};")),
344                Err(nom::Err::Error(BindParserError::StringLiteral("true}".to_string())))
345            );
346        }
347
348        #[test]
349        fn trailing_comma() {
350            // Matches trailing ','.
351            check_result(
352                string_value_list(NomSpan::new(r#"{abc = "xyz",};"#)),
353                "",
354                vec![Value::Str("abc".to_string(), "xyz".to_string())],
355            );
356        }
357
358        #[test]
359        fn empty_list() {
360            // Does not match empty list.
361            assert_eq!(
362                string_value_list(NomSpan::new("{};")),
363                Err(nom::Err::Error(BindParserError::Identifier("}".to_string())))
364            );
365        }
366
367        #[test]
368        fn invalid_list() {
369            // Must have list start and end braces.
370            assert_eq!(
371                string_value_list(NomSpan::new(r#"abc = "xyz"};"#)),
372                Err(nom::Err::Error(BindParserError::ListStart(r#"abc = "xyz"}"#.to_string())))
373            );
374            assert_eq!(
375                string_value_list(NomSpan::new(r#"{abc = "xyz";"#)),
376                Err(nom::Err::Error(BindParserError::ListEnd("".to_string())))
377            );
378
379            // Must have assignment operator.
380            assert_eq!(
381                number_value_list(NomSpan::new(r#"{abc "xyz"};"#)),
382                Err(nom::Err::Error(BindParserError::Assignment(r#""xyz"}"#.to_string())))
383            );
384        }
385
386        #[test]
387        fn no_list() {
388            // Matches no list.
389            check_result(string_value_list(NomSpan::new(";")), "", vec![]);
390        }
391    }
392
393    mod bool_value_lists {
394        use super::*;
395
396        #[test]
397        fn single_value() {
398            // Matches one string value.
399            check_result(
400                bool_value_list(NomSpan::new("{abc = true};")),
401                "",
402                vec![Value::Bool("abc".to_string(), true)],
403            );
404        }
405
406        #[test]
407        fn multiple_values() {
408            // Matches multiple string values.
409            check_result(
410                bool_value_list(NomSpan::new("{abc = true, DEF = false};")),
411                "",
412                vec![Value::Bool("abc".to_string(), true), Value::Bool("DEF".to_string(), false)],
413            );
414            check_result(
415                bool_value_list(NomSpan::new("{abc = true, DEF = false, ghi = false};")),
416                "",
417                vec![
418                    Value::Bool("abc".to_string(), true),
419                    Value::Bool("DEF".to_string(), false),
420                    Value::Bool("ghi".to_string(), false),
421                ],
422            );
423        }
424
425        #[test]
426        fn whitespace() {
427            // Handles whitespace.
428            check_result(
429                bool_value_list(NomSpan::new("{  abc=true,\n\tDEF\t =  false\n};")),
430                "",
431                vec![Value::Bool("abc".to_string(), true), Value::Bool("DEF".to_string(), false)],
432            );
433        }
434
435        #[test]
436        fn invalid_values() {
437            // Does not match non-bool values.
438            assert_eq!(
439                bool_value_list(NomSpan::new("{abc = 123};")),
440                Err(nom::Err::Error(BindParserError::BoolLiteral("123}".to_string())))
441            );
442            assert_eq!(
443                bool_value_list(NomSpan::new("{abc = \"string\"};")),
444                Err(nom::Err::Error(BindParserError::BoolLiteral("\"string\"}".to_string())))
445            );
446        }
447
448        #[test]
449        fn trailing_comma() {
450            // Matches trailing ','.
451            check_result(
452                bool_value_list(NomSpan::new(r#"{abc = true,};"#)),
453                "",
454                vec![Value::Bool("abc".to_string(), true)],
455            );
456        }
457
458        #[test]
459        fn empty_list() {
460            // Does not match empty list.
461            assert_eq!(
462                bool_value_list(NomSpan::new("{};")),
463                Err(nom::Err::Error(BindParserError::Identifier("}".to_string())))
464            );
465        }
466
467        #[test]
468        fn invalid_list() {
469            // Must have list start and end braces.
470            assert_eq!(
471                bool_value_list(NomSpan::new("abc = true};")),
472                Err(nom::Err::Error(BindParserError::ListStart("abc = true}".to_string())))
473            );
474            assert_eq!(
475                bool_value_list(NomSpan::new("{abc = true;")),
476                Err(nom::Err::Error(BindParserError::ListEnd("".to_string())))
477            );
478
479            // Must have assignment operator.
480            assert_eq!(
481                number_value_list(NomSpan::new("{abc false};")),
482                Err(nom::Err::Error(BindParserError::Assignment("false}".to_string())))
483            );
484        }
485
486        #[test]
487        fn no_list() {
488            // Matches no list
489            check_result(bool_value_list(NomSpan::new(";")), "", vec![]);
490        }
491    }
492
493    mod enum_value_lists {
494        use super::*;
495
496        #[test]
497        fn single_value() {
498            // Matches one identifier.
499            check_result(
500                enum_value_list(NomSpan::new("{abc};")),
501                "",
502                vec![Value::Enum("abc".to_string())],
503            );
504        }
505
506        #[test]
507        fn multiple_values() {
508            // Matches multiple identifiers.
509            check_result(
510                enum_value_list(NomSpan::new("{abc,def};")),
511                "",
512                vec![Value::Enum("abc".to_string()), Value::Enum("def".to_string())],
513            );
514            check_result(
515                enum_value_list(NomSpan::new("{abc,def,ghi};")),
516                "",
517                vec![
518                    Value::Enum("abc".to_string()),
519                    Value::Enum("def".to_string()),
520                    Value::Enum("ghi".to_string()),
521                ],
522            );
523        }
524
525        #[test]
526        fn whitespace() {
527            // Matches multiple identifiers with whitespace.
528            check_result(
529                enum_value_list(NomSpan::new("{abc,   def, \tghi,\n jkl};")),
530                "",
531                vec![
532                    Value::Enum("abc".to_string()),
533                    Value::Enum("def".to_string()),
534                    Value::Enum("ghi".to_string()),
535                    Value::Enum("jkl".to_string()),
536                ],
537            );
538        }
539
540        #[test]
541        fn trailing_comma() {
542            // Matches trailing ','.
543            check_result(
544                enum_value_list(NomSpan::new("{abc,};")),
545                "",
546                vec![Value::Enum("abc".to_string())],
547            );
548        }
549
550        #[test]
551        fn no_list() {
552            // Matches no list.
553            check_result(enum_value_list(NomSpan::new(";")), "", vec![]);
554        }
555
556        #[test]
557        fn invalid_list() {
558            // Must have semicolon.
559            assert_eq!(
560                enum_value_list(NomSpan::new("{abc,}")),
561                Err(nom::Err::Error(BindParserError::Semicolon("{abc,}".to_string())))
562            );
563
564            // Must have list start and end braces.
565            assert_eq!(
566                enum_value_list(NomSpan::new("abc};")),
567                Err(nom::Err::Error(BindParserError::ListStart("abc}".to_string())))
568            );
569            assert_eq!(
570                enum_value_list(NomSpan::new("{abc;")),
571                Err(nom::Err::Error(BindParserError::ListEnd("".to_string())))
572            );
573        }
574
575        #[test]
576        fn empty_list() {
577            // Does not match empty list.
578            assert_eq!(
579                enum_value_list(NomSpan::new("{};")),
580                Err(nom::Err::Error(BindParserError::Identifier("}".to_string())))
581            );
582        }
583    }
584
585    mod declarations {
586        use super::*;
587
588        #[test]
589        fn no_value() {
590            // Matches key declaration without values.
591            check_result(
592                declaration(NomSpan::new("uint test;")),
593                "",
594                Declaration {
595                    identifier: make_identifier!["test"],
596                    value_type: ValueType::Number,
597                    extends: false,
598                    values: vec![],
599                },
600            );
601        }
602
603        #[test]
604        fn numbers() {
605            // Matches numbers.
606            check_result(
607                declaration(NomSpan::new("uint test { x = 1 };")),
608                "",
609                Declaration {
610                    identifier: make_identifier!["test"],
611                    value_type: ValueType::Number,
612                    extends: false,
613                    values: vec![Value::Number("x".to_string(), 1)],
614                },
615            );
616        }
617
618        #[test]
619        fn strings() {
620            // Matches strings.
621            check_result(
622                declaration(NomSpan::new(r#"string test { x = "a" };"#)),
623                "",
624                Declaration {
625                    identifier: make_identifier!["test"],
626                    value_type: ValueType::Str,
627                    extends: false,
628                    values: vec![Value::Str("x".to_string(), "a".to_string())],
629                },
630            );
631        }
632
633        #[test]
634        fn bools() {
635            // Matches bools.
636            check_result(
637                declaration(NomSpan::new("bool test { x = false };")),
638                "",
639                Declaration {
640                    identifier: make_identifier!["test"],
641                    value_type: ValueType::Bool,
642                    extends: false,
643                    values: vec![Value::Bool("x".to_string(), false)],
644                },
645            );
646        }
647
648        #[test]
649        fn enums() {
650            // Matches enums.
651            check_result(
652                declaration(NomSpan::new("enum test { x };")),
653                "",
654                Declaration {
655                    identifier: make_identifier!["test"],
656                    value_type: ValueType::Enum,
657                    extends: false,
658                    values: vec![Value::Enum("x".to_string())],
659                },
660            );
661        }
662
663        #[test]
664        fn extend() {
665            // Handles "extend" keyword.
666            check_result(
667                declaration(NomSpan::new("extend uint test { x = 1 };")),
668                "",
669                Declaration {
670                    identifier: make_identifier!["test"],
671                    value_type: ValueType::Number,
672                    extends: true,
673                    values: vec![Value::Number("x".to_string(), 1)],
674                },
675            );
676        }
677
678        #[test]
679        fn type_mismatch() {
680            // Handles type mismatches.
681            assert_eq!(
682                declaration(NomSpan::new("uint test { x = false };")),
683                Err(nom::Err::Error(BindParserError::NumericLiteral("false }".to_string())))
684            );
685        }
686
687        #[test]
688        fn invalid() {
689            // Must have a type, and an identifier.
690            assert_eq!(
691                declaration(NomSpan::new("bool { x = false };")),
692                Err(nom::Err::Error(BindParserError::Identifier("{ x = false };".to_string())))
693            );
694            assert_eq!(
695                declaration(NomSpan::new("test { x = false };")),
696                Err(nom::Err::Error(BindParserError::Type("test { x = false };".to_string())))
697            );
698
699            // Must be terminated by ';'.
700            assert_eq!(
701                declaration(NomSpan::new("bool test { x = false }")),
702                Err(nom::Err::Error(BindParserError::Semicolon(" { x = false }".to_string())))
703            );
704        }
705
706        #[test]
707        fn compound_identifier() {
708            // Identifier can be compound.
709            check_result(
710                declaration(NomSpan::new("uint this.is.a.test { x = 1 };")),
711                "",
712                Declaration {
713                    identifier: make_identifier!["this", "is", "a", "test"],
714                    value_type: ValueType::Number,
715                    extends: false,
716                    values: vec![Value::Number("x".to_string(), 1)],
717                },
718            );
719        }
720
721        #[test]
722        fn empty() {
723            // Does not match empty string.
724            assert_eq!(
725                declaration(NomSpan::new("")),
726                Err(nom::Err::Error(BindParserError::Type("".to_string())))
727            );
728        }
729    }
730
731    mod library_names {
732        use super::*;
733
734        #[test]
735        fn single_name() {
736            check_result(library_name(NomSpan::new("library a;")), "", make_identifier!["a"]);
737        }
738
739        #[test]
740        fn compound_name() {
741            check_result(
742                library_name(NomSpan::new("library a.b;")),
743                "",
744                make_identifier!["a", "b"],
745            );
746        }
747
748        #[test]
749        fn whitespace() {
750            check_result(
751                library_name(NomSpan::new("library \n\t a\n\t ;")),
752                "",
753                make_identifier!["a"],
754            );
755        }
756
757        #[test]
758        fn invalid() {
759            // Must have a name.
760            assert_eq!(
761                library_name(NomSpan::new("library ;")),
762                Err(nom::Err::Error(BindParserError::Identifier(";".to_string())))
763            );
764
765            // Must be terminated by ';'.
766            assert_eq!(
767                library_name(NomSpan::new("library a")),
768                Err(nom::Err::Error(BindParserError::Semicolon("".to_string())))
769            );
770        }
771
772        #[test]
773        fn empty() {
774            // Does not match empty string.
775            assert_eq!(
776                library_name(NomSpan::new("")),
777                Err(nom::Err::Error(BindParserError::LibraryKeyword("".to_string())))
778            );
779        }
780    }
781
782    mod libraries {
783        use super::*;
784
785        #[test]
786        fn empty() {
787            // Does not match empty string.
788            assert_eq!(
789                library(NomSpan::new("")),
790                Err(nom::Err::Error(BindParserError::LibraryKeyword("".to_string())))
791            );
792        }
793
794        #[test]
795        fn empty_library() {
796            check_result(
797                library(NomSpan::new("library a;")),
798                "",
799                Ast { name: make_identifier!["a"], using: vec![], declarations: vec![] },
800            );
801        }
802
803        #[test]
804        fn using_list() {
805            check_result(
806                library(NomSpan::new("library a; using c as d;")),
807                "",
808                Ast {
809                    name: make_identifier!["a"],
810                    using: vec![Include {
811                        name: make_identifier!["c"],
812                        alias: Some("d".to_string()),
813                    }],
814                    declarations: vec![],
815                },
816            );
817        }
818
819        #[test]
820        fn declarations() {
821            check_result(
822                library(NomSpan::new("library a; uint t { x = 1 };")),
823                "",
824                Ast {
825                    name: make_identifier!["a"],
826                    using: vec![],
827                    declarations: vec![Declaration {
828                        identifier: make_identifier!["t"],
829                        value_type: ValueType::Number,
830                        extends: false,
831                        values: vec![(Value::Number("x".to_string(), 1))],
832                    }],
833                },
834            );
835        }
836
837        #[test]
838        fn multiple_elements() {
839            // Matches library with using list and declarations.
840            check_result(
841                library(NomSpan::new("library a; using b.c as d; extend enum d.t { x };")),
842                "",
843                Ast {
844                    name: make_identifier!["a"],
845                    using: vec![Include {
846                        name: make_identifier!["b", "c"],
847                        alias: Some("d".to_string()),
848                    }],
849                    declarations: vec![Declaration {
850                        identifier: make_identifier!["d", "t"],
851                        value_type: ValueType::Enum,
852                        extends: true,
853                        values: vec![Value::Enum("x".to_string())],
854                    }],
855                },
856            );
857
858            // Matches library with using list and two declarations.
859            check_result(
860                library(NomSpan::new("library a; using b.c as d; extend enum d.t { x }; bool e;")),
861                "",
862                Ast {
863                    name: make_identifier!["a"],
864                    using: vec![Include {
865                        name: make_identifier!["b", "c"],
866                        alias: Some("d".to_string()),
867                    }],
868                    declarations: vec![
869                        Declaration {
870                            identifier: make_identifier!["d", "t"],
871                            value_type: ValueType::Enum,
872                            extends: true,
873                            values: vec![Value::Enum("x".to_string())],
874                        },
875                        Declaration {
876                            identifier: make_identifier!["e"],
877                            value_type: ValueType::Bool,
878                            extends: false,
879                            values: vec![],
880                        },
881                    ],
882                },
883            );
884        }
885
886        #[test]
887        fn consumes_entire_input() {
888            // Must parse entire input.
889            assert_eq!(
890                library(NomSpan::new("library a; using b.c as d; invalid input")),
891                Err(nom::Err::Error(BindParserError::Type("invalid input".to_string())))
892            );
893        }
894
895        #[test]
896        fn whitespace() {
897            // Handles whitespace.
898            assert_eq!(
899                library(NomSpan::new(
900                    "\n\t library a;\t using b.c as d;\n extend enum d.t { x }; \t bool e;\n "
901                ))
902                .unwrap()
903                .1,
904                library(NomSpan::new("library a; using b.c as d; extend enum d.t { x }; bool e;"))
905                    .unwrap()
906                    .1,
907            );
908        }
909    }
910}