glowdust 0.0.1

A DBMS with a data model based on functions and pattern matching
Documentation
use crate::compiler::parser::lexer::TokenType;
use crate::compiler::parser::pointer::P;
use std::fmt::{Display, Formatter};

#[derive(Debug, PartialEq, Clone)]
pub(crate) enum Stmt {
    Expr(P<Expr>),
    Semi(P<Expr>),
    Match(Vec<P<Atom>>), // this really shouldn't be here, match is above statements because they don't nest
    Return(Vec<P<Expr>>),
    BangBang,
    Empty,
}

impl Display for Stmt {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            Stmt::Expr(_) => {
                write!(f, "ExprStmt")
            }
            Stmt::Semi(_) => {
                write!(f, "SemiStmt")
            }
            Stmt::Match(_) => {
                write!(f, "MatchStmt")
            }
            Stmt::Return(_) => {
                write!(f, "Return")
            }
            Stmt::BangBang => {
                write!(f, "BangBang")
            }
            Stmt::Empty => {
                write!(f, "Empty")
            }
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub(crate) enum ExprKind {
    Tuple(Vec<P<Expr>>),
    Unary(UnaryOpToken, P<Expr>),
    Binary(BinOpToken, P<Expr>, P<Expr>),
    Assignment(P<Expr>, P<Expr>),
    Literal(LiteralToken),
    Variable(u8),
    ValueDiscard,
    FunCall(u8, Vec<NamedParameter>),
    FieldAccess(P<Expr>, u8),
}

impl Display for ExprKind {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            ExprKind::Tuple(_) => {
                write!(f, "Tuple")
            }
            ExprKind::Unary(op, _) => {
                write!(f, "{}", op)
            }
            ExprKind::Binary(op, _, _) => {
                write!(f, "{}", op)
            }
            ExprKind::Assignment(_, _) => {
                write!(f, "Assignment")
            }
            ExprKind::Literal(lit) => {
                write!(f, "{}", lit)
            }
            ExprKind::Variable(id) => {
                write!(f, "var({})", *id)
            }
            ExprKind::ValueDiscard => {
                write!(f, "discard")
            }
            ExprKind::FunCall(name, _) => {
                write!(f, "Call({})", name)
            }
            ExprKind::FieldAccess(_, _) => {
                write!(f, "FieldAccess")
            }
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub(crate) struct Expr {
    pub(crate) kind: ExprKind,
    pub(crate) span: Span,
}

#[derive(Debug, PartialEq, Clone)]
pub(crate) struct Block {
    pub(crate) stmts: Vec<Stmt>,
    pub(crate) span: Span,
}

#[derive(Debug, PartialEq, Clone)]
pub(crate) struct NamedParameter {
    pub(crate) name: Option<u8>,
    pub(crate) value: P<Expr>,
}

#[derive(Debug, PartialEq, Clone)]
pub(crate) struct Atom {
    pub(crate) kind: AtomKind,
    pub(crate) span: Span,
}

#[derive(Debug, PartialEq, Clone)]
pub(crate) enum AtomKind {
    FunCall(u8, Vec<NamedParameter>),
    Map(u8, Vec<NamedParameter>, MapTarget),
    Block(P<Block>),
    Return(Vec<P<Expr>>),
}

impl Display for AtomKind {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            AtomKind::FunCall(name, _) => {
                write!(f, "Call({})", name)
            }
            AtomKind::Map(name, _, map_to) => {
                write!(f, "Map({})->[", name)?;
                match map_to {
                    MapTarget::Tuple(t) => write!(f, "Tuple({})", t.len())?,
                    MapTarget::Type(type_name, _) => write!(f, "Type({})", type_name)?,
                }
                write!(f, "]")?;
                Ok(())
            }
            AtomKind::Block(_) => {
                write!(f, "Block")
            }
            AtomKind::Return(_) => {
                write!(f, "Generate")
            }
        }
    }
}

#[derive(Debug, PartialEq, Clone)]
pub(crate) enum MapTarget {
    Tuple(Vec<P<Expr>>),
    Type(u8, Vec<NamedParameter>),
}

#[derive(Debug, PartialEq, Default, Clone)]
pub(crate) struct FunctionDefinition {
    pub(crate) name: String,
    pub(crate) formal_arguments: Vec<P<Expr>>,
    pub(crate) body: Vec<Stmt>,
}

