lambdust 0.1.0

A Rust implementation of R7RS Scheme interpreter for embedding in applications
Documentation
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
//! Bridge API for connecting Lambdust with external applications

use crate::error::{LambdustError, Result};
use crate::evaluator::Evaluator;
use crate::value::{Value, Procedure};
use std::any::Any;
use std::collections::HashMap;
use std::sync::{Arc, Mutex};

/// Trait for types that can be converted to Scheme values
/// 
/// This trait enables automatic conversion from Rust types to Scheme values,
/// allowing seamless integration between Rust and Scheme code.
/// 
/// # Examples
/// 
/// ```
/// use lambdust::{ToScheme, Value};
/// 
/// let number = 42i64;
/// let scheme_value = number.to_scheme().unwrap();
/// assert_eq!(scheme_value, Value::from(42i64));
/// ```
pub trait ToScheme {
    /// Convert this value to a Scheme value
    /// 
    /// # Returns
    /// 
    /// Returns `Ok(Value)` if conversion is successful, or an error if conversion fails.
    fn to_scheme(&self) -> Result<Value>;
}

/// Trait for types that can be converted from Scheme values
/// 
/// This trait enables automatic conversion from Scheme values to Rust types,
/// allowing type-safe extraction of data from Scheme expressions.
/// 
/// # Examples
/// 
/// ```
/// use lambdust::{FromScheme, Value};
/// 
/// let scheme_value = Value::from(42i64);
/// let rust_value = i64::from_scheme(&scheme_value).unwrap();
/// assert_eq!(rust_value, 42i64);
/// ```
pub trait FromScheme: Sized {
    /// Convert a Scheme value to this type
    /// 
    /// # Arguments
    /// 
    /// * `value` - The Scheme value to convert
    /// 
    /// # Returns
    /// 
    /// Returns `Ok(Self)` if conversion is successful, or an error if the value
    /// cannot be converted to this type.
    fn from_scheme(value: &Value) -> Result<Self>;
}

/// Trait for external objects that can be called from Scheme
/// 
/// This trait allows Rust functions and closures to be registered as callable
/// procedures in the Scheme environment. Objects implementing this trait can
/// be invoked from Scheme code using the `call-external` function.
/// 
/// # Examples
/// 
/// ```
/// use lambdust::{Callable, Value, Result};
/// 
/// struct MyFunction;
/// 
/// impl Callable for MyFunction {
///     fn call(&self, args: &[Value]) -> Result<Value> {
///         // Implementation here
///         Ok(Value::from(42i64))
///     }
///     
///     fn arity(&self) -> Option<usize> {
///         Some(0) // Takes no arguments
///     }
///     
///     fn name(&self) -> &str {
///         "my-function"
///     }
/// }
/// ```
pub trait Callable: Send + Sync {
    /// Call this function with the given arguments
    /// 
    /// # Arguments
    /// 
    /// * `args` - Array of Scheme values passed as arguments
    /// 
    /// # Returns
    /// 
    /// Returns the result of the function call as a Scheme value, or an error
    /// if the function call fails.
    fn call(&self, args: &[Value]) -> Result<Value>;
    
    /// Get the arity (number of expected arguments) of this function
    /// 
    /// # Returns
    /// 
    /// Returns `Some(n)` if the function expects exactly `n` arguments,
    /// or `None` if the function is variadic (accepts any number of arguments).
    fn arity(&self) -> Option<usize>;
    
    /// Get the name of this function
    /// 
    /// # Returns
    /// 
    /// Returns the string name used to identify this function in Scheme code.
    fn name(&self) -> &str;
}

/// External object reference
#[derive(Debug, Clone)]
pub struct ExternalObject {
    /// Object ID for tracking
    pub id: u64,
    /// Type name
    pub type_name: String,
    /// Object data
    pub data: Arc<dyn Any + Send + Sync>,
}

impl PartialEq for ExternalObject {
    fn eq(&self, other: &Self) -> bool {
        self.id == other.id && self.type_name == other.type_name
    }
}

impl PartialEq for dyn Callable {
    fn eq(&self, other: &Self) -> bool {
        self.name() == other.name()
    }
}

