runmat-hir 0.4.6

High-level IR for RunMat with type inference and lowering utilities
Documentation
use crate::{Span, Type, VarId};
use runmat_parser as parser;
use serde::{Deserialize, Serialize};
use std::collections::HashMap;

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct HirExpr {
    pub kind: HirExprKind,
    pub ty: Type,
    pub span: Span,
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum HirExprKind {
    Number(String),
    String(String),
    Var(VarId),
    Constant(String),
    Unary(parser::UnOp, Box<HirExpr>),
    Binary(Box<HirExpr>, parser::BinOp, Box<HirExpr>),
    Tensor(Vec<Vec<HirExpr>>),
    Cell(Vec<Vec<HirExpr>>),
    Index(Box<HirExpr>, Vec<HirExpr>),
    IndexCell(Box<HirExpr>, Vec<HirExpr>),
    Range(Box<HirExpr>, Option<Box<HirExpr>>, Box<HirExpr>),
    Colon,
    End,
    Member(Box<HirExpr>, String),
    MemberDynamic(Box<HirExpr>, Box<HirExpr>),
    DottedInvoke(Box<HirExpr>, String, Vec<HirExpr>),
    MethodCall(Box<HirExpr>, String, Vec<HirExpr>),
    AnonFunc {
        params: Vec<VarId>,
        body: Box<HirExpr>,
    },
    FuncHandle(String),
    FuncCall(String, Vec<HirExpr>),
    MetaClass(String),
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum HirStmt {
    ExprStmt(HirExpr, bool, Span),
    Assign(VarId, HirExpr, bool, Span),
    MultiAssign(Vec<Option<VarId>>, HirExpr, bool, Span),
    AssignLValue(HirLValue, HirExpr, bool, Span),
    If {
        cond: HirExpr,
        then_body: Vec<HirStmt>,
        elseif_blocks: Vec<(HirExpr, Vec<HirStmt>)>,
        else_body: Option<Vec<HirStmt>>,
        span: Span,
    },
    While {
        cond: HirExpr,
        body: Vec<HirStmt>,
        span: Span,
    },
    For {
        var: VarId,
        expr: HirExpr,
        body: Vec<HirStmt>,
        span: Span,
    },
    Switch {
        expr: HirExpr,
        cases: Vec<(HirExpr, Vec<HirStmt>)>,
        otherwise: Option<Vec<HirStmt>>,
        span: Span,
    },
    TryCatch {
        try_body: Vec<HirStmt>,
        catch_var: Option<VarId>,
        catch_body: Vec<HirStmt>,
        span: Span,
    },
    Global(Vec<(VarId, String)>, Span),
    Persistent(Vec<(VarId, String)>, Span),
    Break(Span),
    Continue(Span),
    Return(Span),
    Function {
        name: String,
        params: Vec<VarId>,
        outputs: Vec<VarId>,
        body: Vec<HirStmt>,
        has_varargin: bool,
        has_varargout: bool,
        span: Span,
    },
    ClassDef {
        name: String,
        super_class: Option<String>,
        members: Vec<HirClassMember>,
        span: Span,
    },
    Import {
        path: Vec<String>,
        wildcard: bool,
        span: Span,
    },
}

impl HirExpr {
    pub fn span(&self) -> Span {
        self.span
    }
}

impl HirStmt {
    pub fn span(&self) -> Span {
        match self {
            HirStmt::ExprStmt(_, _, span)
            | HirStmt::Assign(_, _, _, span)
            | HirStmt::MultiAssign(_, _, _, span)
            | HirStmt::AssignLValue(_, _, _, span)
            | HirStmt::Global(_, span)
            | HirStmt::Persistent(_, span)
            | HirStmt::Break(span)
            | HirStmt::Continue(span)
            | HirStmt::Return(span) => *span,
            HirStmt::If { span, .. }
            | HirStmt::While { span, .. }
            | HirStmt::For { span, .. }
            | HirStmt::Switch { span, .. }
            | HirStmt::TryCatch { span, .. }
            | HirStmt::Function { span, .. }
            | HirStmt::ClassDef { span, .. }
            | HirStmt::Import { span, .. } => *span,
        }
    }
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum HirClassMember {
    Properties {
        attributes: Vec<parser::Attr>,
        names: Vec<String>,
    },
    Methods {
        attributes: Vec<parser::Attr>,
        body: Vec<HirStmt>,
    },
    Events {
        attributes: Vec<parser::Attr>,
        names: Vec<String>,
    },
    Enumeration {
        attributes: Vec<parser::Attr>,
        names: Vec<String>,
    },
    Arguments {
        attributes: Vec<parser::Attr>,
        names: Vec<String>,
    },
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub enum HirLValue {
    Var(VarId),
    Member(Box<HirExpr>, String),
    MemberDynamic(Box<HirExpr>, Box<HirExpr>),
    Index(Box<HirExpr>, Vec<HirExpr>),
    IndexCell(Box<HirExpr>, Vec<HirExpr>),
}

#[derive(Debug, PartialEq, Clone, Serialize, Deserialize)]
pub struct HirProgram {
    pub body: Vec<HirStmt>,
    #[serde(default)]
    pub var_types: Vec<Type>,
}

#[derive(Debug, Clone)]
pub struct LoweringResult {
    pub hir: HirProgram,
    pub variables: HashMap<String, usize>,
    pub functions: HashMap<String, HirStmt>,
    pub var_types: Vec<Type>,
    pub var_names: HashMap<VarId, String>,
    pub inferred_globals: HashMap<VarId, Type>,
    pub inferred_function_envs: HashMap<String, HashMap<VarId, Type>>,
    pub inferred_function_returns: HashMap<String, Vec<Type>>,
}