1use std::sync::Arc;
4
5use super::Parser;
6use super::error::ParserError;
7use super::error::ParserErrorKind;
8use crate::ast::identifier::Identifier;
9use crate::ast::path::Path;
10use crate::lexer::token::TokenTy;
11use crate::source_tracking::fragment::Fragment;
12
13impl Path {
14 pub fn parse(parser: &mut Parser) -> Result<Self, ParserError> {
17 let head: Identifier = parse_head(parser)?;
18 let mut tail = Vec::new();
19
20 while let Some(ident) = parse_segment(parser) {
22 tail.push(ident);
23 }
24
25 let last = tail.last().unwrap_or(&head);
27 let matched_source_range = head.fragment.range.start..last.fragment.range.end;
28
29 Ok(Path {
30 full_path: Fragment {
32 source: Arc::clone(&head.fragment.source),
33 range: matched_source_range,
34 },
35 head,
36 tail,
37 })
38 }
39}
40
41fn parse_head(parser: &mut Parser) -> Result<Identifier, ParserError> {
43 Identifier::parse(parser).map_err(|mut err| {
44 err.kind = ParserErrorKind::ExpectedPath;
45 err
46 })
47}
48
49fn parse_segment(parser: &mut Parser) -> Option<Identifier> {
52 if parser.matches_ignore_whitespace(&[TokenTy::ColonColon, TokenTy::Identifier]) {
53 parser.consume_optional_whitespace();
55
56 parser.advance(1);
58
59 parser.consume_optional_whitespace();
61
62 return Some(unsafe { Identifier::parse(parser).unwrap_unchecked() });
65 }
66
67 None
69}
70
71#[cfg(test)]
72mod test_path {
73 use crate::{
74 ast::path::Path,
75 lexer::Lexer,
76 parser::Parser,
77 source_tracking::{SourceMap, filename::FileName, source::Source},
78 };
79
80 #[test]
82 fn test_ok_paths() {
83 let map = SourceMap::new();
84 let sources = &["test::path", "test :: path", "test ::path", "test:: path"];
85
86 for source in sources {
87 dbg!(source);
88 let source_ref = map.add(Source::new_from_static_str(FileName::None, *source));
89 let lexer = Lexer::new(source_ref);
90 let mut parser = Parser::new(lexer);
91 let path = Path::parse(&mut parser).unwrap();
92 assert_eq!(path.head.fragment.as_str(), "test");
93 assert_eq!(path.tail[0].fragment.as_str(), "path");
94 assert_eq!(path.full_path.len(), source.len());
95 assert_eq!(parser.lexer.bytes_remaining(), 0);
96 }
97 }
98
99 #[test]
100 fn test_not_paths() {
101 let sources = &["", "0", "_"];
102
103 for source in sources {
104 let mut parser = Parser::new(Lexer::new_test(source));
105 assert_eq!(Path::parse(&mut parser).unwrap_err().location.as_str(), *source);
106 }
107 }
108}