arrow-parser 0.0.2

Parser for the Arrow programming language
Documentation
use crate::ast::Expression;
use crate::ast::Node;
use crate::ast::Statement;
use crate::error::SyntaxErrorType;
use crate::error::SyntaxResult;
use crate::parse::Parser;
use crate::symbol::ScopeType;
use crate::token::TokenType;
use crate::token::TokenTypeSet;

impl<'a> Parser<'a> {
  pub fn parse_stmt(&mut self, require_semicolon: bool) -> SyntaxResult<Node<Statement>> {
    let stmt = match self.peek()?.typ {
      TokenType::KeywordBreak => self.parse_stmt_break(),
      TokenType::KeywordContinue => self.parse_stmt_continue(),
      TokenType::KeywordFor => self.parse_stmt_for(),
      TokenType::KeywordLet => self.parse_stmt_let(),
      TokenType::KeywordLoop => self.parse_stmt_loop(),
      TokenType::KeywordReturn => self.parse_stmt_return(),
      _ => {
        let expr = self.parse_expr_until(TokenTypeSet::new(&[
          TokenType::Equals,
          TokenType::Semicolon,
          TokenType::BraceClose,
        ]))?;
        let stmt = if self.consume_if(TokenType::Equals)?.is_match() {
          let value = self.parse_expr(TokenType::Semicolon)?;
          self.new_statement(expr.loc + value.loc, match *expr.stx {
            Expression::Field {
              object,
              field,
              optional,
            } => Statement::FieldAssign {
              object,
              field,
              value,
              optional,
            },
            Expression::Index {
              object,
              index,
              optional,
            } => Statement::IndexAssign {
              object,
              index,
              value,
              optional,
            },
            Expression::Var { name } => Statement::VarAssign {
              variable: name,
              value,
            },
            _ => {
              return Err(
                expr
                  .loc
                  .error(SyntaxErrorType::InvalidAssigmentTarget, None),
              )
            }
          })
        } else {
          self.new_statement(expr.loc, Statement::Expression { expression: expr })
        };
        Ok(stmt)
      }
    }?;
    if require_semicolon {
      self.require(TokenType::Semicolon)?;
    };
    Ok(stmt)
  }

  pub fn parse_stmt_break(&mut self) -> SyntaxResult<Node<Statement>> {
    let loc = self.require(TokenType::KeywordBreak)?.loc;
    Ok(self.new_statement(loc, Statement::Break))
  }

  pub fn parse_stmt_continue(&mut self) -> SyntaxResult<Node<Statement>> {
    let loc = self.require(TokenType::KeywordContinue)?.loc;
    Ok(self.new_statement(loc, Statement::Continue))
  }

  pub fn parse_stmt_for(&mut self) -> SyntaxResult<Node<Statement>> {
    let parent_scope = self.enter_new_scope(ScopeType::Block);
    let loc_start = self.require(TokenType::KeywordFor)?.loc;
    let (_, variable) = self.require_identifier_as_string()?;
    assert!(self.scope.add_symbol(variable.clone()));
    self.require(TokenType::KeywordIn)?;
    let iterable = self.parse_expr(TokenType::BraceOpen)?;
    let body = self.parse_expr_block_without_new_scope()?;
    match body.stx.as_ref() {
      Expression::Block {
        result: Some(..), ..
      } => return Err(body.loc.error(SyntaxErrorType::LoopCannotResult, None)),
      _ => {}
    };
    let stmt = self.new_statement(loc_start + body.loc, Statement::For {
      variable,
      iterable,
      body,
    });
    self.return_to_scope(parent_scope);
    Ok(stmt)
  }

  pub fn parse_stmt_let(&mut self) -> SyntaxResult<Node<Statement>> {
    let loc_start = self.require(TokenType::KeywordLet)?.loc;
    let (variable_loc, variable) = self.require_identifier_as_string()?;
    if !self.scope.add_symbol(variable.clone()) {
      return Err(variable_loc.error(SyntaxErrorType::RedeclaredVar, None));
    };
    self.require(TokenType::Equals)?;
    let value = self.parse_expr(TokenType::Semicolon)?;
    Ok(self.new_statement(loc_start + value.loc, Statement::Let { variable, value }))
  }

  pub fn parse_stmt_loop(&mut self) -> SyntaxResult<Node<Statement>> {
    let loc_start = self.require(TokenType::KeywordLoop)?.loc;
    let body = self.parse_expr_block()?;
    match body.stx.as_ref() {
      Expression::Block {
        result: Some(..), ..
      } => return Err(body.loc.error(SyntaxErrorType::LoopCannotResult, None)),
      _ => {}
    };
    Ok(self.new_statement(loc_start + body.loc, Statement::Loop { body }))
  }

  pub fn parse_stmt_return(&mut self) -> SyntaxResult<Node<Statement>> {
    let loc_start = self.require(TokenType::KeywordReturn)?.loc;
    let value = if self.peek()?.typ == TokenType::Semicolon {
      None
    } else {
      Some(self.parse_expr(TokenType::Semicolon)?)
    };
    Ok(self.new_statement(loc_start, Statement::Return { value }))
  }
}