134 lines
3.1 KiB
Rust
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)))
|
|
}
|
|
}
|
|
|