1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
use crate::operator::{BinaryOperator, UnaryOperator};
use crate::{interner::Symbol, location::Location, operator::TernaryOperator};

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Stmt {
    Assign {
        var: Symbol,
        value: Expr,
        location: Location,
    },
    Print {
        values: Vec<Expr>,
        newline: bool,
        wait: bool,
        location: Location,
    },
    If {
        arms: Vec<(Expr, Vec<Stmt>, Location)>,
        other: Vec<Stmt>,
        other_location: Location,
    },
    While {
        cond: Expr,
        body: Vec<Stmt>,
        location: Location,
    },
    Expression {
        expr: Expr,
        location: Location,
    },
    Exit {
        location: Location,
    },
}

impl Stmt {
    pub fn location(&self) -> Location {
        match self {
            Stmt::Assign { location, .. }
            | Stmt::Print { location, .. }
            | Stmt::While { location, .. }
            | Stmt::Expression { location, .. }
            | Stmt::Exit { location } => *location,
            Stmt::If { arms, .. } => arms[0].2,
        }
    }

    pub fn is_block(&self) -> bool {
        match self {
            Stmt::If { .. } | Stmt::While { .. } => true,
            Stmt::Assign { .. }
            | Stmt::Print { .. }
            | Stmt::Expression { .. }
            | Stmt::Exit { .. } => false,
        }
    }
}

#[derive(Clone, Debug, Eq, PartialEq)]
pub enum Expr {
    Number(u32),
    String(Symbol),
    Variable(Symbol),
    BuiltinFunc {
        name: Symbol,
        args: Vec<Expr>,
    },

    Nop(Box<Expr>),

    UnaryOp {
        value: Box<Expr>,
        op: UnaryOperator,
    },

    BinaryOp {
        lhs: Box<Expr>,
        rhs: Box<Expr>,
        op: BinaryOperator,
    },

    TernaryOp {
        lhs: Box<Expr>,
        mhs: Box<Expr>,
        rhs: Box<Expr>,
        op: TernaryOperator,
    },
}

impl Expr {
    pub fn unary_op(self, op: UnaryOperator) -> Self {
        Expr::UnaryOp {
            value: Box::new(self),
            op,
        }
    }

    pub fn binary_op(self, rhs: Self, op: BinaryOperator) -> Self {
        Expr::BinaryOp {
            lhs: Box::new(self),
            rhs: Box::new(rhs),
            op,
        }
    }

    pub fn ternary_op(self, mhs: Self, rhs: Self, op: TernaryOperator) -> Self {
        Expr::TernaryOp {
            lhs: Box::new(self),
            mhs: Box::new(mhs),
            rhs: Box::new(rhs),
            op,
        }
    }
}