oters_lang 0.1.3

Language definitions and interpreter for the oters programming language
Documentation
use daggy::petgraph::visit::IntoEdges;
use daggy::{petgraph::visit::EdgeRef, Dag};

use super::{Type, TypeError};
use std::collections::HashMap;
use std::fmt::Display;

impl Display for Type {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        use Type::*;
        match self {
            Unit => write!(f, "()"),
            Int => write!(f, "int"),
            Float => write!(f, "float"),
            String => write!(f, "string"),
            Bool => write!(f, "bool"),
            Tuple(v) => {
                let mut t_str = "(".to_string();
                for i in 0..v.len() - 1 {
                    t_str.push_str(&format!("{}, ", v[i]));
                }

                t_str.push_str(&format!("{})", v[v.len() - 1]));
                write!(f, "{}", t_str)
            }
            List(t) => write!(f, "[{}]", t),
            Function(t1, t2) => write!(f, "({} -> {})", t1, t2),
            Delay(t) => write!(f, "@{}", t),
            Stable(t) => write!(f, "#{}", t),
            Fix(v, t) => match *t.clone() {
                Tuple(ts) => {
                    if ts.len() == 2 && matches!(*ts[1], FixVar(_)) {
                        write!(f, "Str<{}>", ts[0])
                    } else {
                        write!(f, "Fix {}.{}", v, t)
                    }
                }
                _ => write!(f, "Fix {}.{}", v, t),
            },
            FixVar(v) => write!(f, "{}", v),
            Generic(v, t) => {
                let mut vars = "∀ ".to_string();
                for i in 0..v.len() - 1 {
                    vars.push_str(&format!("{}, ", v[i]));
                }

                vars.push_str(&format!("{}", v[v.len() - 1]));
                write!(f, "{}.{}", vars, t)
            }
            GenericVar(v, stab) => {
                if *stab {
                    write!(f, "Stable({})", v)
                } else {
                    write!(f, "{}", v)
                }
            }
            Struct(map) => {
                let mut t_str = "struct {".to_string();

                for (s, t) in map {
                    t_str.push_str(&format!("{}: {}, ", s, t));
                }

                t_str.push('}');
                write!(f, "{}", t_str)
            }
            Enum(map) => {
                let mut t_str = "enum {".to_string();

                for (s, o) in map {
                    match o {
                        None => t_str.push_str(&format!("{}, ", s)),
                        Some(t) => t_str.push_str(&format!("{}({}), ", s, t)),
                    }
                }

                t_str.push('}');
                write!(f, "{}", t_str)
            }
        }
    }
}

pub fn traverse_path<T: Clone>(dag: &Dag<T, String>, path: &Vec<String>) -> anyhow::Result<T> {
    let mut node = 0.into();
    for module in path {
        let mut child = None;
        for edge in dag.edges(node) {
            if edge.weight() == module {
                child = Some(edge.target());
                break;
            }
        }
        node = if let Some(child) = child {
            child
        } else {
            return Err(TypeError::InvalidPath(format!("{:?}", path)).into());
        }
    }

    Ok(dag[node].clone())
}

pub fn insert_dec(
    dag: &mut Dag<HashMap<String, Type>, String>,
    name: String,
    t: Type,
    path: &Vec<String>,
) {
    let mut node = 0.into();
    for module in path {
        let mut child = None;
        for edge in dag.edges(node) {
            if edge.weight() == module {
                child = Some(edge.target());
                break;
            }
        }
        node = if let Some(child) = child {
            child
        } else {
            dag.add_child(node, module.clone(), HashMap::new()).1
        };
    }

    dag[node].insert(name, t);
}

pub fn create_path(dag: &mut Dag<HashMap<String, Type>, String>, path: &Vec<String>) {
    let mut node = 0.into();
    for module in path {
        let mut child = None;
        for edge in dag.edges(node) {
            if edge.weight() == module {
                child = Some(edge.target());
                break;
            }
        }
        node = if let Some(child) = child {
            child
        } else {
            dag.add_child(node, module.clone(), HashMap::new()).1
        };
    }
}