use crate::diagnostics::{Error as DiagnosticError, Result};
use crate::eval::value::{Value, PrimitiveProcedure, PrimitiveImpl, ThreadSafeEnvironment};
use crate::effects::Effect;
use std::sync::Arc;
pub fn create_type_bindings(env: &Arc<ThreadSafeEnvironment>) {
bind_type_queries(env);
bind_type_operations(env);
bind_type_checking(env);
bind_gradual_typing(env);
}
fn bind_type_queries(env: &Arc<ThreadSafeEnvironment>) {
env.define("type-of".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "type-of".to_string(),
arity_min: 1,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(primitive_type_of),
effects: vec![Effect::Pure],
})));
env.define("type?".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "type?".to_string(),
arity_min: 1,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(primitive_type_p),
effects: vec![Effect::Pure],
})));
env.define("type-name".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "type-name".to_string(),
arity_min: 1,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(primitive_type_name),
effects: vec![Effect::Pure],
})));
}
fn bind_type_operations(env: &Arc<ThreadSafeEnvironment>) {
env.define("type-union".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "type-union".to_string(),
arity_min: 2,
arity_max: None,
implementation: PrimitiveImpl::RustFn(primitive_type_union),
effects: vec![Effect::Pure],
})));
env.define("type-intersection".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "type-intersection".to_string(),
arity_min: 2,
arity_max: None,
implementation: PrimitiveImpl::RustFn(primitive_type_intersection),
effects: vec![Effect::Pure],
})));
env.define("type-difference".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "type-difference".to_string(),
arity_min: 2,
arity_max: Some(2),
implementation: PrimitiveImpl::RustFn(primitive_type_difference),
effects: vec![Effect::Pure],
})));
env.define("subtype?".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "subtype?".to_string(),
arity_min: 2,
arity_max: Some(2),
implementation: PrimitiveImpl::RustFn(primitive_subtype_p),
effects: vec![Effect::Pure],
})));
env.define("type-equivalent?".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "type-equivalent?".to_string(),
arity_min: 2,
arity_max: Some(2),
implementation: PrimitiveImpl::RustFn(primitive_type_equivalent_p),
effects: vec![Effect::Pure],
})));
}
fn bind_type_checking(env: &Arc<ThreadSafeEnvironment>) {
env.define("type-check".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "type-check".to_string(),
arity_min: 2,
arity_max: Some(2),
implementation: PrimitiveImpl::RustFn(primitive_type_check),
effects: vec![Effect::Pure],
})));
env.define("type-assert".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "type-assert".to_string(),
arity_min: 2,
arity_max: Some(2),
implementation: PrimitiveImpl::RustFn(primitive_type_assert),
effects: vec![Effect::Error], })));
env.define("type-cast".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "type-cast".to_string(),
arity_min: 2,
arity_max: Some(2),
implementation: PrimitiveImpl::RustFn(primitive_type_cast),
effects: vec![Effect::Pure],
})));
}
fn bind_gradual_typing(env: &Arc<ThreadSafeEnvironment>) {
env.define("any-type".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "any-type".to_string(),
arity_min: 0,
arity_max: Some(0),
implementation: PrimitiveImpl::RustFn(primitive_any_type),
effects: vec![Effect::Pure],
})));
env.define("unknown-type".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "unknown-type".to_string(),
arity_min: 0,
arity_max: Some(0),
implementation: PrimitiveImpl::RustFn(primitive_unknown_type),
effects: vec![Effect::Pure],
})));
env.define("make-function-type".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "make-function-type".to_string(),
arity_min: 2,
arity_max: Some(2),
implementation: PrimitiveImpl::RustFn(primitive_make_function_type),
effects: vec![Effect::Pure],
})));
env.define("function-type?".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "function-type?".to_string(),
arity_min: 1,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(primitive_function_type_p),
effects: vec![Effect::Pure],
})));
env.define("function-parameter-types".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "function-parameter-types".to_string(),
arity_min: 1,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(primitive_function_parameter_types),
effects: vec![Effect::Pure],
})));
env.define("function-return-type".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "function-return-type".to_string(),
arity_min: 1,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(primitive_function_return_type),
effects: vec![Effect::Pure],
})));
}
fn primitive_type_of(args: &[Value]) -> Result<Value> {
if args.len() != 1 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("type-of expects 1 argument, got {}", args.len()),
None,
)));
}
let type_name = get_value_type_name(&args[0]);
Ok(Value::string(type_name))
}
fn primitive_type_p(args: &[Value]) -> Result<Value> {
if args.len() != 1 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("type? expects 1 argument, got {}", args.len()),
None,
)));
}
let is_type = matches!(args[0], Value::Type(_));
Ok(Value::boolean(is_type))
}
fn primitive_type_name(args: &[Value]) -> Result<Value> {
if args.len() != 1 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("type-name expects 1 argument, got {}", args.len()),
None,
)));
}
match &args[0] {
Value::Type(type_val) => {
let name = match type_val.as_ref() {
crate::eval::value::TypeValue::Base(name) => name.clone(),
crate::eval::value::TypeValue::Function { .. } => "function".to_string(),
crate::eval::value::TypeValue::Union(_) => "union".to_string(),
crate::eval::value::TypeValue::Intersection(_) => "intersection".to_string(),
crate::eval::value::TypeValue::Variable(name) => name.clone(),
};
Ok(Value::string(name))
}
_ => Err(Box::new(DiagnosticError::runtime_error(
"type-name requires a type argument".to_string(),
None,
))),
}
}
fn primitive_type_union(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"type-union requires type system integration (not yet implemented)".to_string(),
None,
)))
}
fn primitive_type_intersection(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"type-intersection requires type system integration (not yet implemented)".to_string(),
None,
)))
}
fn primitive_type_difference(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"type-difference requires type system integration (not yet implemented)".to_string(),
None,
)))
}
fn primitive_subtype_p(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"subtype? requires type system integration (not yet implemented)".to_string(),
None,
)))
}
fn primitive_type_equivalent_p(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"type-equivalent? requires type system integration (not yet implemented)".to_string(),
None,
)))
}
fn primitive_type_check(args: &[Value]) -> Result<Value> {
if args.len() != 2 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("type-check expects 2 arguments, got {}", args.len()),
None,
)));
}
let value = &args[0];
let expected_type = args[1].as_string().unwrap_or("unknown");
let actual_type = get_value_type_name(value);
Ok(Value::boolean(actual_type == expected_type))
}
fn primitive_type_assert(args: &[Value]) -> Result<Value> {
if args.len() != 2 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("type-assert expects 2 arguments, got {}", args.len()),
None,
)));
}
let type_check_result = primitive_type_check(args)?;
if type_check_result.is_truthy() {
Ok(args[0].clone())
} else {
Err(Box::new(DiagnosticError::runtime_error(
format!("Type assertion failed: expected {}, got {}",
args[1], get_value_type_name(&args[0])),
None,
)))
}
}
fn primitive_type_cast(args: &[Value]) -> Result<Value> {
if args.len() != 2 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("type-cast expects 2 arguments, got {}", args.len()),
None,
)));
}
Ok(args[0].clone())
}
fn primitive_any_type(_args: &[Value]) -> Result<Value> {
Ok(Value::Type(Arc::new(crate::eval::value::TypeValue::Base("any".to_string()))))
}
fn primitive_unknown_type(_args: &[Value]) -> Result<Value> {
Ok(Value::Type(Arc::new(crate::eval::value::TypeValue::Base("unknown".to_string()))))
}
fn primitive_make_function_type(args: &[Value]) -> Result<Value> {
if args.len() != 2 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("make-function-type expects 2 arguments, got {}", args.len()),
None,
)));
}
Err(Box::new(DiagnosticError::runtime_error(
"make-function-type requires type system integration (not yet implemented)".to_string(),
None,
)))
}
fn primitive_function_type_p(args: &[Value]) -> Result<Value> {
if args.len() != 1 {
return Err(Box::new(DiagnosticError::runtime_error(
format!("function-type? expects 1 argument, got {}", args.len()),
None,
)));
}
match &args[0] {
Value::Type(type_val) => {
let is_function = matches!(type_val.as_ref(), crate::eval::value::TypeValue::Function { .. });
Ok(Value::boolean(is_function))
}
_ => Ok(Value::boolean(false)),
}
}
fn primitive_function_parameter_types(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"function-parameter-types requires type system integration (not yet implemented)".to_string(),
None,
)))
}
fn primitive_function_return_type(_args: &[Value]) -> Result<Value> {
Err(Box::new(DiagnosticError::runtime_error(
"function-return-type requires type system integration (not yet implemented)".to_string(),
None,
)))
}
fn get_value_type_name(value: &Value) -> String {
match value {
Value::Literal(lit) => match lit {
crate::ast::Literal::ExactInteger(_) => "integer".to_string(),
crate::ast::Literal::InexactReal(_) => "real".to_string(),
crate::ast::Literal::Number(_) => "number".to_string(),
crate::ast::Literal::Rational { .. } => "rational".to_string(),
crate::ast::Literal::Complex { .. } => "complex".to_string(),
crate::ast::Literal::String(_) => "string".to_string(),
crate::ast::Literal::Character(_) => "character".to_string(),
crate::ast::Literal::Boolean(_) => "boolean".to_string(),
crate::ast::Literal::Bytevector(_) => "bytevector".to_string(),
crate::ast::Literal::Nil => "null".to_string(),
crate::ast::Literal::Unspecified => "unspecified".to_string(),
},
Value::Symbol(_) => "symbol".to_string(),
Value::Keyword(_) => "keyword".to_string(),
Value::Nil => "null".to_string(),
Value::Unspecified => "unspecified".to_string(),
Value::Pair(_, _) => "pair".to_string(),
Value::MutablePair(_, _) => "pair".to_string(),
Value::Vector(_) => "vector".to_string(),
Value::Hashtable(_) => "hashtable".to_string(),
Value::Procedure(_) => "procedure".to_string(),
Value::Primitive(_) => "primitive".to_string(),
Value::Continuation(_) => "continuation".to_string(),
Value::Syntax(_) => "syntax".to_string(),
Value::Port(_) => "port".to_string(),
Value::Promise(_) => "promise".to_string(),
Value::Type(_) => "type".to_string(),
Value::Foreign(obj) => obj.type_name.clone(),
Value::ErrorObject(_) => "error".to_string(),
Value::CharSet(_) => "char-set".to_string(),
Value::Parameter(_) => "parameter".to_string(),
Value::CaseLambda(_) => "procedure".to_string(), Value::Record(_) => "record".to_string(),
Value::AdvancedHashTable(_) => "advanced-hash-table".to_string(),
Value::Ideque(_) => "ideque".to_string(),
Value::PriorityQueue(_) => "priority-queue".to_string(),
Value::OrderedSet(_) => "ordered-set".to_string(),
Value::ListQueue(_) => "list-queue".to_string(),
Value::RandomAccessList(_) => "random-access-list".to_string(),
#[cfg(feature = "async-runtime")]
Value::Future(_) => "future".to_string(),
#[cfg(feature = "async-runtime")]
Value::Channel(_) => "channel".to_string(),
#[cfg(feature = "async-runtime")]
Value::Mutex(_) => "mutex".to_string(),
#[cfg(feature = "async-runtime")]
Value::Semaphore(_) => "semaphore".to_string(),
#[cfg(feature = "async-runtime")]
Value::AtomicCounter(_) => "atomic-counter".to_string(),
#[cfg(feature = "async-runtime")]
Value::DistributedNode(_) => "distributed-node".to_string(),
Value::MutableString(_) => "string".to_string(),
Value::Set(_) => "set".to_string(),
Value::Bag(_) => "bag".to_string(),
Value::Generator(_) => "generator".to_string(),
Value::Opaque(_) => "opaque".to_string(),
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn test_type_of() {
let args = vec![Value::integer(42)];
let result = primitive_type_of(&args).unwrap();
assert_eq!(result, Value::string("number"));
let args = vec![Value::string("hello")];
let result = primitive_type_of(&args).unwrap();
assert_eq!(result, Value::string("string"));
let args = vec![Value::boolean(true)];
let result = primitive_type_of(&args).unwrap();
assert_eq!(result, Value::string("boolean"));
}
#[test]
fn test_type_predicate() {
let not_type = Value::integer(42);
let result = primitive_type_p(&[not_type]).unwrap();
assert_eq!(result, Value::boolean(false));
let type_val = Value::Type(Arc::new(crate::eval::value::TypeValue::Base("number".to_string())));
let result = primitive_type_p(&[type_val]).unwrap();
assert_eq!(result, Value::boolean(true));
}
#[test]
fn test_type_check() {
let args = vec![Value::integer(42), Value::string("number")];
let result = primitive_type_check(&args).unwrap();
assert_eq!(result, Value::boolean(true));
let args = vec![Value::string("hello"), Value::string("number")];
let result = primitive_type_check(&args).unwrap();
assert_eq!(result, Value::boolean(false));
}
#[test]
fn test_type_assert() {
let args = vec![Value::integer(42), Value::string("number")];
let result = primitive_type_assert(&args).unwrap();
assert_eq!(result, Value::integer(42));
let args = vec![Value::string("hello"), Value::string("number")];
let result = primitive_type_assert(&args);
assert!(result.is_err());
}
#[test]
fn test_any_type() {
let result = primitive_any_type(&[]).unwrap();
assert!(matches!(result, Value::Type(_)));
}
}