use crate::ast::Program;
use crate::diagnostics::Result;
use crate::eval::{Evaluator, Value};
use crate::module_system::{ModuleSystem, ImportSpec};
use super::{BootstrapIntegration, BootstrapIntegrationConfig, BootstrapMode};
use std::collections::HashMap;
#[derive(Debug)]
pub struct Runtime {
evaluator: Evaluator,
module_system: ModuleSystem,
}
impl Runtime {
pub fn new() -> Self {
Self::with_bootstrap_config(BootstrapIntegrationConfig::default())
.expect("Failed to create runtime with default bootstrap")
}
pub fn with_bootstrap_config(config: BootstrapIntegrationConfig) -> Result<Self> {
let mut bootstrap = BootstrapIntegration::with_config(config)?;
let global_env_manager = bootstrap.bootstrap()?;
let mut evaluator = Evaluator::new();
Self::merge_bootstrap_environment(&mut evaluator, &global_env_manager)?;
use crate::eval::environment::global_environment;
let final_env = global_environment();
Self::populate_essential_primitives(&final_env)?;
let module_system = ModuleSystem::new().map_err(|e| {
crate::diagnostics::Error::runtime_error(
format!("Failed to create module system: {e}"),
None,
)
})?;
Ok(Self {
evaluator,
module_system,
})
}
pub fn with_fallback() -> Result<Self> {
let config = BootstrapIntegrationConfig {
mode: BootstrapMode::Fallback,
verbose: false,
..Default::default()
};
Self::with_bootstrap_config(config)
}
pub fn eval(&mut self, program: Program) -> Result<Value> {
self.evaluator.eval_program(&program)
}
pub fn expand_macros(&mut self, program: Program) -> Result<Program> {
self.evaluator.macro_expander_mut().expand_program(&program)
}
pub fn type_check(&self, program: Program) -> Result<Program> {
Ok(program)
}
pub fn import_module(&mut self, import_spec: ImportSpec) -> Result<HashMap<String, Value>> {
self.module_system.resolve_import(&import_spec)
}
pub fn evaluator(&self) -> &Evaluator {
&self.evaluator
}
pub fn evaluator_mut(&mut self) -> &mut Evaluator {
&mut self.evaluator
}
pub fn module_system(&self) -> &ModuleSystem {
&self.module_system
}
pub fn module_system_mut(&mut self) -> &mut ModuleSystem {
&mut self.module_system
}
fn merge_bootstrap_environment(
evaluator: &mut Evaluator,
global_env_manager: &super::GlobalEnvironmentManager
) -> Result<()> {
use crate::eval::environment::global_environment;
let evaluator_env = global_environment();
let bootstrap_env = global_env_manager.root_environment();
Self::populate_essential_primitives(&evaluator_env)?;
Ok(())
}
fn populate_essential_primitives(env: &std::rc::Rc<crate::eval::Environment>) -> Result<()> {
use crate::eval::Value;
use crate::eval::value::{PrimitiveProcedure, PrimitiveImpl};
use crate::effects::Effect;
use std::sync::Arc;
env.define("cons".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "cons".to_string(),
arity_min: 2,
arity_max: Some(2),
implementation: PrimitiveImpl::RustFn(Self::primitive_cons),
effects: vec![Effect::Pure],
})));
env.define("car".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "car".to_string(),
arity_min: 1,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(Self::primitive_car),
effects: vec![Effect::Pure],
})));
env.define("cdr".to_string(), Value::Primitive(Arc::new(PrimitiveProcedure {
name: "cdr".to_string(),
arity_min: 1,
arity_max: Some(1),
implementation: PrimitiveImpl::RustFn(Self::primitive_cdr),
effects: vec![Effect::Pure],
})));
println!("DEBUG: Force defined car, cdr, cons primitives in runtime");
Ok(())
}
fn primitive_cons(args: &[Value]) -> Result<Value> {
if args.len() != 2 {
return Err(Box::new(crate::diagnostics::Error::runtime_error(
format!("cons expects 2 arguments, got {}", args.len()),
None,
)));
}
Ok(Value::pair(args[0].clone(), args[1].clone()))
}
fn primitive_car(args: &[Value]) -> Result<Value> {
println!("DEBUG: primitive_car called with {} args", args.len());
if !args.is_empty() {
println!("DEBUG: first arg is: {:?}", args[0]);
}
if args.len() != 1 {
return Err(Box::new(crate::diagnostics::Error::runtime_error(
format!("car expects 1 argument, got {}", args.len()),
None,
)));
}
match &args[0] {
Value::Pair(car, _) => {
let result = (**car).clone();
println!("DEBUG: primitive_car returning: {result:?}");
Ok(result)
}
_ => {
println!("DEBUG: primitive_car error - not a pair: {:?}", args[0]);
Err(Box::new(crate::diagnostics::Error::runtime_error(
"car requires a pair".to_string(),
None,
)))
}
}
}
fn primitive_cdr(args: &[Value]) -> Result<Value> {
if args.len() != 1 {
return Err(Box::new(crate::diagnostics::Error::runtime_error(
format!("cdr expects 1 argument, got {}", args.len()),
None,
)));
}
match &args[0] {
Value::Pair(_, cdr) => Ok((**cdr).clone()),
_ => Err(Box::new(crate::diagnostics::Error::runtime_error(
"cdr requires a pair".to_string(),
None,
))),
}
}
}
impl Default for Runtime {
fn default() -> Self {
Self::new()
}
}