use super::*;
impl Parser {
pub(super) fn parse_block(&mut self) -> Result<Block> {
self.expect(Token::LeftBrace)?;
self.finish_block()
}
pub(super) fn finish_block(&mut self) -> Result<Block> {
let mut statements = Vec::new();
let mut result = None;
while !self.at(&Token::RightBrace) && !self.at(&Token::End) {
if self.is_statement_start() {
statements.extend(self.parse_statement()?);
} else {
let expression = self.parse_expression()?;
result = self.finish_block_statement(expression, &mut statements);
if result.is_some() {
break;
}
}
}
self.expect(Token::RightBrace)?;
Ok(Block { statements, result })
}
pub(super) fn finish_block_after_expression(&mut self, first: Expression) -> Result<Block> {
let mut statements = Vec::new();
let mut result = self.finish_block_statement(first, &mut statements);
if result.is_none() {
while !self.at(&Token::RightBrace) && !self.at(&Token::End) {
if self.is_statement_start() {
statements.extend(self.parse_statement()?);
} else {
let expression = self.parse_expression()?;
result = self.finish_block_statement(expression, &mut statements);
if result.is_some() {
break;
}
}
}
}
self.expect(Token::RightBrace)?;
Ok(Block { statements, result })
}
fn finish_block_statement(
&mut self,
expression: Expression,
statements: &mut Vec<Statement>,
) -> Option<Box<Expression>> {
if self.at(&Token::Semicolon) {
self.advance();
statements.push(Statement::Expression(expression));
None
} else if is_block_expression(&expression)
&& !self.at(&Token::RightBrace)
&& !self.at(&Token::End)
{
statements.push(Statement::Expression(expression));
None
} else {
Some(Box::new(auto_deref(expression, &self.context)))
}
}
pub(super) fn is_statement_start(&self) -> bool {
matches!(
self.peek(),
Token::Let
| Token::Var
| Token::Ref
| Token::Return
| Token::Label
| Token::Jump
| Token::Defer
| Token::While
)
}
pub(super) fn parse_statement(&mut self) -> Result<Vec<Statement>> {
match self.peek().clone() {
Token::Let => self.parse_let(Binding::Value),
Token::Var => self.parse_let(Binding::Variable),
Token::Ref => self.parse_let(Binding::Reference),
Token::Return => self.parse_return().map(|s| vec![s]),
Token::Label => self.parse_label().map(|s| vec![s]),
Token::Jump => self.parse_jump().map(|s| vec![s]),
Token::Defer => self.parse_defer().map(|s| vec![s]),
Token::While => self.parse_while().map(|s| vec![s]),
_ => unreachable!(),
}
}
fn parse_while(&mut self) -> Result<Statement> {
self.advance();
let condition = auto_deref(self.parse_expression()?, &self.context);
let body = self.parse_block()?;
Ok(Statement::While { condition, body })
}
fn parse_defer(&mut self) -> Result<Statement> {
self.advance();
let inner = if self.is_statement_start() {
let mut statements = self.parse_statement()?;
if statements.len() == 1 {
statements.remove(0)
} else {
return Err(Error {
message: "defer does not support multi-assignment".into(),
span: Some(self.span()),
});
}
} else {
let expression = self.parse_expression()?;
self.expect(Token::Semicolon)?;
Statement::Expression(expression)
};
Ok(Statement::Defer(Box::new(inner)))
}
fn parse_let(&mut self, binding: Binding) -> Result<Vec<Statement>> {
self.advance();
let name = self.expect_identifier()?;
let start_line = self.span().line;
if self.at(&Token::Comma) {
return self.parse_multi_let(binding, name);
}
let (declared_type, value) = if self.at(&Token::Colon) {
self.advance();
let declared = self.parse_type_expression()?;
self.expect(Token::Equal)?;
let value = auto_deref(self.parse_expression()?, &self.context);
(Some(declared), value)
} else {
self.expect(Token::Equal)?;
let value = auto_deref(self.parse_expression()?, &self.context);
(None, value)
};
self.expect(Token::Semicolon)?;
let inner_type = declared_type
.clone()
.unwrap_or_else(|| value.resolved_type.clone());
self.context
.define_variable(name.clone(), wrap_binding_type(binding, inner_type));
if matches!(binding, Binding::Variable | Binding::Reference) {
self.context.mark_auto_ref(&name);
}
Ok(vec![Statement::Let {
name,
binding,
declared_type,
value,
line: start_line,
}])
}
fn parse_multi_let(&mut self, binding: Binding, first_name: String) -> Result<Vec<Statement>> {
let mut names = vec![first_name];
while self.at(&Token::Comma) {
self.advance();
names.push(self.expect_identifier()?);
}
self.expect(Token::Equal)?;
let mut values = vec![auto_deref(self.parse_expression()?, &self.context)];
while self.at(&Token::Comma) {
self.advance();
values.push(auto_deref(self.parse_expression()?, &self.context));
}
self.expect(Token::Semicolon)?;
if names.len() != values.len() {
return Err(Error {
message: format!(
"multi-let: {} names but {} values",
names.len(),
values.len()
),
span: Some(self.span()),
});
}
let mut statements = Vec::new();
for (name, value) in names.into_iter().zip(values) {
let inner_type = value.resolved_type.clone();
self.context
.define_variable(name.clone(), wrap_binding_type(binding, inner_type));
if matches!(binding, Binding::Variable | Binding::Reference) {
self.context.mark_auto_ref(&name);
}
statements.push(Statement::Let {
name,
binding,
declared_type: None,
value,
line: self.span().line,
});
}
Ok(statements)
}
fn parse_return(&mut self) -> Result<Statement> {
self.advance();
if self.at(&Token::Semicolon) {
self.advance();
return Ok(Statement::Return(None));
}
let value = auto_deref(self.parse_expression()?, &self.context);
self.expect(Token::Semicolon)?;
Ok(Statement::Return(Some(value)))
}
fn parse_label(&mut self) -> Result<Statement> {
self.advance();
let name = self.expect_identifier()?;
let mut parameters = Vec::new();
let mut initial_arguments = Vec::new();
if self.at(&Token::LeftParen) {
self.advance();
if !self.at(&Token::RightParen) {
loop {
let parameter_name = self.expect_identifier()?;
let parameter_type = if self.at(&Token::Colon) {
self.advance();
Some(self.parse_type_expression()?)
} else {
None
};
self.expect(Token::Equal)?;
let init = auto_deref(self.parse_expression()?, &self.context);
let parameter_type =
parameter_type.unwrap_or_else(|| init.resolved_type.clone());
parameters.push(Parameter {
name: parameter_name,
parameter_type,
});
initial_arguments.push(init);
if !self.at(&Token::Comma) {
break;
}
self.advance();
}
}
self.expect(Token::RightParen)?;
}
self.expect(Token::Semicolon)?;
for parameter in ¶meters {
self.context
.define_variable(parameter.name.clone(), parameter.parameter_type.clone());
}
Ok(Statement::Label {
name,
parameters,
initial_arguments,
})
}
fn parse_jump(&mut self) -> Result<Statement> {
self.advance();
let label = self.expect_identifier()?;
let mut arguments = Vec::new();
if self.at(&Token::LeftParen) {
self.advance();
if !self.at(&Token::RightParen) {
arguments.push(auto_deref(self.parse_expression()?, &self.context));
while self.at(&Token::Comma) {
self.advance();
arguments.push(auto_deref(self.parse_expression()?, &self.context));
}
}
self.expect(Token::RightParen)?;
}
self.expect(Token::Semicolon)?;
Ok(Statement::Jump { label, arguments })
}
}