oonta 0.1.0

OCaml to LLVM IR compiler front-end
Documentation
mod ast_printer;

use std::{cell::RefCell, rc::Rc};

use crate::{ast::ast_printer::AstPrinter, lexer::Lexer, symbol::Span};

pub struct Ast {
    pub binds: Vec<Bind>,
}

pub struct Bind {
    pub name: Option<Span>,
    pub expr: Rc<RefCell<Expr>>,
}

pub enum Expr {
    Literal(LiteralExpr),
    Var(VarExpr),
    Fun(FunExpr),
    Application(ApplicationExpr),
    LetIn(LetInExpr),
    BinOp(BinOpExpr),
    Conditional(CondExpr),
}

pub enum LiteralExpr {
    Integer(i32, Span),
    Unit(Span),
}

pub struct VarExpr {
    pub id: Span,
}

pub struct FunExpr {
    pub params: Vec<Span>,
    pub body: Rc<RefCell<Expr>>,
    pub captures: Vec<String>,
    pub recursive_bind: Option<String>,
    pub span: Span,
}

pub struct ApplicationExpr {
    pub fun: Rc<RefCell<Expr>>,
    pub binds: Vec<Rc<RefCell<Expr>>>,
    pub span: Span,
}

pub struct LetInExpr {
    pub bind: (Span, Rc<RefCell<Expr>>),
    pub expr: Rc<RefCell<Expr>>,
    pub span: Span,
}

pub struct BinOpExpr {
    pub op: Operator,
    pub lhs: Rc<RefCell<Expr>>,
    pub rhs: Rc<RefCell<Expr>>,
    pub span: Span,
}

pub struct CondExpr {
    pub cond: Rc<RefCell<Expr>>,
    pub yes: Rc<RefCell<Expr>>,
    pub no: Rc<RefCell<Expr>>,
    pub span: Span,
}

#[derive(Copy, Clone)]
pub enum Operator {
    Plus,
    Minus,
    Star,
    Slash,
    Eq,
    Lte,
    Lt,
    Gte,
    Gt,
}

impl From<Bind> for Ast {
    fn from(bind: Bind) -> Self {
        Self { binds: vec![bind] }
    }
}

impl Ast {
    pub fn append(&mut self, bind: Bind) {
        self.binds.push(bind);
    }
}

impl Expr {
    pub fn span(&self) -> &Span {
        match self {
            Expr::Literal(LiteralExpr::Integer(_, span)) => span,
            Expr::Literal(LiteralExpr::Unit(span)) => span,
            Expr::Var(VarExpr { id }) => id,
            Expr::Fun(FunExpr { span, .. }) => span,
            Expr::Application(ApplicationExpr { span, .. }) => span,
            Expr::LetIn(LetInExpr { span, .. }) => span,
            Expr::BinOp(BinOpExpr { span, .. }) => span,
            Expr::Conditional(CondExpr { span, .. }) => span,
        }
    }

    pub fn integer(value: i32, span: Span) -> Self {
        Self::Literal(LiteralExpr::Integer(value, span.clone()))
    }

    pub fn var(span: Span) -> Self {
        Self::Var(VarExpr { id: span })
    }

    pub fn fun(
        params: Vec<Span>,
        body: Rc<RefCell<Expr>>,
        captures: Vec<String>,
        recursive_bind: Option<String>,
        span: Span,
    ) -> Self {
        Self::Fun(FunExpr {
            params,
            body,
            captures,
            recursive_bind,
            span,
        })
    }

    pub fn binop(op: Operator, lhs: Rc<RefCell<Expr>>, rhs: Rc<RefCell<Expr>>, span: Span) -> Self {
        Self::BinOp(BinOpExpr { op, lhs, rhs, span })
    }
}

impl Ast {
    pub fn pretty_print(&self, lexer: &Lexer) {
        let printer = AstPrinter::new(lexer);
        printer.pretty_print(self);
    }
}

impl ApplicationExpr {
    pub fn pretty_print(&self, lexer: &Lexer) {
        let mut printer = AstPrinter::new(lexer);
        printer.pretty_print_application_expr(self);
    }
}

impl std::fmt::Display for Operator {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            Operator::Plus => write!(f, "+"),
            Operator::Minus => write!(f, "-"),
            Operator::Star => write!(f, "*"),
            Operator::Slash => write!(f, "/"),
            Operator::Eq => write!(f, "="),
            Operator::Lte => write!(f, "<="),
            Operator::Lt => write!(f, "<"),
            Operator::Gte => write!(f, ">="),
            Operator::Gt => write!(f, ">"),
        }
    }
}