iowo/crates/lang/src/ast/mod_tree.rs

282 lines
7.8 KiB
Rust
Raw Normal View History

2024-06-05 18:00:14 +02:00
use std::{
2024-06-05 21:10:52 +02:00
cell::RefCell,
collections::HashMap,
path::{Path, PathBuf},
rc::Rc,
2024-06-05 18:00:14 +02:00
sync::Arc,
};
2024-06-06 12:59:30 +02:00
use rowan::ast::{AstNode, SyntaxNodePtr};
2024-06-05 18:00:14 +02:00
2024-06-06 12:59:30 +02:00
use crate::{lst_parser::syntax_kind::SyntaxKind, Lang, SyntaxNode};
2024-06-05 18:00:14 +02:00
use super::{
error::Error,
2024-06-06 12:59:30 +02:00
namespace::Registry,
2024-06-05 18:00:14 +02:00
nodes::{self, Mod, ModBody, ModName, Root},
2024-06-06 12:59:30 +02:00
path::{ItemPath, OwnedItemPath},
2024-06-05 18:00:14 +02:00
source_file::SourceFile,
Loc,
};
pub struct ModuleTree {
modules: Rc<HashMap<String, Rc<Module>>>,
2024-06-05 21:10:52 +02:00
}
#[derive(Clone)]
struct ModuleParsingContext {
files: Rc<RefCell<HashMap<PathBuf, SourceFile>>>,
errors: Rc<RefCell<Vec<Error>>>,
2024-06-06 12:59:30 +02:00
reg: Rc<RefCell<Registry>>,
2024-06-05 21:10:52 +02:00
proj_dir: Rc<PathBuf>,
cur_path: Vec<String>,
cur_file: PathBuf,
}
impl ModuleParsingContext {
fn new(entry_path: &Path) -> Self {
let proj_dir = entry_path.parent().unwrap().to_owned();
Self {
files: Rc::new(RefCell::new(HashMap::new())),
errors: Rc::new(RefCell::new(Vec::new())),
2024-06-06 12:59:30 +02:00
reg: Rc::new(RefCell::new(Registry::new())),
2024-06-05 21:10:52 +02:00
proj_dir: Rc::new(entry_path.to_owned()),
cur_path: Vec::new(),
cur_file: entry_path.to_owned(),
}
}
fn entry_path(&self) -> PathBuf {
self.proj_dir.to_path_buf()
}
fn make_mod_file_path(&self, mod_path: &[String], mod_name: &str) -> PathBuf {
let mut entry_path = self.entry_path();
for el in mod_path {
entry_path.push(format!("{el}/"));
}
entry_path.push(format!("{mod_name}.owo"));
entry_path
}
fn push_cur_path(&mut self, name_to_add: String) {
self.cur_path.push(name_to_add);
}
fn set_cur_file(&mut self, new: PathBuf) {
self.cur_file = new;
}
fn push_errs(&self, errs: Vec<Error>) {
self.errors.borrow_mut().extend(errs);
}
fn parse_child_modules(
&self,
node: &SyntaxNode,
name: Option<String>,
) -> HashMap<String, Rc<Module>> {
2024-06-05 21:10:52 +02:00
let mut ctx = self.clone();
if let Some(name) = name {
ctx.push_cur_path(name)
}
node.children()
.filter_map(Mod::cast)
.filter_map(|m| match Module::parse_mod(m, self.clone()) {
2024-06-06 12:59:30 +02:00
Ok(module) => Some((module.name(), module)),
2024-06-05 21:10:52 +02:00
Err(error) => {
self.errors.borrow_mut().push(error);
None
}
})
.collect::<HashMap<String, Rc<Module>>>()
2024-06-05 21:10:52 +02:00
}
2024-06-06 12:59:30 +02:00
fn dissolve(self) -> (HashMap<PathBuf, SourceFile>, Vec<Error>, Registry) {
let Self {
files,
errors,
mut reg,
..
} = self;
(files.take(), errors.take(), (&*reg).take())
2024-06-05 21:10:52 +02:00
}
2024-06-05 18:00:14 +02:00
}
impl ModuleTree {
pub fn parse_from_main(
path: &PathBuf,
main_file: &SourceFile,
2024-06-06 12:59:30 +02:00
) -> (Self, HashMap<PathBuf, SourceFile>, Vec<Error>, Registry) {
2024-06-05 18:00:14 +02:00
let entry_path = path.parent().unwrap().to_owned();
2024-06-05 21:10:52 +02:00
let ctx = ModuleParsingContext::new(&entry_path);
let modules = Rc::new(ctx.parse_child_modules(main_file.tree().syntax(), None));
2024-06-05 18:00:14 +02:00
2024-06-06 12:59:30 +02:00
let (files, errors, reg) = ctx.dissolve();
(Self { modules }, files, errors, reg)
2024-06-05 18:00:14 +02:00
}
pub fn print_tree(&self, lst: &Root) {
let name = "main";
2024-06-05 21:10:52 +02:00
print_tree(&name, self.modules.clone(), 0)
2024-06-05 18:00:14 +02:00
}
}
2024-06-06 12:59:30 +02:00
#[derive(Debug)]
2024-06-05 18:00:14 +02:00
pub struct Module {
path: Vec<String>,
name: String,
kind: ModuleKind,
children: Rc<HashMap<String, Rc<Module>>>,
parent: Option<Rc<Module>>,
2024-06-06 12:59:30 +02:00
body: SyntaxNodePtr<Lang>,
2024-06-05 18:00:14 +02:00
}
impl Module {
2024-06-06 12:59:30 +02:00
fn parse_mod(module: Mod, mut ctx: ModuleParsingContext) -> Result<Rc<Self>, Error> {
2024-06-05 18:00:14 +02:00
let children = module
.syntax()
.children()
// .map(|n| n.kind())
.collect::<Vec<_>>();
2024-06-06 12:59:30 +02:00
let r;
2024-06-05 18:00:14 +02:00
if children.len() == 1 {
let name = &children[0];
assert_eq!(name.kind(), SyntaxKind::MODULE_NAME);
2024-06-06 12:59:30 +02:00
r = Self::parse_file_mod(
2024-06-05 18:00:14 +02:00
name.text().to_string(),
2024-06-05 21:10:52 +02:00
ctx.clone(),
Loc::new(ctx.cur_file.clone(), &module),
2024-06-05 18:00:14 +02:00
);
} else if children.len() == 2 {
let name = &children[0];
assert_eq!(name.kind(), SyntaxKind::MODULE_NAME);
let body = &children[1];
assert_eq!(body.kind(), SyntaxKind::MODULE_BODY);
2024-06-06 12:59:30 +02:00
r = Ok(Self::parse_inline_mod(module, ctx.clone()));
} else {
unreachable!()
2024-06-05 18:00:14 +02:00
}
2024-06-06 12:59:30 +02:00
r.map(|module| {
let rc = Rc::new(module);
ctx.reg.borrow_mut().insert_mod(rc.path(), rc.clone());
rc
})
2024-06-05 18:00:14 +02:00
}
fn parse_file_mod(
name: String,
2024-06-05 21:10:52 +02:00
mut ctx: ModuleParsingContext,
2024-06-05 18:00:14 +02:00
decl: Loc<Mod>,
2024-06-05 21:10:52 +02:00
) -> Result<Self, Error> {
ctx.set_cur_file(ctx.make_mod_file_path(&ctx.cur_path, &name));
2024-06-05 18:00:14 +02:00
2024-06-05 21:10:52 +02:00
let source = match std::fs::read_to_string(&ctx.cur_file) {
2024-06-05 18:00:14 +02:00
Ok(f) => f,
2024-06-05 21:10:52 +02:00
Err(e) => return Err(Error::FailedToOpenFileMod(ctx.cur_file, e)),
2024-06-05 18:00:14 +02:00
};
2024-06-05 21:10:52 +02:00
let (source_file, file_errors) = SourceFile::parse_from(&ctx.cur_file, source);
let old_path = ctx.cur_path.clone();
ctx.push_cur_path(name.clone());
ctx.push_errs(file_errors);
let children =
Rc::new(ctx.parse_child_modules(source_file.tree().syntax(), Some(name.clone())));
2024-06-06 12:59:30 +02:00
let body = SyntaxNodePtr::new(source_file.tree().syntax());
2024-06-05 21:10:52 +02:00
ctx.files
.borrow_mut()
.insert(ctx.cur_file.clone(), source_file);
Ok(Self {
path: old_path,
name,
kind: ModuleKind::File {
declaration: decl,
file_id: ctx.cur_file.clone(),
2024-06-05 18:00:14 +02:00
},
2024-06-05 21:10:52 +02:00
children,
parent: None,
2024-06-06 12:59:30 +02:00
body,
2024-06-05 21:10:52 +02:00
})
2024-06-05 18:00:14 +02:00
}
2024-06-05 21:10:52 +02:00
fn parse_inline_mod(module: Mod, mut ctx: ModuleParsingContext) -> Self {
2024-06-05 18:00:14 +02:00
let mut children = module.syntax().children().collect::<Vec<_>>();
let body = ModBody::cast(children.pop().unwrap()).unwrap();
2024-06-05 21:10:52 +02:00
let name = ModName::cast(children.pop().unwrap())
.unwrap()
2024-06-05 18:00:14 +02:00
.syntax()
2024-06-05 21:10:52 +02:00
.text()
.to_string();
let old_path = ctx.cur_path.clone();
ctx.push_cur_path(name.clone());
let children = Rc::new(ctx.parse_child_modules(body.syntax(), Some(name.clone())));
Self {
name,
kind: ModuleKind::Inline(Loc::new(ctx.cur_file.to_owned(), &module)),
children,
parent: None,
path: old_path,
2024-06-06 12:59:30 +02:00
body: SyntaxNodePtr::new(body.syntax()),
}
}
pub fn path(&self) -> ItemPath {
let mut p = self.path.clone();
p.push(self.name());
let mut r_p = ItemPath::new();
for i in p {
r_p = r_p.push(i);
2024-06-05 21:10:52 +02:00
}
2024-06-06 12:59:30 +02:00
r_p
2024-06-05 18:00:14 +02:00
}
pub fn name(&self) -> String {
// self.name.to_node(lst.syntax()).syntax().text().to_string()
self.name.clone()
}
2024-06-06 12:59:30 +02:00
pub fn body(&self, files: &HashMap<PathBuf, SourceFile>) -> SyntaxNode {
match &self.kind {
ModuleKind::Inline(l) => {
let file = files.get(l.file()).unwrap();
self.body.to_node(file.tree().syntax())
}
ModuleKind::File { file_id, .. } => files.get(file_id).unwrap().tree().syntax().clone(),
}
}
2024-06-05 18:00:14 +02:00
}
fn print_tree(name: &str, children: Rc<HashMap<String, Rc<Module>>>, level: u32) {
2024-06-05 18:00:14 +02:00
const INDENT_STR: &str = " ";
for _ in 0..level {
print!("{}", INDENT_STR);
}
print!("{name}\n");
2024-06-05 21:10:52 +02:00
// for (name, module) in children.iter() {
// ;
// }
children
.iter()
.for_each(|(name, m)| print_tree(name, m.children.clone(), level + 1))
2024-06-05 18:00:14 +02:00
}
2024-06-06 12:59:30 +02:00
#[derive(Debug)]
2024-06-05 18:00:14 +02:00
enum ModuleKind {
Inline(Loc<nodes::Mod>),
File {
declaration: Loc<nodes::Mod>,
file_id: PathBuf,
},
}