use crate::symbol::SymbolId;
use crate::term::TermId;
use std::collections::HashMap;
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Attributes {
pub reducible: bool,
pub instance: bool,
pub recursor: bool,
pub custom: Vec<String>,
}
impl Default for Attributes {
fn default() -> Self {
Self {
reducible: true,
instance: false,
recursor: false,
custom: Vec::new(),
}
}
}
impl Attributes {
pub fn opaque() -> Self {
Self {
reducible: false,
..Default::default()
}
}
pub fn instance() -> Self {
Self {
instance: true,
..Default::default()
}
}
pub fn recursor() -> Self {
Self {
recursor: true,
..Default::default()
}
}
}
#[derive(Debug, Clone, PartialEq, Eq)]
pub struct Declaration {
pub name: SymbolId,
pub level_params: Vec<u32>,
pub ty: TermId,
pub value: Option<TermId>,
pub attrs: Attributes,
pub kind: DeclKind,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum DeclKind {
Def,
Axiom,
Theorem,
Inductive,
Constructor,
Recursor,
}
impl Declaration {
pub fn def(
name: SymbolId,
level_params: Vec<u32>,
ty: TermId,
value: TermId,
) -> Self {
Self {
name,
level_params,
ty,
value: Some(value),
attrs: Attributes::default(),
kind: DeclKind::Def,
}
}
pub fn axiom(name: SymbolId, level_params: Vec<u32>, ty: TermId) -> Self {
Self {
name,
level_params,
ty,
value: None,
attrs: Attributes::default(),
kind: DeclKind::Axiom,
}
}
pub fn theorem(
name: SymbolId,
level_params: Vec<u32>,
ty: TermId,
proof: TermId,
) -> Self {
Self {
name,
level_params,
ty,
value: Some(proof),
attrs: Attributes::opaque(),
kind: DeclKind::Theorem,
}
}
pub fn is_reducible(&self) -> bool {
self.attrs.reducible && self.value.is_some()
}
pub fn is_opaque(&self) -> bool {
!self.attrs.reducible
}
}
#[derive(Debug, Clone)]
pub struct InductiveDecl {
pub name: SymbolId,
pub level_params: Vec<u32>,
pub ty: TermId,
pub num_params: u32,
pub num_indices: u32,
pub constructors: Vec<ConstructorDecl>,
pub recursor: Option<SymbolId>,
}
#[derive(Debug, Clone)]
pub struct ConstructorDecl {
pub name: SymbolId,
pub ty: TermId,
pub num_fields: u32,
}
pub struct Environment {
declarations: HashMap<SymbolId, Declaration>,
inductives: HashMap<SymbolId, InductiveDecl>,
constructor_to_ind: HashMap<SymbolId, SymbolId>,
}
impl Environment {
pub fn new() -> Self {
Self {
declarations: HashMap::new(),
inductives: HashMap::new(),
constructor_to_ind: HashMap::new(),
}
}
pub fn add_decl(&mut self, decl: Declaration) -> crate::Result<()> {
if self.declarations.contains_key(&decl.name) {
return Err(crate::Error::Internal(format!(
"Declaration already exists: {:?}",
decl.name
)));
}
self.declarations.insert(decl.name, decl);
Ok(())
}
pub fn get_decl(&self, name: SymbolId) -> Option<&Declaration> {
self.declarations.get(&name)
}
pub fn has_decl(&self, name: SymbolId) -> bool {
self.declarations.contains_key(&name)
}
pub fn add_inductive(&mut self, ind: InductiveDecl) -> crate::Result<()> {
for ctor in &ind.constructors {
self.constructor_to_ind.insert(ctor.name, ind.name);
}
self.inductives.insert(ind.name, ind);
Ok(())
}
pub fn get_inductive(&self, name: SymbolId) -> Option<&InductiveDecl> {
self.inductives.get(&name)
}
pub fn get_inductive_of_constructor(&self, ctor: SymbolId) -> Option<&InductiveDecl> {
let ind_name = self.constructor_to_ind.get(&ctor)?;
self.get_inductive(*ind_name)
}
pub fn is_constructor(&self, name: SymbolId) -> bool {
self.constructor_to_ind.contains_key(&name)
}
pub fn declarations(&self) -> impl Iterator<Item = (&SymbolId, &Declaration)> {
self.declarations.iter()
}
pub fn num_decls(&self) -> usize {
self.declarations.len()
}
pub fn fork(&self) -> Self {
Self {
declarations: self.declarations.clone(),
inductives: self.inductives.clone(),
constructor_to_ind: self.constructor_to_ind.clone(),
}
}
}
impl Default for Environment {
fn default() -> Self {
Self::new()
}
}
impl Clone for Environment {
fn clone(&self) -> Self {
self.fork()
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_environment_basic() {
let mut env = Environment::new();
let name = SymbolId::new(0);
let ty = TermId::new(0);
let value = TermId::new(1);
let decl = Declaration::def(name, vec![], ty, value);
env.add_decl(decl).unwrap();
assert!(env.has_decl(name));
let retrieved = env.get_decl(name).unwrap();
assert_eq!(retrieved.ty, ty);
assert_eq!(retrieved.value, Some(value));
}
#[test]
fn test_duplicate_declaration() {
let mut env = Environment::new();
let name = SymbolId::new(0);
let decl = Declaration::axiom(name, vec![], TermId::new(0));
env.add_decl(decl.clone()).unwrap();
let result = env.add_decl(decl);
assert!(result.is_err());
}
#[test]
fn test_environment_fork() {
let mut env1 = Environment::new();
let name = SymbolId::new(0);
let decl = Declaration::axiom(name, vec![], TermId::new(0));
env1.add_decl(decl).unwrap();
let env2 = env1.fork();
assert!(env2.has_decl(name));
assert_eq!(env1.num_decls(), env2.num_decls());
}
#[test]
fn test_reducibility() {
let name = SymbolId::new(0);
let def = Declaration::def(name, vec![], TermId::new(0), TermId::new(1));
assert!(def.is_reducible());
let axiom = Declaration::axiom(name, vec![], TermId::new(0));
assert!(!axiom.is_reducible());
let theorem = Declaration::theorem(name, vec![], TermId::new(0), TermId::new(1));
assert!(!theorem.is_reducible()); }
}