use alloc::{string::String, vec::Vec}; use crate::{ Ast, ExprId, SourceForm, SourceId, Value, runtime::{EnvId, ThunkId}, }; #[derive(Debug, Clone)] pub struct Module { pub key: String, pub name: String, pub source: SourceId, pub ast: Ast, pub root: ExprId, pub source_form: SourceForm, pub root_env: EnvId, pub root_thunk: ThunkId, } /// Content resolved by an [`ImportLoader`]. #[derive(Debug, Clone)] pub enum LoadedImport { Source { key: String, name: String, source: String, }, Value { key: String, value: Value, }, } /// An import specifier offered by host-owned language tooling. #[derive(Debug, Clone, PartialEq, Eq)] pub struct ImportCandidate { pub specifier: String, pub detail: Option, } impl ImportCandidate { pub fn new(specifier: impl Into) -> Self { Self { specifier: specifier.into(), detail: None, } } pub fn with_detail(mut self, detail: impl Into) -> Self { self.detail = Some(detail.into()); self } } impl LoadedImport { pub fn source( key: impl Into, name: impl Into, source: impl Into, ) -> Self { Self::Source { key: key.into(), name: name.into(), source: source.into(), } } pub fn value(key: impl Into, value: Value) -> Self { Self::Value { key: key.into(), value, } } } pub trait ImportLoader { fn load(&mut self, current_key: Option<&str>, specifier: &str) -> crate::Result; /// Returns host-resolvable import specifiers matching an unfinished prefix. /// /// Runtime-only loaders may keep the default implementation. Hosts that /// provide an editor should implement this from the same namespace used by /// [`ImportLoader::load`]. fn complete_import( &mut self, _current_key: Option<&str>, _prefix: &str, ) -> crate::Result> { Ok(Vec::new()) } } #[derive(Debug, Clone, Copy, Default)] pub struct EmptyLoader; impl ImportLoader for EmptyLoader { fn load(&mut self, _current_key: Option<&str>, specifier: &str) -> crate::Result { Err(crate::Diagnostic::new( crate::DiagnosticKind::Import, crate::Span::default(), alloc::format!("no source loader is configured for import `{specifier}`"), )) } }