use std::{collections::HashMap, fmt};
use self::comparison::ComparisonStatement;
pub use self::{thing::Thing, type_::Type};
use crate::{
common::{identifier::Identifier, token, Span, Spanned},
expression::Expression,
pretty::{indent, Pretty},
util::write_joined,
variable::Variable,
};
pub mod comparison;
pub mod thing;
pub mod type_;
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Is {
pub span: Option<Span>,
pub lhs: Variable,
pub rhs: Variable,
}
impl Is {
pub(crate) fn new(span: Option<Span>, lhs: Variable, rhs: Variable) -> Self {
Self { span, lhs, rhs }
}
}
impl Spanned for Is {
fn span(&self) -> Option<Span> {
self.span
}
}
impl Pretty for Is {}
impl fmt::Display for Is {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {} {}", self.lhs, token::Keyword::Is, self.rhs)
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct InIterable {
pub span: Option<Span>,
pub lhs: Vec<Variable>,
pub rhs: Expression,
}
impl InIterable {
pub(crate) fn new(span: Option<Span>, lhs: Vec<Variable>, rhs: Expression) -> Self {
Self { span, lhs, rhs }
}
}
impl Spanned for InIterable {
fn span(&self) -> Option<Span> {
self.span
}
}
impl Pretty for InIterable {}
impl fmt::Display for InIterable {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} ", token::Keyword::Let)?;
write_joined!(f, ", ", self.lhs)?;
write!(f, " {} {}", token::Keyword::In, self.rhs)?;
Ok(())
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum DeconstructField {
Variable(Variable),
Deconstruct(StructDeconstruct),
}
impl Pretty for DeconstructField {
fn fmt(&self, indent_level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DeconstructField::Variable(var) => Pretty::fmt(var, indent_level, f),
DeconstructField::Deconstruct(struct_deconstruct) => Pretty::fmt(struct_deconstruct, indent_level, f),
}
}
}
impl fmt::Display for DeconstructField {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
DeconstructField::Variable(var) => fmt::Display::fmt(var, f),
DeconstructField::Deconstruct(struct_deconstruct) => fmt::Display::fmt(struct_deconstruct, f),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct StructDeconstruct {
pub span: Option<Span>,
field_map: HashMap<Identifier, DeconstructField>,
}
impl StructDeconstruct {
pub fn new(span: Option<Span>, field_map: HashMap<Identifier, DeconstructField>) -> Self {
Self { span, field_map }
}
}
impl Spanned for StructDeconstruct {
fn span(&self) -> Option<Span> {
self.span
}
}
impl Pretty for StructDeconstruct {
fn fmt(&self, indent_level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
indent(indent_level, f)?;
fmt::Display::fmt(self, f)
}
}
impl fmt::Display for StructDeconstruct {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{}", token::Char::CurlyLeft)?;
for (identifier, field_deconstruct) in &self.field_map {
write!(f, "{}{} {},", identifier, token::Char::Colon, field_deconstruct)?;
}
write!(f, "{}", token::Char::CurlyRight)
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum AssignmentPattern {
Variables(Vec<Variable>),
Deconstruct(StructDeconstruct),
}
impl Pretty for AssignmentPattern {}
impl fmt::Display for AssignmentPattern {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Self::Variables(vars) => write_joined!(f, ", ", vars),
Self::Deconstruct(_) => todo!(),
}
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub struct Assignment {
pub span: Option<Span>,
pub lhs: AssignmentPattern,
pub rhs: Expression,
}
impl Assignment {
pub fn new(span: Option<Span>, lhs: AssignmentPattern, rhs: Expression) -> Self {
Self { span, lhs, rhs }
}
}
impl Spanned for Assignment {
fn span(&self) -> Option<Span> {
self.span
}
}
impl Pretty for Assignment {}
impl fmt::Display for Assignment {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "{} {} = {}", token::Keyword::Let, self.lhs, self.rhs)
}
}
#[derive(Debug, Clone, Eq, PartialEq)]
pub enum Statement {
Is(Is),
InIterable(InIterable),
Comparison(ComparisonStatement),
Assignment(Assignment),
Thing(Thing),
Type(Type),
}
impl Spanned for Statement {
fn span(&self) -> Option<Span> {
match self {
Statement::Is(inner) => inner.span(),
Statement::InIterable(inner) => inner.span(),
Statement::Comparison(inner) => inner.span(),
Statement::Assignment(inner) => inner.span(),
Statement::Thing(inner) => inner.span(),
Statement::Type(inner) => inner.span(),
}
}
}
impl Pretty for Statement {
fn fmt(&self, indent_level: usize, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Statement::Is(inner) => Pretty::fmt(inner, indent_level, f),
Statement::InIterable(inner) => Pretty::fmt(inner, indent_level, f),
Statement::Comparison(inner) => Pretty::fmt(inner, indent_level, f),
Statement::Assignment(inner) => Pretty::fmt(inner, indent_level, f),
Statement::Thing(inner) => Pretty::fmt(inner, indent_level, f),
Statement::Type(inner) => Pretty::fmt(inner, indent_level, f),
}
}
}
impl fmt::Display for Statement {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
match self {
Statement::Is(inner) => fmt::Display::fmt(inner, f),
Statement::InIterable(inner) => fmt::Display::fmt(inner, f),
Statement::Comparison(inner) => fmt::Display::fmt(inner, f),
Statement::Assignment(inner) => fmt::Display::fmt(inner, f),
Statement::Thing(inner) => fmt::Display::fmt(inner, f),
Statement::Type(inner) => fmt::Display::fmt(inner, f),
}
}
}