lang: module resolvin

This commit is contained in:
Schrottkatze 2024-06-05 21:10:52 +02:00
parent d6bc644fb6
commit 7bc603f7e7
Signed by: schrottkatze
SSH key fingerprint: SHA256:hXb3t1vINBFCiDCmhRABHX5ocdbLiKyCdKI4HK2Rbbc
5 changed files with 148 additions and 156 deletions

8
Cargo.lock generated
View file

@ -850,9 +850,9 @@ checksum = "ec0be4795e2f6a28069bec0b5ff3e2ac9bafc99e6a9a7dc3547996c5c816922c"
[[package]] [[package]]
name = "rayon" name = "rayon"
version = "1.8.0" version = "1.10.0"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "9c27db03db7734835b3f53954b534c91069375ce6ccaa2e065441e07d9b6cdb1" checksum = "b418a60154510ca1a002a752ca9714984e21e4241e804d32555251faf8b78ffa"
dependencies = [ dependencies = [
"either", "either",
"rayon-core", "rayon-core",
@ -860,9 +860,9 @@ dependencies = [
[[package]] [[package]]
name = "rayon-core" name = "rayon-core"
version = "1.12.0" version = "1.12.1"
source = "registry+https://github.com/rust-lang/crates.io-index" source = "registry+https://github.com/rust-lang/crates.io-index"
checksum = "5ce3fb6ad83f861aac485e76e1985cd109d9a3713802152be56c3b1f0e0658ed" checksum = "1465873a3dfdaa8ae7cb14b4383657caab0b3e8a0aa9ae8e04b044854c8dfce2"
dependencies = [ dependencies = [
"crossbeam-deque", "crossbeam-deque",
"crossbeam-utils", "crossbeam-utils",

View file

@ -1,10 +1,10 @@
use std::{collections::HashMap, path::PathBuf, sync::Arc}; use std::{collections::HashMap, path::PathBuf};
use rowan::ast::{AstNode, AstPtr}; use rowan::ast::{AstNode, AstPtr};
use self::{ use self::{
error::{Error, WorldCreationError}, error::{Error, WorldCreationError},
mod_tree::{Module, ModuleTree}, mod_tree::ModuleTree,
source_file::SourceFile, source_file::SourceFile,
}; };
@ -42,7 +42,7 @@ impl World {
Err(e) => return Err(WorldCreationError::FailedToOpenEntryPoint(entry_point, e)), 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); let (module_tree, mut files, new_errors) = ModuleTree::parse_from_main(&entry_point, &src);
errors.extend(new_errors); errors.extend(new_errors);

View file

@ -1,10 +1,12 @@
use std::{ use std::{
collections::{HashMap, HashSet}, cell::RefCell,
path::PathBuf, collections::HashMap,
path::{Path, PathBuf},
rc::Rc,
sync::Arc, sync::Arc,
}; };
use rowan::ast::{AstNode, AstPtr}; use rowan::ast::AstNode;
use crate::{lst_parser::syntax_kind::SyntaxKind, SyntaxNode}; use crate::{lst_parser::syntax_kind::SyntaxKind, SyntaxNode};
@ -16,7 +18,80 @@ use super::{
}; };
pub struct ModuleTree { pub struct ModuleTree {
modules: HashMap<String, Arc<Module>>, modules: Rc<HashMap<String, Module>>,
}
#[derive(Clone)]
struct ModuleParsingContext {
files: Rc<RefCell<HashMap<PathBuf, SourceFile>>>,
errors: Rc<RefCell<Vec<Error>>>,
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())),
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, Module> {
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::<HashMap<String, Module>>()
}
fn dissolve(self) -> (HashMap<PathBuf, SourceFile>, Vec<Error>) {
let Self { files, errors, .. } = self;
(files.take(), errors.take())
}
} }
impl ModuleTree { impl ModuleTree {
@ -24,37 +99,18 @@ impl ModuleTree {
path: &PathBuf, path: &PathBuf,
main_file: &SourceFile, main_file: &SourceFile,
) -> (Self, HashMap<PathBuf, SourceFile>, Vec<Error>) { ) -> (Self, HashMap<PathBuf, SourceFile>, Vec<Error>) {
let tree = main_file.tree();
let mut files = HashMap::new();
let mut errors = Vec::new();
let entry_path = path.parent().unwrap().to_owned(); let entry_path = path.parent().unwrap().to_owned();
let modules = main_file let ctx = ModuleParsingContext::new(&entry_path);
.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::<HashMap<String, Arc<Module>>>();
let modules = Rc::new(ctx.parse_child_modules(main_file.tree().syntax(), None));
let (files, errors) = ctx.dissolve();
(Self { modules }, files, errors) (Self { modules }, files, errors)
} }
pub fn print_tree(&self, lst: &Root) { pub fn print_tree(&self, lst: &Root) {
let name = "main"; 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<String>, path: Vec<String>,
name: String, name: String,
kind: ModuleKind, kind: ModuleKind,
children: HashMap<String, Arc<Module>>, children: Rc<HashMap<String, Module>>,
parent: Option<Arc<Module>>, parent: Option<Arc<Module>>,
} }
impl Module { impl Module {
fn parse_mod( fn parse_mod(module: Mod, ctx: ModuleParsingContext) -> Result<Self, Error> {
module: Mod,
cur_path: Vec<String>,
cur_file: &PathBuf,
entry_path: &PathBuf,
) -> Result<(Self, HashMap<PathBuf, SourceFile>, Vec<Error>), Error> {
dbg!(cur_file);
dbg!(entry_path);
let children = module let children = module
.syntax() .syntax()
.children() .children()
@ -86,138 +135,77 @@ impl Module {
assert_eq!(name.kind(), SyntaxKind::MODULE_NAME); assert_eq!(name.kind(), SyntaxKind::MODULE_NAME);
return Self::parse_file_mod( return Self::parse_file_mod(
name.text().to_string(), name.text().to_string(),
Loc::new(cur_file.clone(), &module), ctx.clone(),
cur_path, Loc::new(ctx.cur_file.clone(), &module),
entry_path,
); );
} else if children.len() == 2 { } else if children.len() == 2 {
let name = &children[0]; let name = &children[0];
assert_eq!(name.kind(), SyntaxKind::MODULE_NAME); assert_eq!(name.kind(), SyntaxKind::MODULE_NAME);
let body = &children[1]; let body = &children[1];
assert_eq!(body.kind(), SyntaxKind::MODULE_BODY); assert_eq!(body.kind(), SyntaxKind::MODULE_BODY);
return Ok(Self::parse_inline_mod( return Ok(Self::parse_inline_mod(module, ctx.clone()));
module, cur_path, cur_file, entry_path,
));
} }
todo!() todo!()
} }
fn parse_file_mod( fn parse_file_mod(
name: String, name: String,
mut ctx: ModuleParsingContext,
decl: Loc<Mod>, decl: Loc<Mod>,
mut cur_path: Vec<String>, ) -> Result<Self, Error> {
entry_path: &PathBuf, ctx.set_cur_file(ctx.make_mod_file_path(&ctx.cur_path, &name));
) -> Result<(Self, HashMap<PathBuf, SourceFile>, Vec<Error>), Error> {
let mut mod_file_path = entry_path.to_owned();
for el in &cur_path { let source = match std::fs::read_to_string(&ctx.cur_file) {
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)) {
Ok(f) => f, 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); let (source_file, file_errors) = SourceFile::parse_from(&ctx.cur_file, source);
errors.extend(file_errors);
let tree = source_file.tree(); let old_path = ctx.cur_path.clone();
let old_path = cur_path.clone(); ctx.push_cur_path(name.clone());
cur_path.push(name.clone()); ctx.push_errs(file_errors);
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::<HashMap<String, Arc<Module>>>();
files.insert(mod_file_path.clone(), source_file); let children =
Rc::new(ctx.parse_child_modules(source_file.tree().syntax(), Some(name.clone())));
Ok(( ctx.files
Self { .borrow_mut()
path: old_path, .insert(ctx.cur_file.clone(), source_file);
name,
kind: ModuleKind::File { Ok(Self {
declaration: decl, path: old_path,
file_id: mod_file_path, name,
}, kind: ModuleKind::File {
children, declaration: decl,
parent: None, file_id: ctx.cur_file.clone(),
}, },
files, children,
errors, parent: None,
)) })
} }
fn parse_inline_mod( fn parse_inline_mod(module: Mod, mut ctx: ModuleParsingContext) -> Self {
module: Mod,
mut cur_path: Vec<String>,
cur_file: &PathBuf,
entry_path: &PathBuf,
) -> (Self, HashMap<PathBuf, SourceFile>, Vec<Error>) {
let mut children = module.syntax().children().collect::<Vec<_>>(); let mut children = module.syntax().children().collect::<Vec<_>>();
let body = ModBody::cast(children.pop().unwrap()).unwrap(); let body = ModBody::cast(children.pop().unwrap()).unwrap();
let name = ModName::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
.syntax() .syntax()
.children() .text()
.filter_map(|node| Mod::cast(node)) .to_string();
.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::<HashMap<String, Arc<Module>>>();
( let old_path = ctx.cur_path.clone();
Self { ctx.push_cur_path(name.clone());
name: name.syntax().text().to_string(), let children = Rc::new(ctx.parse_child_modules(body.syntax(), Some(name.clone())));
kind: ModuleKind::Inline(Loc::new(cur_file.to_owned(), &module)),
children, Self {
parent: None, name,
path: old_path, kind: ModuleKind::Inline(Loc::new(ctx.cur_file.to_owned(), &module)),
}, children,
files, parent: None,
errors, path: old_path,
) }
} }
pub fn name(&self) -> String { pub fn name(&self) -> String {
@ -226,7 +214,7 @@ impl Module {
} }
} }
fn print_tree(name: &str, children: &HashMap<String, Arc<Module>>, level: u32) { fn print_tree(name: &str, children: Rc<HashMap<String, Module>>, level: u32) {
const INDENT_STR: &str = " "; const INDENT_STR: &str = " ";
for _ in 0..level { for _ in 0..level {
@ -234,9 +222,12 @@ fn print_tree(name: &str, children: &HashMap<String, Arc<Module>>, level: u32) {
} }
print!("{name}\n"); print!("{name}\n");
for (name, module) in children { // for (name, module) in children.iter() {
print_tree(name, &module.children, level + 1); // ;
} // }
children
.iter()
.for_each(|(name, m)| print_tree(name, m.children.clone(), level + 1))
} }
enum ModuleKind { enum ModuleKind {

View file

@ -4,7 +4,7 @@ use rowan::Language;
macro_rules! ast_nodes { macro_rules! ast_nodes {
($($ast:ident, $kind:ident);+) => { ($($ast:ident, $kind:ident);+) => {
$( $(
#[derive(PartialEq, Eq, Hash)] #[derive(Debug, PartialEq, Eq, Hash)]
#[repr(transparent)] #[repr(transparent)]
pub struct $ast(SyntaxNode); pub struct $ast(SyntaxNode);
impl rowan::ast::AstNode for $ast { impl rowan::ast::AstNode for $ast {

View file

@ -1,4 +1,4 @@
use std::path::PathBuf; use std::path::{Path, PathBuf};
use rowan::ast::{AstNode, AstPtr}; use rowan::ast::{AstNode, AstPtr};
@ -15,6 +15,7 @@ use super::{
nodes::{Def, Mod, Root, Use}, nodes::{Def, Mod, Root, Use},
}; };
#[derive(Debug)]
pub struct SourceFile { pub struct SourceFile {
lst: Root, lst: Root,
modules: Vec<AstPtr<Mod>>, modules: Vec<AstPtr<Mod>>,
@ -23,7 +24,7 @@ pub struct SourceFile {
} }
impl SourceFile { impl SourceFile {
pub fn parse_from(path: PathBuf, source_text: String) -> (Self, Vec<Error>) { pub fn parse_from(path: &Path, source_text: String) -> (Self, Vec<Error>) {
let toks = syntax_kind::lex(&source_text); let toks = syntax_kind::lex(&source_text);
let input = Input::new(&toks); let input = Input::new(&toks);
let mut parser = Parser::new(input); let mut parser = Parser::new(input);
@ -57,7 +58,7 @@ impl SourceFile {
}, },
out.errors() out.errors()
.into_iter() .into_iter()
.map(|err| Error::from_syntax(path.clone(), err)) .map(|err| Error::from_syntax(path.to_owned(), err))
.collect(), .collect(),
) )
} }