use std::rc::Rc;
#[derive(Debug)]
pub(crate) enum Node {
Expr(Expr),
Stmt(Stmt),
}
#[derive(Debug)]
pub(crate) enum Stmt {
Let(Let),
Return(Return),
}
#[derive(Debug)]
pub(crate) struct Let {
pub(crate) pos: usize,
pub(crate) ident: Ident,
pub(crate) value: Expr,
}
#[derive(Debug)]
pub(crate) struct Return {
pub(crate) pos: usize,
pub(crate) value: Option<Expr>,
}
#[derive(Debug)]
pub(crate) enum Expr {
Int(Int),
Bool(Bool),
Str(Str),
Seq(Seq),
Map(Map),
Ident(Ident),
Index(Box<Index>),
Unary(Box<Unary>),
Binary(Box<Binary>),
Closure(Rc<Closure>),
Call(Box<Call>),
If(Box<If>),
}
#[derive(Debug)]
pub(crate) struct Int {
pub(crate) pos: usize,
pub(crate) value: i32,
}
#[derive(Debug)]
pub(crate) struct Bool {
pub(crate) pos: usize,
pub(crate) value: bool,
}
#[derive(Debug)]
pub(crate) struct Str {
pos: usize,
value: Rc<str>,
}
#[derive(Debug)]
pub(crate) struct Seq {
pub(crate) pos: usize,
pub(crate) elements: Box<[Expr]>,
}
#[derive(Debug)]
pub(crate) struct Map {
pub(crate) pos: usize,
pub(crate) entries: Box<[(Expr, Expr)]>,
}
#[derive(Clone, Debug)]
pub(crate) struct Ident {
pos: usize,
sym: Rc<str>,
}
#[derive(Debug)]
pub(crate) struct Index {
pub(crate) pos: usize,
pub(crate) base: Expr,
pub(crate) subscript: Expr,
}
#[derive(Debug)]
pub(crate) struct Unary {
pub(crate) pos: usize,
pub(crate) op: UnaryOp,
pub(crate) value: Expr,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum UnaryOp {
Neg,
Not,
}
#[derive(Debug)]
pub(crate) struct Binary {
pub(crate) pos: usize,
pub(crate) left: Expr,
pub(crate) op: BinaryOp,
pub(crate) right: Expr,
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(crate) enum BinaryOp {
Add,
Sub,
Mul,
Div,
Eq,
Ne,
Lt,
Le,
Gt,
Ge,
}
#[derive(Debug)]
pub(crate) struct Closure {
pub(crate) pos: usize,
pub(crate) parameters: Box<[Ident]>,
pub(crate) body: Block,
}
#[derive(Debug)]
pub(crate) struct Block {
pub(crate) pos: usize,
pub(crate) nodes: Box<[Node]>,
}
#[derive(Debug)]
pub(crate) struct Call {
pub(crate) pos: usize,
pub(crate) target: Expr,
pub(crate) args: Box<[Expr]>,
}
#[derive(Debug)]
pub(crate) struct If {
pub(crate) pos: usize,
pub(crate) condition: Expr,
pub(crate) consequence: Block,
pub(crate) alternative: Option<Block>,
}
impl Expr {
pub(crate) fn pos(&self) -> usize {
match self {
Self::Int(expr) => expr.pos,
Self::Bool(expr) => expr.pos,
Self::Str(expr) => expr.pos,
Self::Seq(expr) => expr.pos,
Self::Map(expr) => expr.pos,
Self::Ident(expr) => expr.pos,
Self::Index(expr) => expr.pos,
Self::Unary(expr) => expr.pos,
Self::Binary(expr) => expr.pos,
Self::Closure(expr) => expr.pos,
Self::Call(expr) => expr.pos,
Self::If(expr) => expr.pos,
}
}
}
impl Ident {
pub(crate) fn from_str(pos: usize, sym: &str) -> Self {
Self {
pos,
sym: sym.into(),
}
}
#[cfg(test)]
pub(crate) fn test(sym: &str) -> Self {
Self {
pos: 0,
sym: sym.into(),
}
}
pub(crate) fn pos(&self) -> usize {
self.pos
}
pub(crate) fn sym(&self) -> &str {
&self.sym
}
pub(crate) fn sym_rc_str(&self) -> &Rc<str> {
&self.sym
}
}
impl Str {
pub(crate) fn from_src(pos: usize, value: &str) -> Self {
Self {
pos,
value: value.into(),
}
}
pub(crate) fn value(&self) -> &str {
&self.value
}
pub(crate) fn value_rc_str(&self) -> &Rc<str> {
&self.value
}
}
impl std::fmt::Display for Ident {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
self.sym.fmt(f)
}
}
impl std::fmt::Display for UnaryOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
use std::fmt::Write;
f.write_char(match self {
Self::Neg => '-',
Self::Not => '!',
})
}
}
impl std::fmt::Display for BinaryOp {
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
f.write_str(match self {
Self::Add => "+",
Self::Sub => "-",
Self::Mul => "*",
Self::Div => "/",
Self::Lt => "<",
Self::Le => "<=",
Self::Gt => ">",
Self::Ge => ">=",
Self::Eq => "==",
Self::Ne => "!=",
})
}
}