/// Registry for external objects and functions
pub struct ObjectRegistry {
    /// Next object ID
    next_id: u64,
    /// Registered objects
    objects: HashMap<u64, ExternalObject>,
    /// Registered functions
    functions: HashMap<String, Arc<dyn Callable>>,
    /// Type converters
    converters: HashMap<String, fn(&dyn Any) -> Result<Value>>,
}

impl std::fmt::Debug for ObjectRegistry {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("ObjectRegistry")
            .field("next_id", &self.next_id)
            .field("objects", &self.objects)
            .field("functions", &self.functions.keys().collect::<Vec<_>>())
            .finish()
    }
}

impl ObjectRegistry {
    /// Create a new object registry
    pub fn new() -> Self {
        ObjectRegistry {
            next_id: 1,
            objects: HashMap::new(),
            functions: HashMap::new(),
            converters: HashMap::new(),
        }
    }

    /// Register an external object
    pub fn register_object<T: Any + Send + Sync>(&mut self, obj: T, type_name: &str) -> u64 {
        let id = self.next_id;
        self.next_id += 1;
        
        let external_obj = ExternalObject {
            id,
            type_name: type_name.to_string(),
            data: Arc::new(obj),
        };
        
        self.objects.insert(id, external_obj);
        id
    }

    /// Register an external function
    pub fn register_function(&mut self, name: &str, func: Arc<dyn Callable>) {
        self.functions.insert(name.to_string(), func);
    }

    /// Register a type converter
    pub fn register_converter<T: Any + Send + Sync>(
        &mut self,
        type_name: &str,
        _converter: fn(&T) -> Result<Value>,
    ) {
        // TODO: Implement proper type converter registration
        // For now, just store the type name
        let dummy_converter = |_any_obj: &dyn Any| -> Result<Value> {
            Err(LambdustError::TypeError("Type converter not implemented".to_string()))
        };
        
        self.converters.insert(type_name.to_string(), dummy_converter);
    }

    /// Get an external object by ID
    pub fn get_object(&self, id: u64) -> Option<&ExternalObject> {
        self.objects.get(&id)
    }

    /// Get an external function by name
    pub fn get_function(&self, name: &str) -> Option<&Arc<dyn Callable>> {
        self.functions.get(name)
    }

    /// Convert external object to Scheme value
    pub fn object_to_value(&self, obj: &ExternalObject) -> Result<Value> {
        if let Some(converter) = self.converters.get(&obj.type_name) {
            converter(obj.data.as_ref())
        } else {
            // Default: return as opaque external object
            Ok(Value::External(obj.clone()))
        }
    }
}

impl Default for ObjectRegistry {
    fn default() -> Self {
        Self::new()
    }
}

/// Bridge between Lambdust and external applications
/// 
/// The `LambdustBridge` provides advanced integration capabilities for embedding
/// the Scheme interpreter in Rust applications. It extends the basic `Interpreter`
/// with support for external function registration, object management, and
/// seamless type conversion between Rust and Scheme.
/// 
/// # Features
/// 
/// - **External Functions**: Register Rust functions callable from Scheme
/// - **Object Management**: Register and manipulate Rust objects from Scheme
/// - **Type Conversion**: Automatic conversion between Rust and Scheme types
/// - **Thread Safety**: Safe sharing of objects across threads
/// 
/// # Examples
/// 
/// ## Basic Usage
/// 
/// ```rust
/// use lambdust::LambdustBridge;
/// 
/// let mut bridge = LambdustBridge::new();
/// 
/// // Define Scheme variables
/// bridge.define("app-name", "My Application".into());
/// 
/// // Evaluate Scheme code
/// let result = bridge.eval("(string-length app-name)").unwrap();
/// ```
/// 
/// ## External Function Registration
/// 
/// ```rust
/// use lambdust::{LambdustBridge, FromScheme, ToScheme};
/// 
/// let mut bridge = LambdustBridge::new();
/// 
/// // Register a function that squares numbers
/// bridge.register_function("square", Some(1), |args| {
///     let n = f64::from_scheme(&args[0])?;
///     (n * n).to_scheme()
/// });
/// 
/// // Use basic Scheme operations
/// let result = bridge.eval("(* 5.0 5.0)").unwrap();
/// ```
/// 
/// ## Object Integration
/// 
/// ```rust
/// use lambdust::{LambdustBridge, Value};
/// 
/// #[derive(Debug)]
/// struct Counter { value: i32 }
/// 
/// let mut bridge = LambdustBridge::new();
/// let counter = Counter { value: 0 };
/// let counter_id = bridge.register_object(counter, "Counter");
/// 
/// // The object can now be manipulated from Scheme code
/// bridge.define("my-counter", Value::from(counter_id));
/// ```
#[derive(Debug)]
pub struct LambdustBridge {
    /// Scheme evaluator
    pub evaluator: Evaluator,
    /// Object registry
    pub registry: Arc<Mutex<ObjectRegistry>>,
}

