use super::Parser;
use crate::ast::{Path, PathStart, TypeExpr};
use crate::span::Span;
use crate::token::TokenKind;
impl<'a> Parser<'a> {
pub(super) fn parse_type(&mut self) -> Result<TypeExpr, ()> {
let start_span = self.current_span();
let leading = self.take_path_start();
let mut segments = vec![self.expect_identifier("a type name")?];
while self.peek() == Some(&TokenKind::ColonColon) {
self.bump();
segments.push(self.expect_identifier("a type name after `::`")?);
}
let name = segments.pop().expect("at least one segment");
let path = (leading != PathStart::None || !segments.is_empty()).then(|| {
let end = segments.last().map_or(start_span, |s| s.span);
Path {
leading,
segments,
span: self.span_from(start_span, end),
}
});
let mut span = self.span_from(start_span, name.span);
let args = if self.peek() == Some(&TokenKind::Lt) {
let (args, group_span) = self.parse_generic_args()?;
span = self.span_from(span, group_span);
args
} else {
Vec::new()
};
Ok(TypeExpr {
path,
name,
args,
span,
})
}
fn parse_generic_args(&mut self) -> Result<(Vec<TypeExpr>, Span), ()> {
let lt = self.bump().expect("caller confirmed `<` is present");
let mut args = Vec::new();
loop {
args.push(self.parse_type()?);
if self.bump_if(&TokenKind::Comma) {
if self.peek() == Some(&TokenKind::Gt) {
break;
}
continue;
}
break;
}
let gt = self.expect(TokenKind::Gt, "`>` after the generic arguments")?;
Ok((args, self.span_from(lt.span, gt.span)))
}
pub(super) fn skip_generic_args(&mut self) -> Span {
let lt = self.bump().expect("caller confirmed `<` is present");
let mut depth = 1u32;
let mut last_span = lt.span;
while depth > 0 {
match self.peek() {
Some(TokenKind::Lt) => {
depth += 1;
last_span = self.bump().expect("peek just confirmed a token").span;
}
Some(TokenKind::Gt) => {
depth -= 1;
last_span = self.bump().expect("peek just confirmed a token").span;
}
Some(_) => {
last_span = self.bump().expect("peek just confirmed a token").span;
}
None => break,
}
}
self.span_from(lt.span, last_span)
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::error::SyntaxError;
use crate::lex;
use crate::source::SourceFile;
use crate::span::FileId;
fn parse_type(src: &str) -> (Result<TypeExpr, ()>, Vec<SyntaxError>) {
let file = SourceFile::new(FileId(0), "test.vr", src);
let (tokens, lex_errors) = lex(&file);
assert!(
lex_errors.is_empty(),
"unexpected lex errors: {lex_errors:?}"
);
let mut parser = Parser::new(&tokens, FileId(0));
let ty = parser.parse_type();
(ty, parser.errors().to_vec())
}
fn parse_type_ok(src: &str) -> TypeExpr {
let (ty, errors) = parse_type(src);
assert!(
errors.is_empty(),
"unexpected errors parsing {src:?}: {errors:?}"
);
ty.unwrap_or_else(|()| panic!("expected {src:?} to parse"))
}
#[test]
fn bare_identifier_type() {
let ty = parse_type_ok("i32");
assert_eq!(ty.name.name, "i32");
assert!(ty.path.is_none());
assert!(ty.args.is_empty());
}
#[test]
fn module_qualified_type_parses() {
let ty = parse_type_ok("m::User");
let path = ty.path.as_ref().unwrap();
assert_eq!(path.segments.len(), 1);
assert_eq!(path.segments[0].name, "m");
assert_eq!(ty.name.name, "User");
assert!(ty.args.is_empty());
}
#[test]
fn nested_module_path_type_parses() {
let ty = parse_type_ok("shop::cart::Cart");
let path = ty.path.as_ref().unwrap();
let names: Vec<&str> = path.segments.iter().map(|s| s.name.as_str()).collect();
assert_eq!(names, vec!["shop", "cart"]);
assert_eq!(ty.name.name, "Cart");
}
#[test]
fn crate_prefixed_type_path_parses() {
let ty = parse_type_ok("crate::a::Foo");
let path = ty.path.as_ref().unwrap();
assert!(matches!(path.leading, crate::ast::PathStart::Crate));
let names: Vec<&str> = path.segments.iter().map(|s| s.name.as_str()).collect();
assert_eq!(names, vec!["a"]);
assert_eq!(ty.name.name, "Foo");
}
#[test]
fn generic_type_with_one_argument_parses() {
let ty = parse_type_ok("Vec<i32>");
assert_eq!(ty.name.name, "Vec");
assert_eq!(ty.args.len(), 1);
assert_eq!(ty.args[0].name.name, "i32");
}
#[test]
fn generic_type_with_two_arguments_parses() {
let ty = parse_type_ok("Result<User, string>");
assert_eq!(ty.name.name, "Result");
assert_eq!(ty.args.len(), 2);
assert_eq!(ty.args[0].name.name, "User");
assert_eq!(ty.args[1].name.name, "string");
}
#[test]
fn nested_generic_arguments_parse() {
let ty = parse_type_ok("Vec<Option<Shape>>");
assert_eq!(ty.name.name, "Vec");
assert_eq!(ty.args.len(), 1);
let inner = &ty.args[0];
assert_eq!(inner.name.name, "Option");
assert_eq!(inner.args.len(), 1);
assert_eq!(inner.args[0].name.name, "Shape");
}
#[test]
fn module_qualified_generic_type_parses() {
let ty = parse_type_ok("m::Vec<i32>");
assert_eq!(ty.path.as_ref().unwrap().segments[0].name, "m");
assert_eq!(ty.name.name, "Vec");
assert_eq!(ty.args.len(), 1);
}
}