use super::*;
impl Parser {
pub(super) fn parse_fn(&mut self) -> Result<FnDef, ParseError> {
let fn_line = self.current().line;
self.expect_exact(&TokenKind::Fn)?;
let name_tok =
self.expect_kind(&TokenKind::Ident(String::new()), "Expected function name")?;
let name = match name_tok.kind {
TokenKind::Ident(s) => s,
_ => unreachable!(),
};
self.expect_exact(&TokenKind::LParen)?;
let params = self.parse_params()?;
self.expect_exact(&TokenKind::RParen)?;
let mut return_type = String::from("Unit");
if self.check_exact(&TokenKind::Arrow) {
self.advance();
return_type = self.parse_type()?;
}
if self.check_exact(&TokenKind::Assign) {
return Err(self.error(
"Function bodies no longer use '= expr'. Write the expression as an indented line directly.".to_string(),
));
}
self.skip_newlines();
let mut desc = None;
let mut effects = Vec::new();
let mut body_stmts = Vec::new();
if self.is_indent() {
self.advance(); self.skip_newlines();
if self.check_exact(&TokenKind::Question) {
self.advance();
let text = self
.parse_inline_string_with_continuations()
.map_err(|_| self.error("Expected string after '?'".to_string()))?;
desc = Some(text);
self.skip_newlines();
}
if self.check_exact(&TokenKind::Bang) {
self.advance();
if self.check_exact(&TokenKind::LBracket) {
effects = self.parse_effect_ident_list()?;
} else {
return Err(self.error("Expected '[' after '!'".to_string()));
}
self.skip_newlines();
}
body_stmts = self.parse_fn_body()?;
if self.is_dedent() {
self.advance();
}
}
Ok(FnDef {
name,
line: fn_line,
params,
return_type,
effects,
desc,
body: Rc::new(FnBody::Block(body_stmts)),
resolution: None,
})
}
pub(super) fn parse_params(&mut self) -> Result<Vec<(String, String)>, ParseError> {
let mut params = Vec::new();
while !self.check_exact(&TokenKind::RParen) && !self.is_eof() {
if self.check_exact(&TokenKind::Comma) {
self.advance();
continue;
}
let name_tok =
self.expect_kind(&TokenKind::Ident(String::new()), "Expected parameter name")?;
let param_name = match name_tok.kind {
TokenKind::Ident(s) => s,
_ => unreachable!(),
};
if !self.check_exact(&TokenKind::Colon) {
return Err(self.error(format!(
"Expected ':' and type annotation for parameter '{}'",
param_name
)));
}
self.advance();
let param_type = self.parse_type()?;
params.push((param_name, param_type));
}
Ok(params)
}
pub(super) fn parse_fn_body(&mut self) -> Result<Vec<Stmt>, ParseError> {
let mut stmts = Vec::new();
while !self.is_dedent() && !self.is_eof() {
if self.is_newline() {
self.advance();
continue;
}
if self.check_exact(&TokenKind::Assign) {
return Err(self.error(
"Function bodies no longer use '= expr'. Write the expression as an indented line directly.".to_string(),
));
} else if matches!(&self.current().kind, TokenKind::Ident(s) if s == "val" || s == "var")
{
let kw = match &self.current().kind {
TokenKind::Ident(s) => s.clone(),
_ => unreachable!(),
};
return Err(self.error(format!(
"Unknown keyword '{}'. Bindings are just: x = 5",
kw
)));
} else if self.check_exact(&TokenKind::Match) {
let line = self.current().line;
let expr = self.parse_match()?;
stmts.push(Stmt::Expr(Spanned::new(expr, line)));
} else if matches!(&self.current().kind, TokenKind::Ident(_))
&& matches!(&self.peek(1).kind, TokenKind::Assign | TokenKind::Colon)
{
let stmt = self.parse_binding()?;
stmts.push(stmt);
} else {
let expr = self.parse_expr()?;
stmts.push(Stmt::Expr(expr));
self.skip_newlines();
}
}
Ok(stmts)
}
pub(super) fn parse_binding(&mut self) -> Result<Stmt, ParseError> {
let name_tok =
self.expect_kind(&TokenKind::Ident(String::new()), "Expected variable name")?;
let name = match name_tok.kind {
TokenKind::Ident(s) => s,
_ => unreachable!(),
};
let type_ann = if self.check_exact(&TokenKind::Colon) {
self.advance();
Some(self.parse_type()?)
} else {
None
};
self.expect_exact(&TokenKind::Assign)?;
let value = self.parse_expr()?;
self.skip_newlines();
Ok(Stmt::Binding(name, type_ann, value))
}
}