use core::fmt; use crate::{cons, ir::expr::evaluate}; use self::{types::Type, value::Value, evaluation::{ValueBindings, EvaluateError}}; pub mod types; pub mod expr; pub mod value; pub mod pattern; pub mod evaluation; #[derive(Debug, Clone, Eq, PartialEq)] // name id depth pub struct Identifier(pub String, usize, usize); impl Identifier { pub const ROOT: Identifier = Identifier(String::new(), 1, 0); /// A special identifier used only by the `main` method pub fn main() -> Identifier { Identifier("main".to_string(), 3, 1) } pub fn subid_with_name(&self, new_name: String, index: u32) -> Identifier { Identifier ( new_name, self.1 * nth_prime(self.2).pow(index + 1), self.2 + 1 ) } pub fn subid_generate_name(&self, short_name: &str, index: u32) -> Identifier { self.subid_with_name(format!("{}.{short_name}", self.0), index) } pub fn matches(&self, name: &str) -> bool { name == self.0.as_str() } pub fn set_name(self, new_name: String) -> Identifier { Identifier(new_name, self.1, self.2) } pub fn identifier_Int() -> Identifier { Identifier::main() .subid_with_name("Int".to_string(), 0) } } impl fmt::Display for Identifier { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{}.{}", self.0, self.1) } } #[derive(Debug)] pub enum IrError { MismatchedNames(String, String), Undefined(String), MissingExpression, NestedTypeDeclarations, } pub type Result = std::result::Result; // note: the 0th prime is 2 pub fn nth_prime(n: usize) -> usize { nth_prime_from(n, 3, vec![2]) } pub fn nth_prime_from(n: usize, i: usize, known_primes: Vec) -> usize { if is_prime(i, &known_primes) { if known_primes.len() > n { *known_primes.last().unwrap() } else { nth_prime_from(n, i + 2, cons(known_primes, i)) } } else { nth_prime_from(n, i + 2, known_primes) } } pub fn is_prime(x: usize, known_primes: &[usize]) -> bool { !known_primes.iter() .take_while(|p| **p * **p < x) .any(|p| x % *p == 0) } #[derive(Debug)] pub struct Declaration { pub identifier: Identifier, pub value_type: Value, pub value: Value, } impl fmt::Display for Declaration { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "{0} is of type {1} and has value\n{2}", self.identifier, self.value_type, self.value, ) } } #[derive(Debug, Clone)] pub struct BindingScope<'a>(Option<&'a BindingScope<'a>>, Vec); impl<'a> BindingScope<'a> { pub const ROOT: BindingScope<'static> = BindingScope(None, Vec::new()); pub fn builtins() -> BindingScope<'static> { BindingScope::ROOT.bind_single(Identifier::identifier_Int()) } pub fn bind(&self, idents: Vec) -> BindingScope { BindingScope(Some(self), idents) } pub fn bind_single(self, ident: Identifier) -> BindingScope<'a> { BindingScope(self.0, cons(self.1, ident)) } pub fn lookup(&self, name: &str) -> Option<&Identifier> { let BindingScope(next_scope, identifiers) = self; identifiers.iter() .find(|ident| ident.matches(name)) .or_else(|| next_scope.and_then(|s| s.lookup(name))) } }