use hercules_ir::ir::{Device, Schedule};

#[derive(Debug, Copy, Clone)]
pub enum Pass {
    AutoOutline,
    CCP,
    CRC,
    DCE,
    DeleteUncalled,
    FloatCollections,
    ForkGuardElim,
    ForkSplit,
    ForkCoalesce,
    Forkify,
    GCM,
    GVN,
    InferSchedules,
    Inline,
    InterproceduralSROA,
    LiftDCMath,
    Outline,
    PhiElim,
    Predication,
    SLF,
    SROA,
    Unforkify,
    WritePredication,
    Verify,
    Xdot,
    Serialize,
}

impl Pass {
    pub fn num_args(&self) -> usize {
        match self {
            Pass::Xdot => 1,
            _ => 0,
        }
    }
}

#[derive(Debug, Clone)]
pub enum Selector {
    Everything(),
    Selection(Vec<ScheduleExp>),
}

#[derive(Debug, Clone)]
pub enum ScheduleExp {
    Variable {
        var: String,
    },
    Integer {
        val: usize,
    },
    Boolean {
        val: bool,
    },
    Field {
        collect: Box<ScheduleExp>,
        field: String,
    },
    RunPass {
        pass: Pass,
        args: Vec<ScheduleExp>,
        on: Selector,
    },
    Record {
        fields: Vec<(String, ScheduleExp)>,
    },
    Block {
        body: Vec<ScheduleStmt>,
        res: Box<ScheduleExp>,
    },
    // This is used to "box" a selection by evaluating it at one point and then
    // allowing it to be used as a selector later on
    Selection {
        selection: Selector,
    },
}

#[derive(Debug, Copy, Clone)]
pub enum FixpointLimit {
    NoLimit(),
    PrintIter(),
    StopAfter(usize),
    PanicAfter(usize),
}

#[derive(Debug, Clone)]
pub enum ScheduleStmt {
    Fixpoint {
        body: Box<ScheduleStmt>,
        limit: FixpointLimit,
    },
    Block {
        body: Vec<ScheduleStmt>,
    },
    Let {
        var: String,
        exp: ScheduleExp,
    },
    Assign {
        var: String,
        exp: ScheduleExp,
    },
    AddSchedule {
        sched: Schedule,
        on: Selector,
    },
    AddDevice {
        device: Device,
        on: Selector,
    },
}