use crate::ast::*;
use harn_lexer::TokenKind;
use super::error::ParserError;
use super::state::Parser;
impl Parser {
pub(super) fn parse_type_param_list(&mut self) -> Result<Vec<TypeParam>, ParserError> {
let mut params = Vec::new();
self.skip_newlines();
while !self.is_at_end() && !self.check(&TokenKind::Gt) {
let variance = self.parse_optional_variance_marker();
let name = self.consume_identifier("type parameter name")?;
params.push(TypeParam { name, variance });
if self.check(&TokenKind::Comma) {
self.advance();
self.skip_newlines();
}
}
self.consume(&TokenKind::Gt, ">")?;
Ok(params)
}
pub(super) fn parse_type_arg_list(&mut self) -> Result<Vec<TypeExpr>, ParserError> {
let mut args = Vec::new();
self.skip_newlines();
if self.check(&TokenKind::Gt) {
return Err(self.error("type argument"));
}
while !self.is_at_end() && !self.check(&TokenKind::Gt) {
args.push(self.parse_type_expr()?);
self.skip_newlines();
if self.check(&TokenKind::Comma) {
self.advance();
self.skip_newlines();
} else {
break;
}
}
self.consume(&TokenKind::Gt, ">")?;
Ok(args)
}
pub(super) fn parse_optional_variance_marker(&mut self) -> Variance {
if self.check(&TokenKind::In) {
self.advance();
return Variance::Contravariant;
}
if self.check_identifier("out") {
if let Some(kind) = self.peek_kind() {
if matches!(kind, TokenKind::Identifier(_)) {
self.advance();
return Variance::Covariant;
}
}
}
Variance::Invariant
}
pub(super) fn parse_where_clauses(&mut self) -> Result<Vec<WhereClause>, ParserError> {
if let Some(tok) = self.current() {
if let TokenKind::Identifier(ref id) = tok.kind {
if id == "where" {
self.advance();
let mut clauses = Vec::new();
loop {
self.skip_newlines();
if self.check(&TokenKind::LBrace) || self.is_at_end() {
break;
}
let type_name = self.consume_identifier("type parameter name")?;
self.consume(&TokenKind::Colon, ":")?;
let bound = self.consume_identifier("type bound")?;
clauses.push(WhereClause { type_name, bound });
if self.check(&TokenKind::Comma) {
self.advance();
} else {
break;
}
}
return Ok(clauses);
}
}
}
Ok(Vec::new())
}
pub(super) fn try_parse_type_annotation(&mut self) -> Result<Option<TypeExpr>, ParserError> {
if !self.check(&TokenKind::Colon) {
return Ok(None);
}
self.advance();
Ok(Some(self.parse_type_expr()?))
}
pub(super) fn parse_type_expr(&mut self) -> Result<TypeExpr, ParserError> {
self.skip_newlines();
let first = self.parse_type_intersection()?;
if self.check(&TokenKind::Bar) {
let mut types: Vec<TypeExpr> = Vec::new();
flatten_union_into(&mut types, first);
while self.check(&TokenKind::Bar) {
self.advance();
let next = self.parse_type_intersection()?;
flatten_union_into(&mut types, next);
}
dedupe_in_order(&mut types);
if types.len() == 1 {
return Ok(types.into_iter().next().unwrap());
}
return Ok(TypeExpr::Union(types));
}
Ok(first)
}
fn parse_type_intersection(&mut self) -> Result<TypeExpr, ParserError> {
let first = self.parse_type_primary()?;
if !self.check(&TokenKind::Amp) {
return Ok(first);
}
let mut types = vec![first];
while self.check(&TokenKind::Amp) {
self.advance();
types.push(self.parse_type_primary()?);
}
Ok(TypeExpr::Intersection(types))
}
pub(super) fn parse_type_primary(&mut self) -> Result<TypeExpr, ParserError> {
let base = self.parse_type_primary_base()?;
Ok(self.attach_optional_postfix(base))
}
fn attach_optional_postfix(&mut self, mut ty: TypeExpr) -> TypeExpr {
while self.check(&TokenKind::Question) {
self.advance();
ty = wrap_optional(ty);
}
ty
}
fn parse_type_primary_base(&mut self) -> Result<TypeExpr, ParserError> {
self.skip_newlines();
if self.check(&TokenKind::LBrace) {
return self.parse_shape_type();
}
if self.check(&TokenKind::LBracket) {
self.advance();
let inner = self.parse_type_expr()?;
self.consume(&TokenKind::RBracket, "]")?;
return Ok(TypeExpr::List(Box::new(inner)));
}
if let Some(tok) = self.current() {
match &tok.kind {
TokenKind::Nil => {
self.advance();
return Ok(TypeExpr::Named("nil".to_string()));
}
TokenKind::True | TokenKind::False => {
self.advance();
return Ok(TypeExpr::Named("bool".to_string()));
}
TokenKind::StringLiteral(text) | TokenKind::RawStringLiteral(text) => {
let text = text.clone();
self.advance();
return Ok(TypeExpr::LitString(text));
}
TokenKind::IntLiteral(value) => {
let value = *value;
self.advance();
return Ok(TypeExpr::LitInt(value));
}
TokenKind::Minus => {
if let Some(TokenKind::IntLiteral(v)) = self.peek_kind_at(1) {
let v = *v;
self.advance();
self.advance();
return Ok(TypeExpr::LitInt(-v));
}
}
_ => {}
}
}
if self.check(&TokenKind::Fn) {
self.advance();
self.consume(&TokenKind::LParen, "(")?;
let mut params = Vec::new();
self.skip_newlines();
while !self.is_at_end() && !self.check(&TokenKind::RParen) {
params.push(self.parse_type_expr()?);
self.skip_newlines();
if self.check(&TokenKind::Comma) {
self.advance();
self.skip_newlines();
}
}
self.consume(&TokenKind::RParen, ")")?;
self.consume(&TokenKind::Arrow, "->")?;
let return_type = self.parse_type_expr()?;
return Ok(TypeExpr::FnType {
params,
return_type: Box::new(return_type),
});
}
let name = self.consume_identifier("type name")?;
if name == "never" {
return Ok(TypeExpr::Never);
}
if self.check(&TokenKind::Lt) {
self.advance();
let mut type_args = self.parse_type_arg_list()?;
if name == "list" && type_args.len() == 1 {
return Ok(TypeExpr::List(Box::new(type_args.remove(0))));
} else if name == "dict" && type_args.len() == 2 {
return Ok(TypeExpr::DictType(
Box::new(type_args.remove(0)),
Box::new(type_args.remove(0)),
));
} else if (name == "iter" || name == "Iter") && type_args.len() == 1 {
return Ok(TypeExpr::Iter(Box::new(type_args.remove(0))));
} else if (name == "Generator" || name == "generator") && type_args.len() == 1 {
return Ok(TypeExpr::Generator(Box::new(type_args.remove(0))));
} else if (name == "Stream" || name == "stream") && type_args.len() == 1 {
return Ok(TypeExpr::Stream(Box::new(type_args.remove(0))));
}
return Ok(TypeExpr::Applied {
name,
args: type_args,
});
}
Ok(TypeExpr::Named(name))
}
pub(super) fn parse_shape_type(&mut self) -> Result<TypeExpr, ParserError> {
self.consume(&TokenKind::LBrace, "{")?;
let mut fields = Vec::new();
self.skip_newlines();
while !self.is_at_end() && !self.check(&TokenKind::RBrace) {
let name = self.consume_identifier_or_keyword("field name")?;
let optional = if self.check(&TokenKind::Question) {
self.advance();
true
} else {
false
};
self.consume(&TokenKind::Colon, ":")?;
let type_expr = self.parse_type_expr()?;
fields.push(ShapeField {
name,
type_expr,
optional,
});
self.skip_newlines();
if self.check(&TokenKind::Comma) {
self.advance();
self.skip_newlines();
}
}
self.consume(&TokenKind::RBrace, "}")?;
Ok(TypeExpr::Shape(fields))
}
}
fn is_nil_named(ty: &TypeExpr) -> bool {
matches!(ty, TypeExpr::Named(n) if n == "nil")
}
fn union_contains_nil(types: &[TypeExpr]) -> bool {
types.iter().any(is_nil_named)
}
fn wrap_optional(ty: TypeExpr) -> TypeExpr {
if is_nil_named(&ty) {
return ty;
}
if let TypeExpr::Union(members) = &ty {
if union_contains_nil(members) {
return ty;
}
}
TypeExpr::Union(vec![ty, TypeExpr::Named("nil".to_string())])
}
fn flatten_union_into(out: &mut Vec<TypeExpr>, ty: TypeExpr) {
match ty {
TypeExpr::Union(members) => {
for m in members {
flatten_union_into(out, m);
}
}
other => out.push(other),
}
}
fn dedupe_in_order(types: &mut Vec<TypeExpr>) {
let mut seen: Vec<TypeExpr> = Vec::with_capacity(types.len());
types.retain(|t| {
if seen.contains(t) {
false
} else {
seen.push(t.clone());
true
}
});
}