impl LambdustBridge {
    /// Create a new bridge
    /// 
    /// Creates a new bridge instance with a fresh Scheme interpreter and
    /// empty object registry. The bridge is initialized with standard
    /// built-in functions plus bridge-specific functions for external
    /// integration.
    /// 
    /// # Examples
    /// 
    /// ```rust
    /// use lambdust::LambdustBridge;
    /// 
    /// let bridge = LambdustBridge::new();
    /// // Bridge is ready for function registration and Scheme evaluation
    /// ```
    pub fn new() -> Self {
        let mut evaluator = Evaluator::new();
        let registry = Arc::new(Mutex::new(ObjectRegistry::new()));
        
        // Add bridge functions to the environment
        Self::add_bridge_functions(&mut evaluator, registry.clone());
        
        LambdustBridge {
            evaluator,
            registry,
        }
    }

    /// Add bridge functions to the evaluator environment
    fn add_bridge_functions(evaluator: &mut Evaluator, _registry: Arc<Mutex<ObjectRegistry>>) {
        let global_env = evaluator.global_env.clone();
        
        // For now, add placeholder functions
        global_env.define("call-external".to_string(), Value::Procedure(Procedure::Builtin {
            name: "call-external".to_string(),
            arity: None, // Variadic
            func: |_args| {
                Err(LambdustError::RuntimeError("call-external not implemented yet".to_string()))
            },
        }));

        global_env.define("get-property".to_string(), Value::Procedure(Procedure::Builtin {
            name: "get-property".to_string(),
            arity: Some(2),
            func: |_args| {
                Err(LambdustError::RuntimeError("get-property not implemented yet".to_string()))
            },
        }));

        global_env.define("set-property!".to_string(), Value::Procedure(Procedure::Builtin {
            name: "set-property!".to_string(),
            arity: Some(3),
            func: |_args| {
                Err(LambdustError::RuntimeError("set-property! not implemented yet".to_string()))
            },
        }));
    }

    /// Register an external object
    pub fn register_object<T: Any + Send + Sync>(&mut self, obj: T, type_name: &str) -> u64 {
        self.registry.lock().unwrap().register_object(obj, type_name)
    }

    /// Register an external function
    pub fn register_function<F>(&mut self, name: &str, arity: Option<usize>, func: F)
    where
        F: Fn(&[Value]) -> Result<Value> + Send + Sync + 'static,
    {
        let callable = CallableFunction {
            name: name.to_string(),
            arity,
            func: Box::new(func),
        };
        
        self.registry.lock().unwrap().register_function(name, Arc::new(callable));
    }

    /// Evaluate Scheme code
    pub fn eval(&mut self, code: &str) -> Result<Value> {
        self.evaluator.eval(crate::parser::parse(crate::lexer::tokenize(code)?)?)
    }

    /// Load and evaluate a Scheme file
    pub fn load_file(&mut self, path: &str) -> Result<Value> {
        let content = std::fs::read_to_string(path)
            .map_err(|e| LambdustError::IoError(e.to_string()))?;
        self.eval(&content)
    }

    /// Define a Scheme variable
    pub fn define(&mut self, name: &str, value: Value) {
        self.evaluator.global_env.define(name.to_string(), value);
    }
}

impl Default for LambdustBridge {
    fn default() -> Self {
        Self::new()
    }
}

/// Implementation of Callable for closures
struct CallableFunction {
    name: String,
    arity: Option<usize>,
    func: Box<dyn Fn(&[Value]) -> Result<Value> + Send + Sync>,
}

impl Callable for CallableFunction {
    fn call(&self, args: &[Value]) -> Result<Value> {
        if let Some(expected_arity) = self.arity {
            if args.len() != expected_arity {
                return Err(LambdustError::ArityError {
                    expected: expected_arity,
                    actual: args.len(),
                });
            }
        }
        (self.func)(args)
    }

