val 0.3.6

An arbitrary precision calculator language
Documentation
use super::*;

#[derive(Debug, Clone)]
pub enum Program<'a> {
  Statements(Vec<Spanned<Statement<'a>>>),
}

impl Display for Program<'_> {
  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    match self {
      Program::Statements(statements) => {
        write!(
          f,
          "statements({})",
          statements
            .iter()
            .map(|s| s.0.to_string())
            .collect::<Vec<_>>()
            .join(", ")
        )
      }
    }
  }
}

impl Program<'_> {
  pub fn kind(&self) -> String {
    String::from(match self {
      Program::Statements(_) => "statements",
    })
  }
}

#[derive(Debug, Clone)]
pub enum Statement<'a> {
  Assignment(Spanned<Expression<'a>>, Spanned<Expression<'a>>),
  Block(Vec<Spanned<Statement<'a>>>),
  Break,
  Continue,
  Expression(Spanned<Expression<'a>>),
  Function(&'a str, Vec<&'a str>, Vec<Spanned<Statement<'a>>>),
  If(
    Spanned<Expression<'a>>,
    Vec<Spanned<Statement<'a>>>,
    Option<Vec<Spanned<Statement<'a>>>>,
  ),
  Loop(Vec<Spanned<Statement<'a>>>),
  Return(Option<Spanned<Expression<'a>>>),
  While(Spanned<Expression<'a>>, Vec<Spanned<Statement<'a>>>),
}

impl Display for Statement<'_> {
  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    match self {
      Statement::Assignment(lhs, rhs) => {
        write!(f, "assignment({}, {})", lhs.0, rhs.0)
      }
      Statement::Block(statements) => {
        write!(
          f,
          "block({})",
          statements
            .iter()
            .map(|s| s.0.to_string())
            .collect::<Vec<_>>()
            .join(", ")
        )
      }
      Statement::Break => write!(f, "break"),
      Statement::Continue => write!(f, "continue"),
      Statement::Expression(expression) => {
        write!(f, "expression({})", expression.0)
      }
      Statement::Function(name, params, body) => {
        write!(
          f,
          "function({}, [{}], block({}))",
          name,
          params.join(", "),
          body
            .iter()
            .map(|s| s.0.to_string())
            .collect::<Vec<_>>()
            .join(", ")
        )
      }
      Statement::If(condition, then_branch, else_branch) => {
        let then_str = then_branch
          .iter()
          .map(|s| s.0.to_string())
          .collect::<Vec<_>>()
          .join(", ");

        match else_branch {
          Some(else_statements) => {
            write!(
              f,
              "if({}, block({}), block({}))",
              condition.0,
              then_str,
              else_statements
                .iter()
                .map(|s| s.0.to_string())
                .collect::<Vec<_>>()
                .join(", ")
            )
          }
          None => {
            write!(f, "if({}, block({}))", condition.0, then_str)
          }
        }
      }
      Statement::Loop(body) => {
        write!(
          f,
          "loop(block({}))",
          body
            .iter()
            .map(|s| s.0.to_string())
            .collect::<Vec<_>>()
            .join(", ")
        )
      }
      Statement::Return(expr) => match expr {
        Some(expression) => write!(f, "return({})", expression.0),
        None => write!(f, "return()"),
      },
      Statement::While(condition, body) => {
        write!(
          f,
          "while({}, block({}))",
          condition.0,
          body
            .iter()
            .map(|s| s.0.to_string())
            .collect::<Vec<_>>()
            .join(", ")
        )
      }
    }
  }
}

impl Statement<'_> {
  pub fn kind(&self) -> String {
    String::from(match self {
      Statement::Assignment(_, _) => "assignment",
      Statement::Block(_) => "block",
      Statement::Break => "break",
      Statement::Continue => "continue",
      Statement::Expression(_) => "expression",
      Statement::Function(_, _, _) => "function",
      Statement::If(_, _, _) => "if",
      Statement::Loop(_) => "loop",
      Statement::Return(_) => "return",
      Statement::While(_, _) => "while",
    })
  }
}

#[derive(Debug, Clone)]
pub enum UnaryOp {
  Negate,
  Not,
}

impl Display for UnaryOp {
  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    match self {
      UnaryOp::Negate => write!(f, "-"),
      UnaryOp::Not => write!(f, "!"),
    }
  }
}

