wright/parser/decl/
import.rs

1//! Parser implementation for `use path::to::thing;` declaration.
2
3use crate::{
4    ast::{decl::import::ImportDecl, identifier::Identifier, path::Path},
5    lexer::token::{Token, TokenTy},
6    parser::{
7        Parser,
8        error::{ParserError, ParserErrorKind},
9        whitespace,
10    },
11    source_tracking::fragment::Fragment,
12};
13
14impl ImportDecl {
15    /// Parse an import declaration.
16    ///
17    /// This will advance the parser if `use` is seen -- if a valid formed import does not follow,
18    /// the parser may be left in the middle of a malformed declaration.
19    pub fn parse(parser: &mut Parser) -> Result<Self, ParserError> {
20        let use_kw: Token = parser.next_if_is(TokenTy::KwUse).ok_or(
21            ParserErrorKind::ExpectedImportDeclaration.at(parser.peek_fragment_or_rest_cloned()),
22        )?;
23
24        // Require a whitespace after the keyword.
25        whitespace::require_whitespace(parser)?;
26        // Parse the path.
27        let path: Path = Path::parse(parser)?;
28
29        // Whitespace and then "as ...;" or optional whitespace and semi ";".
30
31        // The "as ...;" requires a whitespace.
32        let imported_as = if parser.matches(&[TokenTy::Whitespace, TokenTy::KwAs]) {
33            parser.advance(2);
34
35            whitespace::require_whitespace(parser)
36                .map_err(|e| e.with_help("whitespace needed between \"as\" and binding."))?;
37
38            let imported_as = Identifier::parse(parser)
39                .map_err(|e| e.with_help("expected binding in \"use ... as\" declaration."))?;
40
41            Some(imported_as)
42        } else {
43            None
44        };
45
46        whitespace::optional_whitespace(parser);
47
48        if let Some(semi) = parser.next_if_is(TokenTy::Semi) {
49            Ok(ImportDecl {
50                matching_source: Fragment::cover(use_kw.fragment, semi.fragment),
51                imported_item: path,
52                imported_as,
53            })
54        } else {
55            Err(ParserErrorKind::ImportMustEndWithSemicolon
56                .at(parser.peek_fragment_or_rest_cloned()))
57        }
58    }
59}
60
61#[cfg(test)]
62mod tests {
63    use crate::{ast::decl::import::ImportDecl, lexer::Lexer, parser::Parser};
64
65    #[test]
66    fn test_import() {
67        let mut parser = Parser::new(Lexer::new_test("use wright::util;"));
68        let import_decl = ImportDecl::parse(&mut parser).unwrap();
69        assert!(parser.lexer.remaining.is_empty());
70        assert_eq!(import_decl.imported_item.head.fragment.as_str(), "wright");
71        assert_eq!(import_decl.imported_item.tail[0].fragment.as_str(), "util");
72    }
73
74    #[test]
75    fn test_import_with_whitespace() {
76        let mut parser = Parser::new(Lexer::new_test("use wright :: util ;"));
77        let import_decl = ImportDecl::parse(&mut parser).unwrap();
78        assert!(parser.lexer.remaining.is_empty());
79        assert_eq!(import_decl.imported_item.head.fragment.as_str(), "wright");
80        assert_eq!(import_decl.imported_item.tail[0].fragment.as_str(), "util");
81    }
82
83    #[test]
84    fn test_import_as() {
85        let mut parser = Parser::new(Lexer::new_test("use wright::util as u;"));
86        let import_decl = ImportDecl::parse(&mut parser).unwrap();
87        assert!(parser.lexer.remaining.is_empty());
88        assert_eq!(import_decl.imported_item.head.fragment.as_str(), "wright");
89        assert_eq!(import_decl.imported_item.tail[0].fragment.as_str(), "util");
90        assert_eq!(import_decl.imported_as.unwrap().fragment.as_str(), "u");
91    }
92
93    #[test]
94    fn test_import_as_with_comment() {
95        let mut parser = Parser::new(Lexer::new_test("use wright::util as /* old_name */ u;"));
96        let import_decl = ImportDecl::parse(&mut parser).unwrap();
97        assert!(parser.lexer.remaining.is_empty());
98        assert_eq!(import_decl.imported_item.head.fragment.as_str(), "wright");
99        assert_eq!(import_decl.imported_item.tail[0].fragment.as_str(), "util");
100        assert_eq!(import_decl.imported_as.unwrap().fragment.as_str(), "u");
101    }
102}