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

117 lines
2.7 KiB
Rust
Raw Normal View History

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,
};
use super::{error::Error, modules::Module, nodes};
pub struct Loc<N: AstNode> {
file: FileId,
syntax: AstPtr<N>,
}
#[derive(Clone)]
pub struct Files(Arc<FilesInner>);
impl Files {
pub fn new() -> Self {
Self(Arc::new(FilesInner::new()))
}
pub fn add_and_parse(&self, file: &Path) -> Result<(FileId, Vec<Error>), std::io::Error> {
self.0.add_and_parse(file)
}
pub fn get(&self, id: FileId) -> Arc<SourceFile> {
self.0.get(id)
}
}
/// global file store
/// contains all known files etc.
struct FilesInner {
paths: Mutex<Vec<PathBuf>>,
store: DashMap<PathBuf, Arc<SourceFile>>,
}
impl FilesInner {
fn new() -> Self {
Self {
paths: Mutex::new(Vec::new()),
store: DashMap::new(),
}
}
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(),
))
}
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 struct SourceFile {
pub lst: Mutex<nodes::Root>,
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();
Ok((
Self {
lst: Mutex::new(nodes::Root::cast(lst).unwrap()),
root_module: None,
},
out.errors(),
))
}
}
#[derive(Debug, Clone, Copy)]
pub struct FileId(pub usize);