From 3e2c5946c8e03745ffb1d31d97ddeeb168cee442 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Thu, 6 Jun 2024 12:59:30 +0200 Subject: [PATCH] lang: add registry/namespace --- crates/lang/src/ast.rs | 13 ++- crates/lang/src/ast/mod_tree.rs | 68 +++++++++++++--- crates/lang/src/ast/namespace.rs | 103 ++++++++++++++++++++++++ crates/lang/src/ast/path.rs | 94 +++++++++++++++++++++ testfiles/{ => testproj}/hello.owo | 0 testfiles/{ => testproj}/hello/meow.owo | 0 testfiles/{ => testproj}/test.owo | 0 testfiles/{ => testproj}/uwu.owo | 0 8 files changed, 264 insertions(+), 14 deletions(-) create mode 100644 crates/lang/src/ast/namespace.rs create mode 100644 crates/lang/src/ast/path.rs rename testfiles/{ => testproj}/hello.owo (100%) rename testfiles/{ => testproj}/hello/meow.owo (100%) rename testfiles/{ => testproj}/test.owo (100%) rename testfiles/{ => testproj}/uwu.owo (100%) diff --git a/crates/lang/src/ast.rs b/crates/lang/src/ast.rs index 3bbb2f1..0c63620 100644 --- a/crates/lang/src/ast.rs +++ b/crates/lang/src/ast.rs @@ -5,14 +5,18 @@ use rowan::ast::{AstNode, AstPtr}; use self::{ error::{Error, WorldCreationError}, mod_tree::ModuleTree, + namespace::Registry, source_file::SourceFile, }; mod error; mod mod_tree; +mod namespace; mod nodes; +mod path; mod source_file; +#[derive(Debug)] struct Loc { file: PathBuf, syntax_el: AstPtr, @@ -25,6 +29,10 @@ impl Loc { syntax_el: AstPtr::new(syntax_el), } } + + pub fn file(&self) -> &PathBuf { + &self.file + } } pub struct World { @@ -32,6 +40,7 @@ pub struct World { files: HashMap, errors: Vec, module_tree: ModuleTree, + registry: Registry, } impl World { @@ -44,7 +53,8 @@ impl World { 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, registry) = + ModuleTree::parse_from_main(&entry_point, &src); errors.extend(new_errors); module_tree.print_tree(&src.tree()); dbg!(&errors); @@ -56,6 +66,7 @@ impl World { entry_point, errors, module_tree, + registry, }) } } diff --git a/crates/lang/src/ast/mod_tree.rs b/crates/lang/src/ast/mod_tree.rs index 8cc373f..2e5e269 100644 --- a/crates/lang/src/ast/mod_tree.rs +++ b/crates/lang/src/ast/mod_tree.rs @@ -6,13 +6,15 @@ use std::{ sync::Arc, }; -use rowan::ast::AstNode; +use rowan::ast::{AstNode, SyntaxNodePtr}; -use crate::{lst_parser::syntax_kind::SyntaxKind, SyntaxNode}; +use crate::{lst_parser::syntax_kind::SyntaxKind, Lang, SyntaxNode}; use super::{ error::Error, + namespace::Registry, nodes::{self, Mod, ModBody, ModName, Root}, + path::{ItemPath, OwnedItemPath}, source_file::SourceFile, Loc, }; @@ -25,6 +27,7 @@ pub struct ModuleTree { struct ModuleParsingContext { files: Rc>>, errors: Rc>>, + reg: Rc>, proj_dir: Rc, cur_path: Vec, cur_file: PathBuf, @@ -36,6 +39,7 @@ impl ModuleParsingContext { Self { files: Rc::new(RefCell::new(HashMap::new())), errors: Rc::new(RefCell::new(Vec::new())), + reg: Rc::new(RefCell::new(Registry::new())), proj_dir: Rc::new(entry_path.to_owned()), cur_path: Vec::new(), cur_file: entry_path.to_owned(), @@ -79,7 +83,7 @@ impl ModuleParsingContext { node.children() .filter_map(Mod::cast) .filter_map(|m| match Module::parse_mod(m, self.clone()) { - Ok(module) => Some((module.name(), Rc::new(module))), + Ok(module) => Some((module.name(), module)), Err(error) => { self.errors.borrow_mut().push(error); None @@ -88,9 +92,14 @@ impl ModuleParsingContext { .collect::>>() } - fn dissolve(self) -> (HashMap, Vec) { - let Self { files, errors, .. } = self; - (files.take(), errors.take()) + fn dissolve(self) -> (HashMap, Vec, Registry) { + let Self { + files, + errors, + mut reg, + .. + } = self; + (files.take(), errors.take(), (&*reg).take()) } } @@ -98,14 +107,14 @@ impl ModuleTree { pub fn parse_from_main( path: &PathBuf, main_file: &SourceFile, - ) -> (Self, HashMap, Vec) { + ) -> (Self, HashMap, Vec, Registry) { let entry_path = path.parent().unwrap().to_owned(); 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) + let (files, errors, reg) = ctx.dissolve(); + (Self { modules }, files, errors, reg) } pub fn print_tree(&self, lst: &Root) { @@ -114,26 +123,29 @@ impl ModuleTree { } } +#[derive(Debug)] pub struct Module { path: Vec, name: String, kind: ModuleKind, children: Rc>>, parent: Option>, + body: SyntaxNodePtr, } impl Module { - fn parse_mod(module: Mod, ctx: ModuleParsingContext) -> Result { + fn parse_mod(module: Mod, mut ctx: ModuleParsingContext) -> Result, Error> { let children = module .syntax() .children() // .map(|n| n.kind()) .collect::>(); + let r; if children.len() == 1 { let name = &children[0]; assert_eq!(name.kind(), SyntaxKind::MODULE_NAME); - return Self::parse_file_mod( + r = Self::parse_file_mod( name.text().to_string(), ctx.clone(), Loc::new(ctx.cur_file.clone(), &module), @@ -143,9 +155,15 @@ impl Module { 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, ctx.clone())); + r = Ok(Self::parse_inline_mod(module, ctx.clone())); + } else { + unreachable!() } - todo!() + r.map(|module| { + let rc = Rc::new(module); + ctx.reg.borrow_mut().insert_mod(rc.path(), rc.clone()); + rc + }) } fn parse_file_mod( @@ -168,6 +186,7 @@ impl Module { let children = Rc::new(ctx.parse_child_modules(source_file.tree().syntax(), Some(name.clone()))); + let body = SyntaxNodePtr::new(source_file.tree().syntax()); ctx.files .borrow_mut() @@ -182,6 +201,7 @@ impl Module { }, children, parent: None, + body, }) } @@ -205,13 +225,34 @@ impl Module { children, parent: None, path: old_path, + 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); + } + r_p + } + pub fn name(&self) -> String { // self.name.to_node(lst.syntax()).syntax().text().to_string() self.name.clone() } + + pub fn body(&self, files: &HashMap) -> 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(), + } + } } fn print_tree(name: &str, children: Rc>>, level: u32) { @@ -230,6 +271,7 @@ fn print_tree(name: &str, children: Rc>>, level: u32) .for_each(|(name, m)| print_tree(name, m.children.clone(), level + 1)) } +#[derive(Debug)] enum ModuleKind { Inline(Loc), File { diff --git a/crates/lang/src/ast/namespace.rs b/crates/lang/src/ast/namespace.rs new file mode 100644 index 0000000..014a6c8 --- /dev/null +++ b/crates/lang/src/ast/namespace.rs @@ -0,0 +1,103 @@ +use std::{ + cell::RefCell, + collections::{HashMap, HashSet}, + rc::Rc, +}; + +use super::{ + mod_tree::Module, + nodes, + path::{ItemPath, OwnedItemPath}, +}; + +// requires mappings: +// names -> sets of references to individual objects +// paths -> individual objects +// glob paths -> sets of object refs +// (OPT/LATER) names (fuzzy) ~> sets of objects +#[derive(Debug)] +pub struct Registry { + defs: Vec>, + mods: Vec>, + names: HashMap>, + paths: HashMap, +} + +impl Registry { + pub fn new() -> Self { + Self { + defs: Vec::new(), + mods: Vec::new(), + names: HashMap::new(), + paths: HashMap::new(), + } + } + + // TODO: rewrite. has lots of flaws + pub fn insert_mod(&mut self, path: ItemPath<'_>, module: Rc) -> Option { + let idx = self.mods.len(); + let Some(name) = path.name() else { return None }; + self.mods.push(StoreObj::new(&name, Mod { module })); + + if let Some(set) = self.names.get_mut(&name) { + set.insert(RegistryIdx::Mod(idx)); + } else { + self.names + .insert(name, HashSet::from([RegistryIdx::Mod(idx)])); + } + + if self + .paths + .get(&path.clone().into()) + .is_some_and(|other_idx| *other_idx != RegistryIdx::Mod(idx)) + { + return None; + } else { + self.paths.insert(path.into(), RegistryIdx::Mod(idx)) + } + } +} + +impl Default for Registry { + fn default() -> Self { + Self::new() + } +} + +#[derive(PartialEq, Eq, Hash, Debug, Clone, Copy)] +pub enum RegistryIdx { + Def(usize), + Mod(usize), +} + +#[derive(Debug)] +struct StoreObj { + inner: Rc>, +} + +impl StoreObj { + pub fn new(name: impl ToString, item: T) -> Self { + Self { + inner: Rc::new(InnerStoreObj { + name: name.to_string(), + obj: item, + }), + } + } +} + +#[derive(Debug)] +struct InnerStoreObj { + name: String, + obj: T, +} + +#[derive(Debug)] +struct Mod { + module: Rc, +} + +#[derive(Debug)] +struct Def { + node: nodes::Def, +} diff --git a/crates/lang/src/ast/path.rs b/crates/lang/src/ast/path.rs new file mode 100644 index 0000000..a15f141 --- /dev/null +++ b/crates/lang/src/ast/path.rs @@ -0,0 +1,94 @@ +use std::borrow::Cow; + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct ItemPath<'a> { + items: Vec>, +} + +#[derive(Clone, Debug, PartialEq, Eq, Hash)] +pub struct OwnedItemPath { + items: Vec, +} + +impl OwnedItemPath { + pub fn name(&self) -> Option { + self.items.last().cloned() + } +} + +impl From> for OwnedItemPath { + fn from(value: ItemPath<'_>) -> Self { + Self { + items: value + .items + .into_iter() + .map(|v| v.into_owned()) + .collect::>(), + } + } +} + +impl<'a> ItemPath<'a> { + pub fn new() -> Self { + Self { items: Vec::new() } + } + + pub fn from_slices(slice: &[&'a str]) -> Self { + Self { + items: slice.into_iter().map(|i| (*i).into()).collect::>(), + } + } + + pub fn push(mut self, item: impl Into>) -> Self { + self.items.push(item.into()); + self + } + + pub fn name(&self) -> Option { + self.items.last().cloned().map(|item| item.into_owned()) + } +} + +impl<'a> TryFrom> for ItemPath<'a> { + type Error = (); + + fn try_from(value: Pattern<'a>) -> Result { + let mut items = Vec::new(); + + for i in value.items { + match i { + PatternEl::Name(n) => items.push(n), + PatternEl::Glob => return Err(()), + } + } + + Ok(Self { items }) + } +} + +#[derive(Clone, Debug)] +pub struct Pattern<'a> { + items: Vec>, +} + +impl<'a> Pattern<'a> { + pub fn new() -> Self { + Self { items: Vec::new() } + } + + pub fn add_name(mut self, name: &'a str) -> Self { + self.items.push(PatternEl::Name(name.into())); + self + } + + pub fn add_glob(mut self) -> Self { + self.items.push(PatternEl::Glob); + self + } +} + +#[derive(Clone, Debug)] +enum PatternEl<'a> { + Name(Cow<'a, str>), + Glob, +} diff --git a/testfiles/hello.owo b/testfiles/testproj/hello.owo similarity index 100% rename from testfiles/hello.owo rename to testfiles/testproj/hello.owo diff --git a/testfiles/hello/meow.owo b/testfiles/testproj/hello/meow.owo similarity index 100% rename from testfiles/hello/meow.owo rename to testfiles/testproj/hello/meow.owo diff --git a/testfiles/test.owo b/testfiles/testproj/test.owo similarity index 100% rename from testfiles/test.owo rename to testfiles/testproj/test.owo diff --git a/testfiles/uwu.owo b/testfiles/testproj/uwu.owo similarity index 100% rename from testfiles/uwu.owo rename to testfiles/testproj/uwu.owo