lang: add registry/namespace

This commit is contained in:
Schrottkatze 2024-06-06 12:59:30 +02:00
parent 1a533eb788
commit 3e2c5946c8
No known key found for this signature in database
8 changed files with 264 additions and 14 deletions

View file

@ -5,14 +5,18 @@ use rowan::ast::{AstNode, AstPtr};
use self::{ use self::{
error::{Error, WorldCreationError}, error::{Error, WorldCreationError},
mod_tree::ModuleTree, mod_tree::ModuleTree,
namespace::Registry,
source_file::SourceFile, source_file::SourceFile,
}; };
mod error; mod error;
mod mod_tree; mod mod_tree;
mod namespace;
mod nodes; mod nodes;
mod path;
mod source_file; mod source_file;
#[derive(Debug)]
struct Loc<T: AstNode> { struct Loc<T: AstNode> {
file: PathBuf, file: PathBuf,
syntax_el: AstPtr<T>, syntax_el: AstPtr<T>,
@ -25,6 +29,10 @@ impl<T: AstNode> Loc<T> {
syntax_el: AstPtr::new(syntax_el), syntax_el: AstPtr::new(syntax_el),
} }
} }
pub fn file(&self) -> &PathBuf {
&self.file
}
} }
pub struct World { pub struct World {
@ -32,6 +40,7 @@ pub struct World {
files: HashMap<PathBuf, SourceFile>, files: HashMap<PathBuf, SourceFile>,
errors: Vec<Error>, errors: Vec<Error>,
module_tree: ModuleTree, module_tree: ModuleTree,
registry: Registry,
} }
impl World { impl World {
@ -44,7 +53,8 @@ impl World {
let (src, mut errors) = SourceFile::parse_from(&entry_point, 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, registry) =
ModuleTree::parse_from_main(&entry_point, &src);
errors.extend(new_errors); errors.extend(new_errors);
module_tree.print_tree(&src.tree()); module_tree.print_tree(&src.tree());
dbg!(&errors); dbg!(&errors);
@ -56,6 +66,7 @@ impl World {
entry_point, entry_point,
errors, errors,
module_tree, module_tree,
registry,
}) })
} }
} }

View file

