From 7bc603f7e70fc81a1519a7f5aad2c451bbd0b0b3 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Wed, 5 Jun 2024 21:10:52 +0200 Subject: [PATCH] lang: module resolvin --- Cargo.lock | 8 +- crates/lang/src/ast.rs | 6 +- crates/lang/src/ast/mod_tree.rs | 281 ++++++++++++++--------------- crates/lang/src/ast/nodes.rs | 2 +- crates/lang/src/ast/source_file.rs | 7 +- 5 files changed, 148 insertions(+), 156 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index cc9818c..eaa8be7 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -850,9 +850,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c" [[package]] name = "rayon" -version = "1.8.0" +version = "1.10.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" +checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa" dependencies = [ "either", "rayon-core", @@ -860,9 +860,9 @@ dependencies = [ [[package]] name = "rayon-core" -version = "1.12.0" +version = "1.12.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" +checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2" dependencies = [ "crossbeam-deque", "crossbeam-utils", diff --git a/crates/lang/src/ast.rs b/crates/lang/src/ast.rs index 1375694..6ff6b03 100644 --- a/crates/lang/src/ast.rs +++ b/crates/lang/src/ast.rs @@ -1,10 +1,10 @@ -use std::{collections::HashMap, path::PathBuf, sync::Arc}; +use std::{collections::HashMap, path::PathBuf}; use rowan::ast::{AstNode, AstPtr}; use self::{ error::{Error, WorldCreationError}, - mod_tree::{Module, ModuleTree}, + mod_tree::ModuleTree, source_file::SourceFile, }; @@ -42,7 +42,7 @@ impl World { Err(e) => return Err(WorldCreationError::FailedToOpenEntryPoint(entry_point, e)), }; - let (src, mut errors) = SourceFile::parse_from(entry_point.clone(), source); + let (src, mut errors) = SourceFile::parse_from(&entry_point, source); let (module_tree, mut files, new_errors) = ModuleTree::parse_from_main(&entry_point, &src); errors.extend(new_errors); diff --git a/crates/lang/src/ast/mod_tree.rs b/crates/lang/src/ast/mod_tree.rs index 035faec..35df053 100644 --- a/crates/lang/src/ast/mod_tree.rs +++ b/crates/lang/src/ast/mod_tree.rs @@ -1,10 +1,12 @@ use std::{ - collections::{HashMap, HashSet}, - path::PathBuf, + cell::RefCell, + collections::HashMap, + path::{Path, PathBuf}, + rc::Rc, sync::Arc, }; -use rowan::ast::{AstNode, AstPtr}; +use rowan::ast::AstNode; use crate::{lst_parser::syntax_kind::SyntaxKind, SyntaxNode}; @@ -16,7 +18,80 @@ use super::{ }; pub struct ModuleTree { - modules: HashMap>, + modules: Rc>, +} + +#[derive(Clone)] +struct ModuleParsingContext { + files: Rc>>, + errors: Rc>>, + proj_dir: Rc, + cur_path: Vec, + 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())), + 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) { + self.errors.borrow_mut().extend(errs); + } + + fn parse_child_modules( + &self, + node: &SyntaxNode, + name: Option, + ) -> HashMap { + 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()) { + Ok(module) => Some((module.name(), module)), + Err(error) => { + self.errors.borrow_mut().push(error); + None + } + }) + .collect::>() + } + + fn dissolve(self) -> (HashMap, Vec) { + let Self { files, errors, .. } = self; + (files.take(), errors.take()) + } } impl ModuleTree { @@ -24,37 +99,18 @@ impl ModuleTree { path: &PathBuf, main_file: &SourceFile, ) -> (Self, HashMap, Vec) { - let tree = main_file.tree(); - let mut files = HashMap::new(); - let mut errors = Vec::new(); - let entry_path = path.parent().unwrap().to_owned(); - let modules = main_file - .top_level_modules() - .into_iter() - .filter_map(|m| { - let module = - Module::parse_mod(m.to_node(tree.syntax()), Vec::new(), &path, &entry_path); - match module { - Ok(module) => { - files.extend(module.1); - errors.extend(module.2); - Some((module.0.name(), Arc::new(module.0))) - } - Err(err) => { - errors.push(err); - None - } - } - }) - .collect::>>(); + let ctx = ModuleParsingContext::new(&entry_path); + let modules = Rc::new(ctx.parse_child_modules(main_file.tree().syntax(), None)); + + let (files, errors) = ctx.dissolve(); (Self { modules }, files, errors) } pub fn print_tree(&self, lst: &Root) { let name = "main"; - print_tree(&name, &self.modules, 0) + print_tree(&name, self.modules.clone(), 0) } } @@ -62,19 +118,12 @@ pub struct Module { path: Vec, name: String, kind: ModuleKind, - children: HashMap>, + children: Rc>, parent: Option>, } impl Module { - fn parse_mod( - module: Mod, - cur_path: Vec, - cur_file: &PathBuf, - entry_path: &PathBuf, - ) -> Result<(Self, HashMap, Vec), Error> { - dbg!(cur_file); - dbg!(entry_path); + fn parse_mod(module: Mod, ctx: ModuleParsingContext) -> Result { let children = module .syntax() .children() @@ -86,138 +135,77 @@ impl Module { assert_eq!(name.kind(), SyntaxKind::MODULE_NAME); return Self::parse_file_mod( name.text().to_string(), - Loc::new(cur_file.clone(), &module), - cur_path, - entry_path, + ctx.clone(), + Loc::new(ctx.cur_file.clone(), &module), ); } 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); - return Ok(Self::parse_inline_mod( - module, cur_path, cur_file, entry_path, - )); + return Ok(Self::parse_inline_mod(module, ctx.clone())); } todo!() } fn parse_file_mod( name: String, + mut ctx: ModuleParsingContext, decl: Loc, - mut cur_path: Vec, - entry_path: &PathBuf, - ) -> Result<(Self, HashMap, Vec), Error> { - let mut mod_file_path = entry_path.to_owned(); + ) -> Result { + ctx.set_cur_file(ctx.make_mod_file_path(&ctx.cur_path, &name)); - for el in &cur_path { - mod_file_path.push(format!("{el}/")); - } - mod_file_path.push(format!("{name}.owo")); - - let mut files = HashMap::new(); - let mut errors = Vec::new(); - - let source = match std::fs::read_to_string(dbg!(&mod_file_path)) { + let source = match std::fs::read_to_string(&ctx.cur_file) { Ok(f) => f, - Err(e) => return Err(Error::FailedToOpenFileMod(mod_file_path, e)), + Err(e) => return Err(Error::FailedToOpenFileMod(ctx.cur_file, e)), }; - let (source_file, file_errors) = SourceFile::parse_from(mod_file_path.clone(), source); - errors.extend(file_errors); + let (source_file, file_errors) = SourceFile::parse_from(&ctx.cur_file, source); - let tree = source_file.tree(); - let old_path = cur_path.clone(); - cur_path.push(name.clone()); - let children = source_file - .top_level_modules() - .into_iter() - .filter_map(|m| { - let module = Module::parse_mod( - m.to_node(tree.syntax()), - cur_path.clone(), - &mod_file_path, - &entry_path, - ); - match module { - Ok(module) => { - files.extend(module.1); - errors.extend(module.2); - Some((module.0.name(), Arc::new(module.0))) - } - Err(err) => { - errors.push(err); - None - } - } - }) - .collect::>>(); + let old_path = ctx.cur_path.clone(); + ctx.push_cur_path(name.clone()); + ctx.push_errs(file_errors); - files.insert(mod_file_path.clone(), source_file); + let children = + Rc::new(ctx.parse_child_modules(source_file.tree().syntax(), Some(name.clone()))); - Ok(( - Self { - path: old_path, - name, - kind: ModuleKind::File { - declaration: decl, - file_id: mod_file_path, - }, - children, - parent: None, + 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(), }, - files, - errors, - )) + children, + parent: None, + }) } - fn parse_inline_mod( - module: Mod, - mut cur_path: Vec, - cur_file: &PathBuf, - entry_path: &PathBuf, - ) -> (Self, HashMap, Vec) { + fn parse_inline_mod(module: Mod, mut ctx: ModuleParsingContext) -> Self { let mut children = module.syntax().children().collect::>(); let body = ModBody::cast(children.pop().unwrap()).unwrap(); - let name = ModName::cast(children.pop().unwrap()).unwrap(); - - let mut files = HashMap::new(); - let mut errors = Vec::new(); - - let old_path = cur_path.clone(); - cur_path.push(name.syntax().to_string()); - let children = body + let name = ModName::cast(children.pop().unwrap()) + .unwrap() .syntax() - .children() - .filter_map(|node| Mod::cast(node)) - .filter_map(|m| { - let m = Self::parse_mod(m, cur_path.clone(), cur_file, entry_path); - match m { - Ok(module) => { - files.extend(module.1); - errors.extend(module.2); - Some((module.0.name(), Arc::new(module.0))) - } - Err(err) => { - errors.push(err); - None - } - } - }) - .collect::>>(); + .text() + .to_string(); - ( - Self { - name: name.syntax().text().to_string(), - kind: ModuleKind::Inline(Loc::new(cur_file.to_owned(), &module)), - children, - parent: None, - path: old_path, - }, - files, - errors, - ) + 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, + } } pub fn name(&self) -> String { @@ -226,7 +214,7 @@ impl Module { } } -fn print_tree(name: &str, children: &HashMap>, level: u32) { +fn print_tree(name: &str, children: Rc>, level: u32) { const INDENT_STR: &str = " "; for _ in 0..level { @@ -234,9 +222,12 @@ fn print_tree(name: &str, children: &HashMap>, level: u32) { } print!("{name}\n"); - for (name, module) in children { - print_tree(name, &module.children, level + 1); - } + // for (name, module) in children.iter() { + // ; + // } + children + .iter() + .for_each(|(name, m)| print_tree(name, m.children.clone(), level + 1)) } enum ModuleKind { diff --git a/crates/lang/src/ast/nodes.rs b/crates/lang/src/ast/nodes.rs index e59c0f3..744596e 100644 --- a/crates/lang/src/ast/nodes.rs +++ b/crates/lang/src/ast/nodes.rs @@ -4,7 +4,7 @@ use rowan::Language; macro_rules! ast_nodes { ($($ast:ident, $kind:ident);+) => { $( - #[derive(PartialEq, Eq, Hash)] + #[derive(Debug, PartialEq, Eq, Hash)] #[repr(transparent)] pub struct $ast(SyntaxNode); impl rowan::ast::AstNode for $ast { diff --git a/crates/lang/src/ast/source_file.rs b/crates/lang/src/ast/source_file.rs index e6e33be..912decd 100644 --- a/crates/lang/src/ast/source_file.rs +++ b/crates/lang/src/ast/source_file.rs @@ -1,4 +1,4 @@ -use std::path::PathBuf; +use std::path::{Path, PathBuf}; use rowan::ast::{AstNode, AstPtr}; @@ -15,6 +15,7 @@ use super::{ nodes::{Def, Mod, Root, Use}, }; +#[derive(Debug)] pub struct SourceFile { lst: Root, modules: Vec>, @@ -23,7 +24,7 @@ pub struct SourceFile { } impl SourceFile { - pub fn parse_from(path: PathBuf, source_text: String) -> (Self, Vec) { + pub fn parse_from(path: &Path, source_text: String) -> (Self, Vec) { let toks = syntax_kind::lex(&source_text); let input = Input::new(&toks); let mut parser = Parser::new(input); @@ -57,7 +58,7 @@ impl SourceFile { }, out.errors() .into_iter() - .map(|err| Error::from_syntax(path.clone(), err)) + .map(|err| Error::from_syntax(path.to_owned(), err)) .collect(), ) }