alpha-shell 0.3.0

A transpiler for the AlphaShell language
use super::{
  error::{Error, ParserResult},
  node::Node,
  parse_helper::ParseHelper,
  value,
};
use crate::{check_token, types::TT};

#[derive(Debug, PartialEq, Eq, Clone)]
pub enum Type {
  Let,
  Export,
}

#[derive(Debug, PartialEq, Clone)]
pub struct Declaration {
  pub r#type: Type,
  pub name: String,
  pub value: Box<Node>,
}

impl Declaration {
  pub fn new(r#type: Type, name: String, value: Box<Node>) -> Self {
    Self {
      r#type,
      name,
      value,
    }
  }
}

pub fn parse(ph: &mut ParseHelper) -> ParserResult<Node> {
  check_token!(ph, TT::Let | TT::Export);

  let r#type = match ph.peek(0) {
    Some(TT::Let) => Type::Let,
    Some(TT::Export) => Type::Export,
    Some(_) => return Err(Error::unexpected(ph)),
    None => return Err(Error::end(ph)),
  };

  ph.advance();

  let name = match ph.peek(0) {
    Some(TT::Identifier(name)) => name.clone(),
    Some(_) => return Err(Error::unexpected(ph)),
    None => return Err(Error::end(ph)),
  };

  if ph.variables.get(&name).is_some() {
    return Err(Error::duplicate_variable(ph));
  }

  ph.variables.insert(name.clone());
  if r#type == Type::Export {
    ph.exports.insert(name.clone());
  }

  ph.advance();

  check_token!(ph, TT::Assignment);

  ph.advance();

  let value = value::parse(ph)?;

  check_token!(ph, TT::Semicolon);

  ph.advance();

  let declaration = Node::Declaration(Declaration::new(r#type, name, Box::new(value)));

  Ok(declaration)
}