use super::{
identifier::{parse_identifier, Identifier},
metadata::AstNodeMeta,
};
use crate::parser::{
error::ParserErrorVariant,
lexer::tokens::TokenTy,
state::ParserState,
util::{ignore::ignore_whitespace_and_comments, NodeParserOption, NodeParserResult},
};
#[derive(Debug)]
pub struct Path<'src> {
pub meta: AstNodeMeta<'src>,
pub head: Identifier<'src>,
pub tail: Option<Box<Path<'src>>>,
}
pub fn parse_path<'src>(parser_state: &mut ParserState<'src>) -> NodeParserResult<Path<'src>> {
let initial_index = parser_state.index();
let head = parse_identifier(parser_state)
.map_err(|mut parser_error| {
parser_error.ty = ParserErrorVariant::Expected(
"fully qualified symbol reference (path) or identifier",
);
parser_error
})?;
let tail = parse_path_tail(parser_state).map(Box::new);
let meta = parser_state.make_ast_node_meta(initial_index, parser_state.index() - initial_index);
Ok(Path { meta, head, tail })
}
fn parse_path_tail<'src>(parser_state: &mut ParserState<'src>) -> NodeParserOption<Path<'src>> {
let initial_index = parser_state.index();
let mut scoped_state = parser_state.clone();
ignore_whitespace_and_comments(&mut scoped_state).ok()?;
scoped_state.next_token_if_ty_eq(TokenTy::ColonColon)?;
ignore_whitespace_and_comments(&mut scoped_state).ok()?;
let head = parse_identifier(&mut scoped_state).ok()?;
*parser_state = scoped_state.clone();
let tail = parse_path_tail(&mut scoped_state).map(Box::new);
if tail.is_some() {
*parser_state = scoped_state;
}
let meta = parser_state.make_ast_node_meta(initial_index, parser_state.index() - initial_index);
Some(Path { meta, head, tail })
}
#[cfg(test)]
mod test_path {
use crate::{
filemap::{FileMap, FileName},
parser::state::ParserState,
};
use super::parse_path;
#[test]
fn test_simple_path() {
let source = "test::path";
let mut file_map = FileMap::new();
let file_id = file_map.add(FileName::Test("test input"), source.to_owned());
let mut parser_state = ParserState::new(&file_map, file_id);
let path = parse_path(&mut parser_state).expect("parses successfully");
assert_eq!(path.head.matching_source(), "test");
assert!(path.tail.is_some());
assert_eq!(path.tail.unwrap().head.matching_source(), "path");
}
}