use std::sync::Arc;
use gluon::{
self,
base::{ast::OwnedExpr, fnv::FnvMap, metadata::Metadata, symbol::Symbol, types::ArcType},
compiler_pipeline::{SalvageResult, TypecheckValue},
import::Importer,
query::AsyncCompilation,
Error as GluonError, ModuleCompiler, Thread, ThreadExt,
};
use {futures::prelude::*, tokio::sync::Mutex, url::Url};
use crate::{
name::module_name_to_file_,
text_edit::{TextChanges, Version},
};
pub(crate) struct Module {
pub source: Arc<gluon::base::source::FileMap>,
pub expr: Arc<OwnedExpr<Symbol>>,
#[allow(unused)] pub metadata: Arc<Metadata>,
pub uri: Url,
}
pub struct State {
pub uri: Url,
pub version: Option<Version>,
pub text_changes: TextChanges,
}
impl State {
pub(crate) fn empty(uri: Url) -> State {
State {
uri,
version: None,
text_changes: TextChanges::new(),
}
}
}
pub(crate) async fn get_module(
thread: &Thread,
module: &str,
) -> gluon::Result<(
Arc<gluon::base::source::FileMap>,
TypecheckValue<Arc<OwnedExpr<Symbol>>>,
)> {
let mut db = thread.get_database();
let m = db
.typechecked_source_module(module.into(), None)
.await
.or_else(|err| err.value.ok_or(err.error))?;
let _ = db.module_type(module.into(), None).await;
let _ = db.module_metadata(module.into(), None).await;
Ok((db.get_filemap(module).expect("Filemap"), m))
}
#[derive(Clone)]
pub(crate) struct CheckImporter(pub(crate) Arc<Mutex<FnvMap<String, State>>>);
impl CheckImporter {
pub(crate) fn new() -> CheckImporter {
CheckImporter(Arc::new(Mutex::new(FnvMap::default())))
}
pub(crate) async fn module(&self, thread: &Thread, module: &str) -> Option<Module> {
let (source, value) = get_module(thread, module)
.await
.map_err(|err| {
dbg!(&err);
err
})
.ok()?;
let uri = {
let map = self.0.lock().await;
map.get(module)?.uri.clone()
};
Some(Module {
source,
expr: value.expr.clone(),
metadata: value.metadata.clone(),
uri,
})
}
pub(crate) async fn modules(&self, thread: &Thread) -> impl Iterator<Item = Module> {
let uris = self
.0
.lock()
.await
.iter()
.map(|(module, s)| (module.clone(), s.uri.clone()))
.collect::<Vec<_>>();
futures::stream::iter(uris)
.filter_map(|(module, uri)| async move {
let (source, value) = get_module(thread, &module).await.ok()?;
Some(Module {
source,
expr: value.expr.clone(),
metadata: value.metadata.clone(),
uri,
})
})
.collect::<Vec<_>>()
.await
.into_iter()
}
}
#[async_trait::async_trait]
impl Importer for CheckImporter {
async fn import(
&self,
compiler: &mut ModuleCompiler<'_, '_>,
_: &Thread,
module_name: &str,
) -> SalvageResult<ArcType> {
compiler
.database
.module_metadata(module_name.into(), None)
.await
.or_else(|err| err.get_value())?;
let typ = compiler
.database
.module_type(module_name.into(), None)
.await
.or_else(|err| err.get_value())?;
self.0.lock().await.insert(
module_name.into(),
State {
uri: module_name_to_file_(module_name)
.map_err(|err| GluonError::from(err.to_string()))?,
version: None,
text_changes: TextChanges::new(),
},
);
Ok(typ)
}
}