iowo/crates/lang/src/world/files.rs

131 lines
3 KiB
Rust

use std::{
clone, fs,
path::{Path, PathBuf},
sync::{Arc, Mutex, RwLock},
};
use dashmap::DashMap;
use rowan::ast::{AstNode, AstPtr};
use crate::{
lst_parser::{
error::SyntaxError, grammar::source_file, input::Input, output::Output, syntax_kind, Parser,
},
Lang,
};
use super::{error::Error, modules::Module, nodes};
#[derive(Clone)]
pub struct Loc<N: AstNode<Language = Lang>> {
file: FileId,
syntax: AstPtr<N>,
}
impl<N: AstNode<Language = Lang>> Loc<N> {
pub fn new(node: N, file: FileId) -> Self {
Self {
file,
syntax: AstPtr::new(&node),
}
}
pub fn file(&self) -> FileId {
self.file
}
pub fn syntax(&self) -> AstPtr<N> {
self.syntax.clone()
}
}
/// global file store
/// contains all known files etc.
#[derive(Clone)]
pub struct Files {
paths: Arc<Mutex<Vec<PathBuf>>>,
store: Arc<DashMap<PathBuf, Arc<SourceFile>>>,
}
impl Files {
pub fn new() -> Self {
Self {
paths: Arc::new(Mutex::new(Vec::new())),
store: Arc::new(DashMap::new()),
}
}
pub fn add_and_parse(&self, path: &Path) -> Result<(FileId, Vec<Error>), std::io::Error> {
let (file, errors) = SourceFile::read_and_parse(&path)?;
// add file to paths and unlock again
let id = {
let path = path.clone();
let mut paths = self.paths.lock().unwrap();
let r = paths.len();
paths.push(path.to_path_buf());
FileId(r)
};
let _ = self.store.insert(path.to_path_buf(), Arc::new(file));
Ok((
id,
errors
.into_iter()
.map(|e| Error::from_syntax(id, e))
.collect(),
))
}
pub fn get(&self, id: FileId) -> Arc<SourceFile> {
let path = {
let paths = self.paths.lock().unwrap();
paths[id.0].clone()
};
self.store.get(&path).unwrap().clone()
}
pub fn get_path(&self, id: FileId) -> PathBuf {
let paths = self.paths.lock().unwrap();
paths[id.0].clone()
}
pub fn path_store(&self) -> Arc<Mutex<Vec<PathBuf>>> {
self.paths.clone()
}
}
pub struct SourceFile {
pub lst: RwLock<rowan::GreenNode>,
root_module: Option<Arc<Module>>,
}
impl SourceFile {
fn read_and_parse(path: &Path) -> Result<(Self, Vec<SyntaxError>), std::io::Error> {
let source_text = fs::read_to_string(&path)?;
let toks = syntax_kind::lex(&source_text);
let input = Input::new(&toks);
let mut parser = Parser::new(input);
source_file(&mut parser);
let events = parser.finish();
let out = Output::from_parser_output(toks, events);
// let lst = out.syntax();
let (lst, errors) = out.dissolve();
Ok((
Self {
lst: RwLock::new(lst),
root_module: None,
},
errors,
))
}
}
#[derive(Debug, Clone, Copy)]
pub struct FileId(pub usize);