forked from katzen-cafe/iowo
117 lines
2.7 KiB
Rust
117 lines
2.7 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,
|
||
|
};
|
||
|
|
||
|
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);
|