use super::*;
impl Parser {
pub(super) fn parse_effect_set(&mut self) -> Result<TopLevel, ParseError> {
Err(self
.error("Effect aliases were removed. Declare concrete effects directly in ! [...]."))
}
pub(super) fn parse_sum_type_def(&mut self) -> Result<TypeDef, ParseError> {
let line = self.current().line;
self.expect_exact(&TokenKind::Type)?;
let name_tok = self.expect_kind(&TokenKind::Ident(String::new()), "Expected type name")?;
let type_name = match name_tok.kind {
TokenKind::Ident(s) => s,
_ => unreachable!(),
};
self.skip_newlines();
let mut variants = Vec::new();
if self.is_indent() {
self.advance(); self.skip_newlines();
while !self.is_dedent() && !self.is_eof() {
if self.is_newline() {
self.advance();
continue;
}
let variant_tok =
self.expect_kind(&TokenKind::Ident(String::new()), "Expected variant name")?;
let variant_name = match variant_tok.kind {
TokenKind::Ident(s) => s,
_ => unreachable!(),
};
let mut fields = Vec::new();
if self.check_exact(&TokenKind::LParen) {
self.advance();
while !self.check_exact(&TokenKind::RParen) && !self.is_eof() {
if self.check_exact(&TokenKind::Comma) {
self.advance();
continue;
}
let ty = self.parse_type()?;
fields.push(ty);
}
self.expect_exact(&TokenKind::RParen)?;
}
variants.push(TypeVariant {
name: variant_name,
fields,
});
self.skip_newlines();
}
if self.is_dedent() {
self.advance();
}
}
Ok(TypeDef::Sum {
name: type_name,
variants,
line,
})
}
pub(super) fn parse_record_def(&mut self) -> Result<TypeDef, ParseError> {
let line = self.current().line;
self.expect_exact(&TokenKind::Record)?;
let name_tok =
self.expect_kind(&TokenKind::Ident(String::new()), "Expected record name")?;
let type_name = match name_tok.kind {
TokenKind::Ident(s) => s,
_ => unreachable!(),
};
self.skip_newlines();
let mut fields = Vec::new();
if self.is_indent() {
self.advance(); self.skip_newlines();
while !self.is_dedent() && !self.is_eof() {
if self.is_newline() {
self.advance();
continue;
}
let field_tok =
self.expect_kind(&TokenKind::Ident(String::new()), "Expected field name")?;
let field_name = match field_tok.kind {
TokenKind::Ident(s) => s,
_ => unreachable!(),
};
self.expect_exact(&TokenKind::Colon)?;
let field_type = self.parse_type()?;
fields.push((field_name, field_type));
self.skip_newlines();
}
if self.is_dedent() {
self.advance();
}
}
Ok(TypeDef::Product {
name: type_name,
fields,
line,
})
}
pub(super) fn parse_type(&mut self) -> Result<String, ParseError> {
if self.check_exact(&TokenKind::LParen) {
self.advance(); let mut elems = Vec::new();
while !self.check_exact(&TokenKind::RParen) && !self.is_eof() {
if self.check_exact(&TokenKind::Comma) {
self.advance();
continue;
}
elems.push(self.parse_type()?);
if self.check_exact(&TokenKind::Comma) {
self.advance();
}
}
self.expect_exact(&TokenKind::RParen)?;
if elems.len() < 2 {
return Err(self.error("Tuple type must have at least 2 elements".to_string()));
}
return Ok(format!("({})", elems.join(", ")));
}
if let TokenKind::Ident(name) = &self.current().kind
&& name == "Fn"
&& matches!(self.peek(1).kind, TokenKind::LParen)
{
self.advance(); self.expect_exact(&TokenKind::LParen)?;
let mut params = Vec::new();
while !self.check_exact(&TokenKind::RParen) && !self.is_eof() {
if self.check_exact(&TokenKind::Comma) {
self.advance();
continue;
}
params.push(self.parse_type()?);
if self.check_exact(&TokenKind::Comma) {
self.advance();
}
}
self.expect_exact(&TokenKind::RParen)?;
self.expect_exact(&TokenKind::Arrow)?;
let ret = self.parse_type()?;
let mut out = format!("Fn({}) -> {}", params.join(", "), ret);
if self.check_exact(&TokenKind::Bang) {
self.advance(); let effects = self.parse_effect_ident_list()?;
out.push_str(&format!(
" ! [{}]",
effects
.iter()
.map(|e| e.node.as_str())
.collect::<Vec<_>>()
.join(", ")
));
}
return Ok(out);
}
let mut base = match &self.current().kind {
TokenKind::Ident(s) => {
let s = s.clone();
self.advance();
if s == "Any" {
return Err(self.error(
"Type 'Any' has been removed. Use an explicit concrete type.".to_string(),
));
}
s
}
_ => {
return Err(self.error(format!(
"Expected a type name, found {}",
self.current().kind
)));
}
};
if self.check_exact(&TokenKind::Dot)
&& let Some(Token {
kind: TokenKind::Ident(next),
..
}) = self.tokens.get(self.pos + 1)
&& next.chars().next().is_some_and(|c| c.is_uppercase())
{
let next = next.clone();
self.advance(); self.advance(); base = format!("{}.{}", base, next);
}
if self.check_exact(&TokenKind::Lt) {
self.advance(); let mut args = Vec::new();
while !self.check_exact(&TokenKind::Gt) && !self.is_eof() {
if self.check_exact(&TokenKind::Comma) {
self.advance();
continue;
}
args.push(self.parse_type()?);
if self.check_exact(&TokenKind::Comma) {
self.advance();
}
}
self.expect_exact(&TokenKind::Gt)?;
base = format!("{}<{}>", base, args.join(", "));
}
Ok(base)
}
pub(super) fn parse_effect_ident_list(
&mut self,
) -> Result<Vec<crate::ast::Spanned<String>>, ParseError> {
self.expect_exact(&TokenKind::LBracket)?;
let mut effects = Vec::new();
while !self.check_exact(&TokenKind::RBracket) && !self.is_eof() {
match self.current().kind.clone() {
TokenKind::Newline | TokenKind::Indent | TokenKind::Dedent => {
self.advance();
}
TokenKind::Ident(_) => {
let line = self.current().line;
let name = self.parse_qualified_ident()?;
effects.push(crate::ast::Spanned { node: name, line });
}
TokenKind::Comma => {
self.advance();
}
_ => {
return Err(self.error(format!(
"Expected effect name in type annotation, found {}",
self.current().kind
)));
}
}
}
self.expect_exact(&TokenKind::RBracket)?;
Ok(effects)
}
}