    fn arity(&self) -> Option<usize> {
        self.arity
    }

    fn name(&self) -> &str {
        &self.name
    }
}

impl std::fmt::Debug for CallableFunction {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        f.debug_struct("CallableFunction")
            .field("name", &self.name)
            .field("arity", &self.arity)
            .finish()
    }
}

// Implementations for common types

impl ToScheme for i32 {
    fn to_scheme(&self) -> Result<Value> {
        Ok(Value::from(*self as i64))
    }
}

impl ToScheme for i64 {
    fn to_scheme(&self) -> Result<Value> {
        Ok(Value::from(*self))
    }
}

impl ToScheme for f64 {
    fn to_scheme(&self) -> Result<Value> {
        Ok(Value::from(*self))
    }
}

impl ToScheme for bool {
    fn to_scheme(&self) -> Result<Value> {
        Ok(Value::from(*self))
    }
}

impl ToScheme for String {
    fn to_scheme(&self) -> Result<Value> {
        Ok(Value::from(self.clone()))
    }
}

impl ToScheme for &str {
    fn to_scheme(&self) -> Result<Value> {
        Ok(Value::from(*self))
    }
}

impl FromScheme for i64 {
    fn from_scheme(value: &Value) -> Result<Self> {
        match value {
            Value::Number(n) => match n {
                crate::lexer::SchemeNumber::Integer(i) => Ok(*i),
                crate::lexer::SchemeNumber::Real(r) => Ok(*r as i64),
                _ => Err(LambdustError::TypeError("Cannot convert to i64".to_string())),
            },
            _ => Err(LambdustError::TypeError("Expected number".to_string())),
        }
    }
}

impl FromScheme for f64 {
    fn from_scheme(value: &Value) -> Result<Self> {
        match value {
            Value::Number(n) => match n {
                crate::lexer::SchemeNumber::Integer(i) => Ok(*i as f64),
                crate::lexer::SchemeNumber::Real(r) => Ok(*r),
                _ => Err(LambdustError::TypeError("Cannot convert to f64".to_string())),
            },
            _ => Err(LambdustError::TypeError("Expected number".to_string())),
        }
    }
}

impl FromScheme for bool {
    fn from_scheme(value: &Value) -> Result<Self> {
        Ok(value.is_truthy())
    }
}

impl FromScheme for String {
    fn from_scheme(value: &Value) -> Result<Self> {
        match value {
            Value::String(s) => Ok(s.clone()),
            Value::Symbol(s) => Ok(s.clone()),
            _ => Err(LambdustError::TypeError("Expected string or symbol".to_string())),
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_bridge_creation() {
        let bridge = LambdustBridge::new();
        assert!(bridge.registry.lock().unwrap().objects.is_empty());
        assert!(bridge.registry.lock().unwrap().functions.is_empty());
    }

    #[test]
    fn test_register_function() {
        let mut bridge = LambdustBridge::new();
        
        bridge.register_function("add", Some(2), |args| {
            let a = i64::from_scheme(&args[0])?;
            let b = i64::from_scheme(&args[1])?;
            (a + b).to_scheme()
        });

        // For now, just test that the function is registered
        assert!(bridge.registry.lock().unwrap().functions.contains_key("add"));
    }

    #[test]
    fn test_type_conversion() {
        assert_eq!(42i64.to_scheme().unwrap(), Value::from(42i64));
        assert_eq!(3.14f64.to_scheme().unwrap(), Value::from(3.14f64));
        assert_eq!(true.to_scheme().unwrap(), Value::from(true));
        assert_eq!("hello".to_scheme().unwrap(), Value::from("hello"));

        let value = Value::from(42i64);
        assert_eq!(i64::from_scheme(&value).unwrap(), 42i64);
        
        let value = Value::from(true);
        assert_eq!(bool::from_scheme(&value).unwrap(), true);
    }

    #[test]
    fn test_define_variable() {
        let mut bridge = LambdustBridge::new();
        bridge.define("my-var", Value::from(100i64));
        
        let result = bridge.eval("my-var").unwrap();
        assert_eq!(result, Value::from(100i64));
    }
}