Amo/src/ir/mod.rs

134 lines
3.1 KiB
Rust

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<T> = std::result::Result<T, IrError>;
// 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>) -> 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<Identifier>);
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<Identifier>) -> 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)))
}
}