#[derive(Debug, Clone)]
pub enum BinaryOp {
  Add,
  Divide,
  Equal,
  GreaterThan,
  GreaterThanEqual,
  LessThan,
  LessThanEqual,
  LogicalAnd,
  LogicalOr,
  Modulo,
  Multiply,
  NotEqual,
  Power,
  Subtract,
}

impl Display for BinaryOp {
  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    match self {
      BinaryOp::Add => write!(f, "+"),
      BinaryOp::Divide => write!(f, "/"),
      BinaryOp::Equal => write!(f, "=="),
      BinaryOp::GreaterThan => write!(f, ">"),
      BinaryOp::GreaterThanEqual => write!(f, ">="),
      BinaryOp::LessThan => write!(f, "<"),
      BinaryOp::LessThanEqual => write!(f, "<="),
      BinaryOp::LogicalAnd => write!(f, "&&"),
      BinaryOp::LogicalOr => write!(f, "||"),
      BinaryOp::Modulo => write!(f, "%"),
      BinaryOp::Multiply => write!(f, "*"),
      BinaryOp::NotEqual => write!(f, "!="),
      BinaryOp::Power => write!(f, "^"),
      BinaryOp::Subtract => write!(f, "-"),
    }
  }
}

#[derive(Debug, Clone)]
pub enum Expression<'a> {
  BinaryOp(BinaryOp, Box<Spanned<Self>>, Box<Spanned<Self>>),
  Boolean(bool),
  FunctionCall(&'a str, Vec<Spanned<Self>>),
  Identifier(&'a str),
  List(Vec<Spanned<Self>>),
  ListAccess(Box<Spanned<Self>>, Box<Spanned<Self>>),
  Null,
  Number(Float),
  String(&'a str),
  UnaryOp(UnaryOp, Box<Spanned<Self>>),
}

impl Display for Expression<'_> {
  fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result {
    match self {
      Expression::BinaryOp(op, lhs, rhs) => {
        write!(f, "binary_op({}, {}, {})", op, lhs.0, rhs.0)
      }
      Expression::Boolean(boolean) => write!(f, "boolean({})", boolean),
      Expression::FunctionCall(name, arguments) => {
        write!(
          f,
          "function_call({},{})",
          name,
          arguments
            .iter()
            .map(|a| a.0.to_string())
            .collect::<Vec<_>>()
            .join(", ")
        )
      }
      Expression::Identifier(identifier) => {
        write!(f, "identifier({})", identifier)
      }
      Expression::List(list) => {
        write!(
          f,
          "list({})",
          list
            .iter()
            .map(|item| item.0.to_string())
            .collect::<Vec<_>>()
            .join(", ")
        )
      }
      Expression::ListAccess(list, index) => {
        write!(f, "list_access({}, {})", list.0, index.0)
      }
      Expression::Null => write!(f, "null"),
      Expression::Number(number) => write!(f, "number({})", number.display()),
      Expression::String(string) => write!(f, "string(\"{}\")", string),
      Expression::UnaryOp(op, expr) => {
        write!(f, "unary_op({}, {})", op, expr.0)
      }
    }
  }
}

impl Expression<'_> {
  pub fn kind(&self) -> String {
    String::from(match self {
      Expression::BinaryOp(_, _, _) => "binary_op",
      Expression::Boolean(_) => "boolean",
      Expression::FunctionCall(_, _) => "function_call",
      Expression::Identifier(_) => "identifier",
      Expression::List(_) => "list",
      Expression::ListAccess(_, _) => "list_access",
      Expression::Null => "null",
      Expression::Number(_) => "number",
      Expression::String(_) => "string",
      Expression::UnaryOp(_, _) => "unary_op",
    })
  }
}