lmntalc 0.13.1

A compiler for the LMNtal language
Documentation
use clap::ValueEnum;
use lmntalc_core::{
    codegen::IRSet,
    diagnostics::{Diagnostic, DiagnosticStage},
    model::guard::ProcessConstraint,
};

mod common;
pub mod cpp;
pub mod java;
pub mod python;

#[derive(Debug, Clone, Copy)]
pub enum Target {
    Cpp,
    Python,
    Java,
}

impl Target {
    pub fn extension(&self) -> &'static str {
        match self {
            Target::Cpp => "cpp",
            Target::Python => "py",
            Target::Java => "java",
        }
    }

    pub fn emit(self, ir_set: &IRSet) -> Result<String, BackendError> {
        match self {
            Target::Cpp => cpp::CppBackend::new().emit(ir_set),
            Target::Python => python::PythonBackend::new().emit(ir_set),
            Target::Java => java::JavaBackend::new().emit(ir_set),
        }
    }
}

impl ValueEnum for Target {
    fn value_variants<'a>() -> &'a [Self] {
        &[Target::Cpp, Target::Python, Target::Java]
    }

    fn to_possible_value(&self) -> Option<clap::builder::PossibleValue> {
        Some(match self {
            Target::Cpp => clap::builder::PossibleValue::new("cpp").alias("c++"),
            Target::Python => clap::builder::PossibleValue::new("python").alias("py"),
            Target::Java => clap::builder::PossibleValue::new("java"),
        })
    }
}

#[derive(Debug)]
pub enum BackendError {
    UnsupportedConstraint { constraint: ProcessConstraint },
    UnsupportedFunction { function: String },
    UnsupportedData { kind: &'static str },
    UnsupportedInstruction { instruction: &'static str },
    UnsupportedOperator { operator: &'static str },
    MissingVariableType { variable_id: usize },
}

impl std::fmt::Display for BackendError {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        match self {
            BackendError::UnsupportedConstraint { constraint } => {
                write!(f, "backend does not support constraint {}", constraint)
            }
            BackendError::UnsupportedFunction { function } => {
                write!(f, "backend does not support function {}", function)
            }
            BackendError::UnsupportedData { kind } => {
                write!(f, "backend does not support {} data yet", kind)
            }
            BackendError::UnsupportedInstruction { instruction } => {
                write!(f, "backend does not support instruction {}", instruction)
            }
            BackendError::UnsupportedOperator { operator } => {
                write!(f, "backend does not support operator {}", operator)
            }
            BackendError::MissingVariableType { variable_id } => {
                write!(
                    f,
                    "missing inferred type for temporary variable {}",
                    variable_id
                )
            }
        }
    }
}

impl std::error::Error for BackendError {}

impl BackendError {
    pub fn diagnostic(&self) -> Diagnostic {
        Diagnostic::error(DiagnosticStage::Backend, self.to_string(), None)
    }
}

pub trait Backend {
    fn new() -> Self;
    fn emit(&mut self, generator: &IRSet) -> Result<String, BackendError>;
}