#[derive(Debug, PartialEq, Default, Clone)]
pub(crate) struct TypeDefinition {
    pub(crate) name: String,
    pub(crate) fields: Vec<TypedVariableDefinition>,
}

impl Display for TypeDefinition {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "type {}:{{", self.name)?;
        for (pos, field) in self.fields.iter().enumerate() {
            write!(f, "({}:{})", field.name, field.type_name)?;
            if pos < self.fields.len() {
                write!(f, ",")?
            }
        }
        Ok(())
    }
}

#[derive(Debug, PartialEq, Default, Clone)]
pub(crate) struct TypedVariableDefinition {
    pub(crate) name: String,
    pub(crate) type_name: TypeName,
}

impl Display for TypedVariableDefinition {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}:{}", self.name, self.type_name)
    }
}

#[derive(Debug, PartialEq, Default, Clone)]
pub(crate) struct TypeName {
    pub(crate) name: String,
}

impl Display for TypeName {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.name)
    }
}

#[derive(Debug, Clone, Copy)]
pub struct Span {
    pub(crate) line: usize,
    pub(crate) offset: usize, // offset in line
    pub(crate) length: usize,
}

impl Display for Span {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        write!(f, "line: {}, position: {}", self.line, self.offset)
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum BinOpToken {
    Plus,
    Minus,
    Star,
    Slash,
    GreaterThan,
    LessThan,
    Equals,
    NotEquals,
    And,
    Or,
}

impl Display for BinOpToken {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            BinOpToken::Plus => {
                write!(f, "Add")
            }
            BinOpToken::Minus => {
                write!(f, "Subtract")
            }
            BinOpToken::Star => {
                write!(f, "Multiply")
            }
            BinOpToken::Slash => {
                write!(f, "Divide")
            }
            BinOpToken::GreaterThan => {
                write!(f, "GreaterThan")
            }
            BinOpToken::LessThan => {
                write!(f, "LessThan")
            }
            BinOpToken::Equals => {
                write!(f, "Equals")
            }
            BinOpToken::NotEquals => {
                write!(f, "NotEquals")
            }
            BinOpToken::And => {
                write!(f, "And")
            }
            BinOpToken::Or => {
                write!(f, "Or")
            }
        }
    }
}

impl TryFrom<TokenType> for BinOpToken {
    type Error = TokenType;

    fn try_from(value: TokenType) -> Result<Self, Self::Error> {
        match value {
            TokenType::Plus => Ok(BinOpToken::Plus),
            TokenType::Minus => Ok(BinOpToken::Minus),
            TokenType::Star => Ok(BinOpToken::Star),
            TokenType::Slash => Ok(BinOpToken::Slash),
            TokenType::GreaterThan => Ok(BinOpToken::GreaterThan),
            TokenType::LessThan => Ok(BinOpToken::LessThan),
            TokenType::EqualsEquals => Ok(BinOpToken::Equals),
            TokenType::BangEquals => Ok(BinOpToken::NotEquals),
            TokenType::AmpAmp => Ok(BinOpToken::And),
            TokenType::PipePipe => Ok(BinOpToken::Or),
            _ => Err(value),
        }
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum UnaryOpToken {
    Bang,
    Minus,
}

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

pub(crate) const DUMMY_SPAN: Span = Span {
    line: 0,
    offset: 0,
    length: 0,
};

impl PartialEq for Span {
    fn eq(&self, other: &Self) -> bool {
        if self.line == DUMMY_SPAN.line && self.offset == DUMMY_SPAN.offset {
            return true;
        }
        if other.line == DUMMY_SPAN.line && other.offset == DUMMY_SPAN.offset {
            return true;
        }
        return self.line == other.line && self.offset == other.offset;
    }
}

#[derive(Debug, PartialEq, Clone, Copy)]
pub enum LiteralToken {
    True,
    False,
    Integer(u8),
    Float(u8),
    StringLiteral(u8),
}

// For actual debugging we need the proper symbol string. That's not available here, but it's better than nothing, for now
impl Display for LiteralToken {
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
        match self {
            LiteralToken::True => Display::fmt("True", f),
            LiteralToken::False => Display::fmt("False", f),
            LiteralToken::Integer(integer) => Display::fmt(integer, f),
            LiteralToken::Float(float) => Display::fmt(float, f),
            LiteralToken::StringLiteral(string) => Display::fmt(string, f),
        }
    }
}