@ -6,13 +6,15 @@ use std::{
sync::Arc, 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::{ use super::{
error::Error, error::Error,
namespace::Registry,
nodes::{self, Mod, ModBody, ModName, Root}, nodes::{self, Mod, ModBody, ModName, Root},
path::{ItemPath, OwnedItemPath},
source_file::SourceFile, source_file::SourceFile,
Loc, Loc,
}; };
@ -25,6 +27,7 @@ pub struct ModuleTree {
struct ModuleParsingContext { struct ModuleParsingContext {
files: Rc<RefCell<HashMap<PathBuf, SourceFile>>>, files: Rc<RefCell<HashMap<PathBuf, SourceFile>>>,
errors: Rc<RefCell<Vec<Error>>>, errors: Rc<RefCell<Vec<Error>>>,
reg: Rc<RefCell<Registry>>,
proj_dir: Rc<PathBuf>, proj_dir: Rc<PathBuf>,
cur_path: Vec<String>, cur_path: Vec<String>,
cur_file: PathBuf, cur_file: PathBuf,
@ -36,6 +39,7 @@ impl ModuleParsingContext {
Self { Self {
files: Rc::new(RefCell::new(HashMap::new())), files: Rc::new(RefCell::new(HashMap::new())),
errors: Rc::new(RefCell::new(Vec::new())), errors: Rc::new(RefCell::new(Vec::new())),
reg: Rc::new(RefCell::new(Registry::new())),
proj_dir: Rc::new(entry_path.to_owned()), proj_dir: Rc::new(entry_path.to_owned()),
cur_path: Vec::new(), cur_path: Vec::new(),
cur_file: entry_path.to_owned(), cur_file: entry_path.to_owned(),
@ -79,7 +83,7 @@ impl ModuleParsingContext {
node.children() node.children()
.filter_map(Mod::cast) .filter_map(Mod::cast)
.filter_map(|m| match Module::parse_mod(m, self.clone()) { .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) => { Err(error) => {
self.errors.borrow_mut().push(error); self.errors.borrow_mut().push(error);
None None
@ -88,9 +92,14 @@ impl ModuleParsingContext {
.collect::<HashMap<String, Rc<Module>>>() .collect::<HashMap<String, Rc<Module>>>()
} }
fn dissolve(self) -> (HashMap<PathBuf, SourceFile>, Vec<Error>) { fn dissolve(self) -> (HashMap<PathBuf, SourceFile>, Vec<Error>, Registry) {
let Self { files, errors, .. } = self; let Self {
(files.take(), errors.take()) files,
errors,
mut reg,
..
} = self;
(files.take(), errors.take(), (&*reg).take())
} }
} }
@ -98,14 +107,14 @@ impl ModuleTree {
pub fn parse_from_main( pub fn parse_from_main(
path: &PathBuf, path: &PathBuf,
main_file: &SourceFile, main_file: &SourceFile,
) -> (Self, HashMap<PathBuf, SourceFile>, Vec<Error>) { ) -> (Self, HashMap<PathBuf, SourceFile>, Vec<Error>, Registry) {
let entry_path = path.parent().unwrap().to_owned(); let entry_path = path.parent().unwrap().to_owned();
let ctx = ModuleParsingContext::new(&entry_path); let ctx = ModuleParsingContext::new(&entry_path);
let modules = Rc::new(ctx.parse_child_modules(main_file.tree().syntax(), None)); let modules = Rc::new(ctx.parse_child_modules(main_file.tree().syntax(), None));
let (files, errors) = ctx.dissolve(); let (files, errors, reg) = ctx.dissolve();
(Self { modules }, files, errors) (Self { modules }, files, errors, reg)
} }
pub fn print_tree(&self, lst: &Root) { pub fn print_tree(&self, lst: &Root) {
@ -114,26 +123,29 @@ impl ModuleTree {
} }
} }
#[derive(Debug)]
pub struct Module { pub struct Module {
path: Vec<String>, path: Vec<String>,
name: String, name: String,
kind: ModuleKind, kind: ModuleKind,
children: Rc<HashMap<String, Rc<Module>>>, children: Rc<HashMap<String, Rc<Module>>>,
parent: Option<Rc<Module>>, parent: Option<Rc<Module>>,
body: SyntaxNodePtr<Lang>,
} }
impl Module { impl Module {
fn parse_mod(module: Mod, ctx: ModuleParsingContext) -> Result<Self, Error> { fn parse_mod(module: Mod, mut ctx: ModuleParsingContext) -> Result<Rc<Self>, Error> {
let children = module let children = module
.syntax() .syntax()
.children() .children()
// .map(|n| n.kind()) // .map(|n| n.kind())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let r;
if children.len() == 1 { if children.len() == 1 {
let name = &children[0]; let name = &children[0];
assert_eq!(name.kind(), SyntaxKind::MODULE_NAME); assert_eq!(name.kind(), SyntaxKind::MODULE_NAME);
return Self::parse_file_mod( r = Self::parse_file_mod(
name.text().to_string(), name.text().to_string(),
ctx.clone(), ctx.clone(),
Loc::new(ctx.cur_file.clone(), &module), Loc::new(ctx.cur_file.clone(), &module),
@ -143,9 +155,15 @@ impl Module {
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(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( fn parse_file_mod(
@ -168,6 +186,7 @@ impl Module {
let children = let children =
Rc::new(ctx.parse_child_modules(source_file.tree().syntax(), Some(name.clone()))); Rc::new(ctx.parse_child_modules(source_file.tree().syntax(), Some(name.clone())));
let body = SyntaxNodePtr::new(source_file.tree().syntax());
ctx.files ctx.files
.borrow_mut() .borrow_mut()
@ -182,6 +201,7 @@ impl Module {
}, },
children, children,
parent: None, parent: None,
body,
}) })
} }
@ -205,13 +225,34 @@ impl Module {
children, children,
parent: None, parent: None,
path: old_path, 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 { pub fn name(&self) -> String {
// self.name.to_node(lst.syntax()).syntax().text().to_string() // self.name.to_node(lst.syntax()).syntax().text().to_string()
self.name.clone() self.name.clone()
} }
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(),
}
}
} }
fn print_tree(name: &str, children: Rc<HashMap<String, Rc<Module>>>, level: u32) { fn print_tree(name: &str, children: Rc<HashMap<String, Rc<Module>>>, level: u32) {
@ -230,6 +271,7 @@ fn print_tree(name: &str, children: Rc<HashMap<String, Rc<Module>>>, level: u32)
.for_each(|(name, m)| print_tree(name, m.children.clone(), level + 1)) .for_each(|(name, m)| print_tree(name, m.children.clone(), level + 1))
} }
#[derive(Debug)]
enum ModuleKind { enum ModuleKind {
Inline(Loc<nodes::Mod>), Inline(Loc<nodes::Mod>),
File { File {

View file

@ -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<StoreObj<Def>>,
mods: Vec<StoreObj<Mod>>,
names: HashMap<String, HashSet<RegistryIdx>>,
paths: HashMap<OwnedItemPath, RegistryIdx>,
}
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<Module>) -> Option<RegistryIdx> {
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<T> {
inner: Rc<InnerStoreObj<T>>,
}
impl<T> StoreObj<T> {
pub fn new(name: impl ToString, item: T) -> Self {
Self {
inner: Rc::new(InnerStoreObj {
name: name.to_string(),
obj: item,
}),
}
}
}
#[derive(Debug)]
struct InnerStoreObj<T> {
name: String,
obj: T,
}
#[derive(Debug)]
struct Mod {
module: Rc<Module>,
}
#[derive(Debug)]
struct Def {
node: nodes::Def,
}

View file

@ -0,0 +1,94 @@
use std::borrow::Cow;
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct ItemPath<'a> {
items: Vec<Cow<'a, str>>,
}
#[derive(Clone, Debug, PartialEq, Eq, Hash)]
pub struct OwnedItemPath {
items: Vec<String>,
}
impl OwnedItemPath {
pub fn name(&self) -> Option<String> {
self.items.last().cloned()
}
}
impl From<ItemPath<'_>> for OwnedItemPath {
fn from(value: ItemPath<'_>) -> Self {
Self {
items: value
.items
.into_iter()
.map(|v| v.into_owned())
.collect::<Vec<String>>(),
}
}
}
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::<Vec<_>>(),
}
}
pub fn push(mut self, item: impl Into<Cow<'a, str>>) -> Self {
self.items.push(item.into());
self
}
pub fn name(&self) -> Option<String> {
self.items.last().cloned().map(|item| item.into_owned())
}
}
impl<'a> TryFrom<Pattern<'a>> for ItemPath<'a> {
type Error = ();
fn try_from(value: Pattern<'a>) -> Result<Self, Self::Error> {
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<PatternEl<'a>>,
}
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,
}