use super::*;
use leo_errors::{ParserError, ParserWarning, Result};
use leo_span::sym;
const ASSIGN_TOKENS: &[Token] = &[
Token::Assign,
Token::AddAssign,
Token::SubAssign,
Token::MulAssign,
Token::DivAssign,
Token::RemAssign,
Token::PowAssign,
Token::OrAssign,
Token::AndAssign,
Token::BitAndAssign,
Token::BitOrAssign,
Token::BitXorAssign,
Token::ShrAssign,
Token::ShlAssign,
];
impl<N: Network> ParserContext<'_, N> {
pub(crate) fn parse_statement(&mut self) -> Result<Statement> {
match &self.token.token {
Token::Return => Ok(Statement::Return(self.parse_return_statement()?)),
Token::If => Ok(Statement::Conditional(self.parse_conditional_statement()?)),
Token::For => Ok(Statement::Iteration(Box::new(self.parse_loop_statement()?))),
Token::Assert | Token::AssertEq | Token::AssertNeq => Ok(self.parse_assert_statement()?),
Token::Let => Ok(Statement::Definition(self.parse_definition_statement()?)),
Token::Const => Ok(Statement::Const(self.parse_const_declaration_statement()?)),
Token::LeftCurly => Ok(Statement::Block(self.parse_block()?)),
Token::Console => Err(ParserError::console_statements_are_not_yet_supported(self.token.span).into()),
_ => Ok(self.parse_assign_statement()?),
}
}
fn parse_assert_statement(&mut self) -> Result<Statement> {
let is_assert = self.check(&Token::Assert);
let is_assert_eq = self.check(&Token::AssertEq);
let is_assert_neq = self.check(&Token::AssertNeq);
let span = self.expect_any(&[Token::Assert, Token::AssertEq, Token::AssertNeq])?;
self.expect(&Token::LeftParen)?;
let variant = match (is_assert, is_assert_eq, is_assert_neq) {
(true, false, false) => AssertVariant::Assert(self.parse_expression()?),
(false, true, false) => AssertVariant::AssertEq(self.parse_expression()?, {
self.expect(&Token::Comma)?;
self.parse_expression()?
}),
(false, false, true) => AssertVariant::AssertNeq(self.parse_expression()?, {
self.expect(&Token::Comma)?;
self.parse_expression()?
}),
_ => unreachable!("The call the `expect_any` ensures that only one of the three tokens is true."),
};
self.expect(&Token::RightParen)?;
self.expect(&Token::Semicolon)?;
Ok(Statement::Assert(AssertStatement { variant, span, id: self.node_builder.next_id() }))
}
fn parse_assign_statement(&mut self) -> Result<Statement> {
let place = self.parse_expression()?;
if self.eat_any(ASSIGN_TOKENS) {
let operation = match &self.prev_token.token {
Token::Assign => None,
Token::AddAssign => Some(BinaryOperation::Add),
Token::SubAssign => Some(BinaryOperation::Sub),
Token::MulAssign => Some(BinaryOperation::Mul),
Token::DivAssign => Some(BinaryOperation::Div),
Token::RemAssign => Some(BinaryOperation::Rem),
Token::PowAssign => Some(BinaryOperation::Pow),
Token::OrAssign => Some(BinaryOperation::Or),
Token::AndAssign => Some(BinaryOperation::And),
Token::BitAndAssign => Some(BinaryOperation::BitwiseAnd),
Token::BitOrAssign => Some(BinaryOperation::BitwiseOr),
Token::BitXorAssign => Some(BinaryOperation::Xor),
Token::ShrAssign => Some(BinaryOperation::Shr),
Token::ShlAssign => Some(BinaryOperation::Shl),
_ => unreachable!("`parse_assign_statement` shouldn't produce this"),
};
let value = self.parse_expression()?;
self.expect(&Token::Semicolon)?;
let span = place.span() + value.span();
let mut left = place.clone();
left.set_id(self.node_builder.next_id());
let value = match operation {
None => value,
Some(op) => Expression::Binary(BinaryExpression {
left: Box::new(left),
right: Box::new(value),
op,
span,
id: self.node_builder.next_id(),
}),
};
Ok(Statement::Assign(Box::new(AssignStatement { span, place, value, id: self.node_builder.next_id() })))
} else {
if let Expression::Call(call_expression) = &place {
match *call_expression.function {
Expression::Identifier(Identifier { name: sym::decrement, .. }) => {
self.emit_warning(ParserWarning::deprecated(
"decrement",
"Use `Mapping::{get, get_or_use, set, remove, contains}` for manipulating on-chain mappings.",
place.span(),
));
}
Expression::Identifier(Identifier { name: sym::increment, .. }) => {
self.emit_warning(ParserWarning::deprecated(
"increment",
"Use `Mapping::{get, get_or_use, set, remove, contains}` for manipulating on-chain mappings.",
place.span(),
));
}
_ => (),
}
}
let end = self.expect(&Token::Semicolon)?;
Ok(Statement::Expression(ExpressionStatement {
span: place.span() + end,
expression: place,
id: self.node_builder.next_id(),
}))
}
}
pub(super) fn parse_block(&mut self) -> Result<Block> {
self.parse_list(Delimiter::Brace, None, |p| p.parse_statement().map(Some)).map(|(statements, _, span)| Block {
statements,
span,
id: self.node_builder.next_id(),
})
}
fn parse_return_statement(&mut self) -> Result<ReturnStatement> {
let start = self.expect(&Token::Return)?;
let expression = match self.token.token {
Token::Semicolon => {
Expression::Unit(UnitExpression { span: self.token.span, id: self.node_builder.next_id() })
}
_ => self.parse_expression()?,
};
let end = self.expect(&Token::Semicolon)?;
let span = start + end;
Ok(ReturnStatement { span, expression, id: self.node_builder.next_id() })
}
fn parse_conditional_statement(&mut self) -> Result<ConditionalStatement> {
let start = self.expect(&Token::If)?;
self.disallow_struct_construction = true;
let expr = self.parse_conditional_expression()?;
self.disallow_struct_construction = false;
let body = self.parse_block()?;
let next = if self.eat(&Token::Else) {
let s = self.parse_statement()?;
if !matches!(s, Statement::Block(_) | Statement::Conditional(_)) {
self.emit_err(ParserError::unexpected_statement(&s, "Block or Conditional", s.span()));
}
Some(Box::new(s))
} else {
None
};
Ok(ConditionalStatement {
span: start + next.as_ref().map(|x| x.span()).unwrap_or(body.span),
condition: expr,
then: body,
otherwise: next,
id: self.node_builder.next_id(),
})
}
fn parse_loop_statement(&mut self) -> Result<IterationStatement> {
let start_span = self.expect(&Token::For)?;
let ident = self.expect_identifier()?;
self.expect(&Token::Colon)?;
let type_ = self.parse_type()?;
self.expect(&Token::In)?;
let start = self.parse_expression()?;
self.expect(&Token::DotDot)?;
self.disallow_struct_construction = true;
let stop = self.parse_conditional_expression()?;
self.disallow_struct_construction = false;
let block = self.parse_block()?;
Ok(IterationStatement {
span: start_span + block.span,
variable: ident,
type_: type_.0,
start,
start_value: Default::default(),
stop,
stop_value: Default::default(),
inclusive: false,
block,
id: self.node_builder.next_id(),
})
}
#[allow(dead_code)]
fn parse_console_statement(&mut self) -> Result<ConsoleStatement> {
let keyword = self.expect(&Token::Console)?;
self.expect(&Token::Dot)?;
let identifier = self.expect_identifier()?;
let (span, function) = match identifier.name {
sym::assert => {
self.expect(&Token::LeftParen)?;
let expr = self.parse_expression()?;
self.expect(&Token::RightParen)?;
(keyword + expr.span(), ConsoleFunction::Assert(expr))
}
sym::assert_eq => {
self.expect(&Token::LeftParen)?;
let left = self.parse_expression()?;
self.expect(&Token::Comma)?;
let right = self.parse_expression()?;
self.expect(&Token::RightParen)?;
(left.span() + right.span(), ConsoleFunction::AssertEq(left, right))
}
sym::assert_neq => {
self.expect(&Token::LeftParen)?;
let left = self.parse_expression()?;
self.expect(&Token::Comma)?;
let right = self.parse_expression()?;
self.expect(&Token::RightParen)?;
(left.span() + right.span(), ConsoleFunction::AssertNeq(left, right))
}
symbol => {
self.emit_err(ParserError::unexpected_ident(
symbol,
&["assert", "assert_eq", "assert_neq"],
identifier.span,
));
(
Default::default(),
ConsoleFunction::Assert(Expression::Err(ErrExpression {
span: Default::default(),
id: self.node_builder.next_id(),
})),
)
}
};
self.expect(&Token::Semicolon)?;
Ok(ConsoleStatement { span: keyword + span, function, id: self.node_builder.next_id() })
}
pub(super) fn parse_const_declaration_statement(&mut self) -> Result<ConstDeclaration> {
self.expect(&Token::Const)?;
let decl_span = self.prev_token.span;
let (place, type_, _) = self.parse_typed_ident()?;
self.expect(&Token::Assign)?;
let value = self.parse_expression()?;
self.expect(&Token::Semicolon)?;
Ok(ConstDeclaration { span: decl_span + value.span(), place, type_, value, id: self.node_builder.next_id() })
}
pub(super) fn parse_definition_statement(&mut self) -> Result<DefinitionStatement> {
self.expect(&Token::Let)?;
let decl_span = self.prev_token.span;
let decl_type = match &self.prev_token.token {
Token::Let => DeclarationType::Let,
_ => unreachable!("parse_definition_statement_ shouldn't produce this"),
};
let place = self.parse_expression()?;
self.expect(&Token::Colon)?;
let type_ = self.parse_type()?.0;
self.expect(&Token::Assign)?;
let value = self.parse_expression()?;
self.expect(&Token::Semicolon)?;
Ok(DefinitionStatement {
span: decl_span + value.span(),
declaration_type: decl_type,
place,
type_,
value,
id: self.node_builder.next_id(),
})
}
}