#![allow(missing_docs)]
use super::{Type, TypeVar, TypeScheme, TypeEnv, Constraint};
use super::type_classes::TypeClassInstance;
use crate::diagnostics::{Error, Result, Span};
use crate::eval::value::Value;
use std::collections::HashMap;
use std::fmt;
pub struct R7RSIntegration {
type_env: TypeEnv,
comparator_types: HashMap<String, ComparatorType>,
hash_table_types: HashMap<String, HashTableType>,
generator_types: HashMap<String, GeneratorType>,
immutable_types: HashMap<String, ImmutableType>,
srfi_types: HashMap<String, SRFITypeExtension>,
}
#[derive(Debug, Clone)]
pub struct ComparatorType {
pub element_type: Type,
pub constraints: Vec<Constraint>,
pub procedures: ComparatorProcedures,
}
#[derive(Debug, Clone)]
pub struct ComparatorProcedures {
pub type_test: Option<TypeScheme>,
pub equality: TypeScheme,
pub ordering: Option<TypeScheme>,
pub hash: Option<TypeScheme>,
}
#[derive(Debug, Clone)]
pub struct HashTableType {
pub key_type: Type,
pub value_type: Type,
pub comparator_type: Option<ComparatorType>,
pub operations: HashTableOperations,
}
#[derive(Debug, Clone)]
pub struct HashTableOperations {
pub get: TypeScheme,
pub set: TypeScheme,
pub delete: TypeScheme,
pub contains: TypeScheme,
}
#[derive(Debug, Clone)]
pub struct GeneratorType {
pub element_type: Type,
pub state_type: Option<Type>,
pub operations: GeneratorOperations,
}
#[derive(Debug, Clone)]
pub struct GeneratorOperations {
pub next: TypeScheme,
pub peek: Option<TypeScheme>,
pub has_more: TypeScheme,
pub map: TypeScheme,
pub filter: TypeScheme,
}
#[derive(Debug, Clone)]
pub struct ImmutableType {
pub element_type: Type,
pub immutability: ImmutabilityLevel,
pub sharing: SharingInfo,
pub operations: ImmutableOperations,
}
#[derive(Debug, Clone, PartialEq)]
pub enum ImmutabilityLevel {
Shallow,
Deep,
Persistent,
}
#[derive(Debug, Clone)]
pub struct SharingInfo {
pub uses_sharing: bool,
pub copy_on_write: bool,
pub max_depth: Option<usize>,
}
#[derive(Debug, Clone)]
pub struct ImmutableOperations {
pub update: TypeScheme,
pub insert: TypeScheme,
pub delete: TypeScheme,
pub merge: Option<TypeScheme>,
}
#[derive(Debug, Clone)]
pub struct SRFITypeExtension {
pub srfi_number: u32,
pub types: HashMap<String, Type>,
pub instances: Vec<TypeClassInstance>,
pub special_rules: Vec<SRFITypeRule>,
}
#[derive(Debug, Clone)]
pub struct SRFITypeRule {
pub name: String,
pub condition: String, pub transformation: String, }
impl R7RSIntegration {
pub fn new() -> Self {
let mut integration = Self {
type_env: TypeEnv::new(),
comparator_types: HashMap::new(),
hash_table_types: HashMap::new(),
generator_types: HashMap::new(),
immutable_types: HashMap::new(),
srfi_types: HashMap::new(),
};
integration.setup_builtin_types();
integration
}
fn setup_builtin_types(&mut self) {
self.setup_comparator_types();
self.setup_hash_table_types();
self.setup_generator_types();
self.setup_immutable_types();
self.setup_srfi_types();
}
fn setup_comparator_types(&mut self) {
let string_comparator = ComparatorType {
element_type: Type::String,
constraints: vec![
Constraint { class: "Eq".to_string(), type_: Type::String },
Constraint { class: "Ord".to_string(), type_: Type::String },
],
procedures: ComparatorProcedures {
type_test: Some(TypeScheme::monomorphic(
Type::function(vec![Type::Dynamic], Type::Boolean)
)),
equality: TypeScheme::monomorphic(
Type::function(vec![Type::String, Type::String], Type::Boolean)
),
ordering: Some(TypeScheme::monomorphic(
Type::function(vec![Type::String, Type::String], Type::Symbol)
)),
hash: Some(TypeScheme::monomorphic(
Type::function(vec![Type::String], Type::Number)
)),
},
};
self.comparator_types.insert("string-comparator".to_string(), string_comparator);
let number_comparator = ComparatorType {
element_type: Type::Number,
constraints: vec![
Constraint { class: "Eq".to_string(), type_: Type::Number },
Constraint { class: "Ord".to_string(), type_: Type::Number },
],
procedures: ComparatorProcedures {
type_test: Some(TypeScheme::monomorphic(
Type::function(vec![Type::Dynamic], Type::Boolean)
)),
equality: TypeScheme::monomorphic(
Type::function(vec![Type::Number, Type::Number], Type::Boolean)
),
ordering: Some(TypeScheme::monomorphic(
Type::function(vec![Type::Number, Type::Number], Type::Symbol)
)),
hash: Some(TypeScheme::monomorphic(
Type::function(vec![Type::Number], Type::Number)
)),
},
};
self.comparator_types.insert("number-comparator".to_string(), number_comparator);
}
fn setup_hash_table_types(&mut self) {
let hash_table_type = HashTableType {
key_type: Type::Variable(TypeVar::with_name("K")),
value_type: Type::Variable(TypeVar::with_name("V")),
comparator_type: None,
operations: HashTableOperations {
get: TypeScheme::polymorphic(
vec![TypeVar::with_name("K"), TypeVar::with_name("V")],
vec![],
Type::function(
vec![
Type::Application {
constructor: Box::new(Type::Constructor {
name: "HashTable".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::arrow(super::Kind::Type, super::Kind::Type)),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("K"))),
},
Type::Variable(TypeVar::with_name("K")),
],
Type::Application {
constructor: Box::new(Type::Constructor {
name: "Maybe".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("V"))),
},
),
),
set: TypeScheme::polymorphic(
vec![TypeVar::with_name("K"), TypeVar::with_name("V")],
vec![],
Type::function(
vec![
Type::Application {
constructor: Box::new(Type::Constructor {
name: "HashTable".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::arrow(super::Kind::Type, super::Kind::Type)),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("K"))),
},
Type::Variable(TypeVar::with_name("K")),
Type::Variable(TypeVar::with_name("V")),
],
Type::Unit,
),
),
delete: TypeScheme::polymorphic(
vec![TypeVar::with_name("K"), TypeVar::with_name("V")],
vec![],
Type::function(
vec![
Type::Application {
constructor: Box::new(Type::Constructor {
name: "HashTable".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::arrow(super::Kind::Type, super::Kind::Type)),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("K"))),
},
Type::Variable(TypeVar::with_name("K")),
],
Type::Unit,
),
),
contains: TypeScheme::polymorphic(
vec![TypeVar::with_name("K"), TypeVar::with_name("V")],
vec![],
Type::function(
vec![
Type::Application {
constructor: Box::new(Type::Constructor {
name: "HashTable".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::arrow(super::Kind::Type, super::Kind::Type)),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("K"))),
},
Type::Variable(TypeVar::with_name("K")),
],
Type::Boolean,
),
),
},
};
self.hash_table_types.insert("hash-table".to_string(), hash_table_type);
}
fn setup_generator_types(&mut self) {
let generator_type = GeneratorType {
element_type: Type::Variable(TypeVar::with_name("A")),
state_type: Some(Type::Variable(TypeVar::with_name("S"))),
operations: GeneratorOperations {
next: TypeScheme::polymorphic(
vec![TypeVar::with_name("A")],
vec![],
Type::function(
vec![Type::Application {
constructor: Box::new(Type::Constructor {
name: "Generator".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
}],
Type::Application {
constructor: Box::new(Type::Constructor {
name: "Maybe".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
),
),
peek: Some(TypeScheme::polymorphic(
vec![TypeVar::with_name("A")],
vec![],
Type::function(
vec![Type::Application {
constructor: Box::new(Type::Constructor {
name: "Generator".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
}],
Type::Application {
constructor: Box::new(Type::Constructor {
name: "Maybe".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
),
)),
has_more: TypeScheme::polymorphic(
vec![TypeVar::with_name("A")],
vec![],
Type::function(
vec![Type::Application {
constructor: Box::new(Type::Constructor {
name: "Generator".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
}],
Type::Boolean,
),
),
map: TypeScheme::polymorphic(
vec![TypeVar::with_name("A"), TypeVar::with_name("B")],
vec![],
Type::function(
vec![
Type::function(
vec![Type::Variable(TypeVar::with_name("A"))],
Type::Variable(TypeVar::with_name("B")),
),
Type::Application {
constructor: Box::new(Type::Constructor {
name: "Generator".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
],
Type::Application {
constructor: Box::new(Type::Constructor {
name: "Generator".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("B"))),
},
),
),
filter: TypeScheme::polymorphic(
vec![TypeVar::with_name("A")],
vec![],
Type::function(
vec![
Type::function(
vec![Type::Variable(TypeVar::with_name("A"))],
Type::Boolean,
),
Type::Application {
constructor: Box::new(Type::Constructor {
name: "Generator".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
],
Type::Application {
constructor: Box::new(Type::Constructor {
name: "Generator".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
),
),
},
};
self.generator_types.insert("generator".to_string(), generator_type);
}
fn setup_immutable_types(&mut self) {
let immutable_list = ImmutableType {
element_type: Type::Variable(TypeVar::with_name("A")),
immutability: ImmutabilityLevel::Persistent,
sharing: SharingInfo {
uses_sharing: true,
copy_on_write: false,
max_depth: None,
},
operations: ImmutableOperations {
update: TypeScheme::polymorphic(
vec![TypeVar::with_name("A")],
vec![],
Type::function(
vec![
Type::Application {
constructor: Box::new(Type::Constructor {
name: "IList".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
Type::Number, Type::Variable(TypeVar::with_name("A")), ],
Type::Application {
constructor: Box::new(Type::Constructor {
name: "IList".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
),
),
insert: TypeScheme::polymorphic(
vec![TypeVar::with_name("A")],
vec![],
Type::function(
vec![
Type::Application {
constructor: Box::new(Type::Constructor {
name: "IList".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
Type::Number, Type::Variable(TypeVar::with_name("A")), ],
Type::Application {
constructor: Box::new(Type::Constructor {
name: "IList".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
),
),
delete: TypeScheme::polymorphic(
vec![TypeVar::with_name("A")],
vec![],
Type::function(
vec![
Type::Application {
constructor: Box::new(Type::Constructor {
name: "IList".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
Type::Number, ],
Type::Application {
constructor: Box::new(Type::Constructor {
name: "IList".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
),
),
merge: Some(TypeScheme::polymorphic(
vec![TypeVar::with_name("A")],
vec![],
Type::function(
vec![
Type::Application {
constructor: Box::new(Type::Constructor {
name: "IList".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
Type::Application {
constructor: Box::new(Type::Constructor {
name: "IList".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
],
Type::Application {
constructor: Box::new(Type::Constructor {
name: "IList".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("A"))),
},
),
)),
},
};
self.immutable_types.insert("ilist".to_string(), immutable_list);
}
fn setup_srfi_types(&mut self) {
let mut srfi1_types = HashMap::new();
srfi1_types.insert("circular-list".to_string(), Type::list(Type::Variable(TypeVar::with_name("a"))));
srfi1_types.insert("dotted-list".to_string(), Type::pair(Type::Variable(TypeVar::with_name("a")), Type::Variable(TypeVar::with_name("b"))));
let srfi1 = SRFITypeExtension {
srfi_number: 1,
types: srfi1_types,
instances: vec![],
special_rules: vec![
SRFITypeRule {
name: "proper-list-constraint".to_string(),
condition: "list operation".to_string(),
transformation: "ensure proper list".to_string(),
},
],
};
self.srfi_types.insert("srfi-1".to_string(), srfi1);
let mut srfi14_types = HashMap::new();
srfi14_types.insert("char-set".to_string(), Type::Constructor {
name: "CharSet".to_string(),
kind: super::Kind::Type,
});
let srfi14 = SRFITypeExtension {
srfi_number: 14,
types: srfi14_types,
instances: vec![],
special_rules: vec![],
};
self.srfi_types.insert("srfi-14".to_string(), srfi14);
let mut srfi39_types = HashMap::new();
srfi39_types.insert("parameter".to_string(), Type::Application {
constructor: Box::new(Type::Constructor {
name: "Parameter".to_string(),
kind: super::Kind::arrow(super::Kind::Type, super::Kind::Type),
}),
argument: Box::new(Type::Variable(TypeVar::with_name("a"))),
});
let srfi39 = SRFITypeExtension {
srfi_number: 39,
types: srfi39_types,
instances: vec![],
special_rules: vec![
SRFITypeRule {
name: "parameter-conversion".to_string(),
condition: "parameter access".to_string(),
transformation: "apply converter".to_string(),
},
],
};
self.srfi_types.insert("srfi-39".to_string(), srfi39);
}
pub fn check_comparator(&self, _name: &str, element_type: &Type) -> Result<ComparatorType> {
let mut constraints = vec![
Constraint { class: "Eq".to_string(), type_: element_type.clone() },
];
if self.supports_ordering(element_type) {
constraints.push(Constraint { class: "Ord".to_string(), type_: element_type.clone() });
}
if self.supports_hashing(element_type) {
constraints.push(Constraint { class: "Hash".to_string(), type_: element_type.clone() });
}
Ok(ComparatorType {
element_type: element_type.clone(),
constraints,
procedures: self.default_comparator_procedures(element_type),
})
}
fn supports_ordering(&self, ty: &Type) -> bool {
matches!(ty, Type::Number | Type::String | Type::Char | Type::Boolean)
}
fn supports_hashing(&self, ty: &Type) -> bool {
matches!(ty, Type::Number | Type::String | Type::Char | Type::Boolean | Type::Symbol)
}
fn default_comparator_procedures(&self, element_type: &Type) -> ComparatorProcedures {
ComparatorProcedures {
type_test: Some(TypeScheme::monomorphic(
Type::function(vec![Type::Dynamic], Type::Boolean)
)),
equality: TypeScheme::monomorphic(
Type::function(vec![element_type.clone(), element_type.clone()], Type::Boolean)
),
ordering: if self.supports_ordering(element_type) {
Some(TypeScheme::monomorphic(
Type::function(vec![element_type.clone(), element_type.clone()], Type::Symbol)
))
} else {
None
},
hash: if self.supports_hashing(element_type) {
Some(TypeScheme::monomorphic(
Type::function(vec![element_type.clone()], Type::Number)
))
} else {
None
},
}
}
pub fn check_hash_table_operation(
&self,
operation: &str,
_key_type: &Type,
_value_type: &Type,
) -> Result<TypeScheme> {
if let Some(hash_table_type) = self.hash_table_types.get("hash-table") {
match operation {
"hash-table-ref" => Ok(hash_table_type.operations.get.clone()),
"hash-table-set!" => Ok(hash_table_type.operations.set.clone()),
"hash-table-delete!" => Ok(hash_table_type.operations.delete.clone()),
"hash-table-contains?" => Ok(hash_table_type.operations.contains.clone()),
_ => Err(Box::new(Error::type_error(
format!("Unknown hash table operation: {operation}"),
Span::default(),
))),
}
} else {
Err(Box::new(Error::type_error(
"Hash table type not found".to_string(),
Span::default(),
)))
}
}
pub fn infer_generator_type(&self, _generator_expr: &str) -> Result<GeneratorType> {
Ok(GeneratorType {
element_type: Type::Dynamic,
state_type: Some(Type::Dynamic),
operations: self.generator_types.get("generator").unwrap().operations.clone(),
})
}
pub fn check_immutability(&self, type_name: &str, operation: &str) -> Result<bool> {
if let Some(_immutable_type) = self.immutable_types.get(type_name) {
match operation {
"update" | "insert" | "delete" | "merge" => {
Ok(true)
}
_ => {
Ok(true)
}
}
} else {
Err(Box::new(Error::type_error(
format!("Unknown immutable type: {type_name}"),
Span::default(),
)))
}
}
pub fn get_srfi_rules(&self, srfi_name: &str) -> Option<&SRFITypeExtension> {
self.srfi_types.get(srfi_name)
}
pub fn validate_gradual_typing(&self, static_type: &Type, dynamic_value: &Value) -> Result<bool> {
match (static_type, dynamic_value) {
(Type::Dynamic, _) => Ok(true),
(Type::Number, Value::Literal(crate::ast::Literal::ExactInteger(_))) => Ok(true),
(Type::Number, Value::Literal(crate::ast::Literal::InexactReal(_))) => Ok(true),
(Type::Number, Value::Literal(crate::ast::Literal::Rational { .. })) => Ok(true),
(Type::Number, Value::Literal(crate::ast::Literal::Complex { .. })) => Ok(true),
(Type::String, Value::Literal(crate::ast::Literal::String(_))) => Ok(true),
(Type::Boolean, Value::Literal(crate::ast::Literal::Boolean(_))) => Ok(true),
(Type::Symbol, Value::Symbol(_)) => Ok(true),
_ => Ok(false), }
}
}
impl Default for R7RSIntegration {
fn default() -> Self {
Self::new()
}
}
impl fmt::Display for ComparatorType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Comparator<{}>", self.element_type)?;
if !self.constraints.is_empty() {
write!(f, " with ")?;
for (i, constraint) in self.constraints.iter().enumerate() {
if i > 0 { write!(f, ", ")?; }
write!(f, "{}", constraint.class)?;
}
}
Ok(())
}
}
impl fmt::Display for HashTableType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "HashTable<{}, {}>", self.key_type, self.value_type)
}
}
impl fmt::Display for GeneratorType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Generator<{}>", self.element_type)
}
}
impl fmt::Display for ImmutableType {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
write!(f, "Immutable<{}> ({:?})", self.element_type, self.immutability)
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_r7rs_integration_creation() {
let integration = R7RSIntegration::new();
assert!(!integration.comparator_types.is_empty());
assert!(!integration.hash_table_types.is_empty());
assert!(!integration.generator_types.is_empty());
assert!(!integration.immutable_types.is_empty());
assert!(!integration.srfi_types.is_empty());
}
#[test]
fn test_comparator_type_checking() {
let integration = R7RSIntegration::new();
let string_comparator = integration.check_comparator("test", &Type::String).unwrap();
assert_eq!(string_comparator.element_type, Type::String);
assert!(string_comparator.constraints.len() >= 2); }
#[test]
fn test_hash_table_operations() {
let integration = R7RSIntegration::new();
let get_op = integration.check_hash_table_operation("hash-table-ref", &Type::String, &Type::Number);
assert!(get_op.is_ok());
let invalid_op = integration.check_hash_table_operation("invalid-op", &Type::String, &Type::Number);
assert!(invalid_op.is_err());
}
#[test]
fn test_immutability_checking() {
let integration = R7RSIntegration::new();
let update_check = integration.check_immutability("ilist", "update");
assert!(update_check.is_ok());
assert!(update_check.unwrap());
let unknown_type = integration.check_immutability("unknown", "update");
assert!(unknown_type.is_err());
}
#[test]
fn test_srfi_integration() {
let integration = R7RSIntegration::new();
let srfi1 = integration.get_srfi_rules("srfi-1");
assert!(srfi1.is_some());
assert_eq!(srfi1.unwrap().srfi_number, 1);
let srfi39 = integration.get_srfi_rules("srfi-39");
assert!(srfi39.is_some());
assert_eq!(srfi39.unwrap().srfi_number, 39);
}
#[test]
fn test_gradual_typing_validation() {
let integration = R7RSIntegration::new();
let result = integration.validate_gradual_typing(&Type::Dynamic, &Value::integer(42));
assert!(result.is_ok());
assert!(result.unwrap());
let result = integration.validate_gradual_typing(&Type::Number, &Value::integer(42));
assert!(result.is_ok());
assert!(result.unwrap());
let result = integration.validate_gradual_typing(&Type::String, &Value::integer(42));
assert!(result.is_ok());
assert!(!result.unwrap());
}
}