lang: add registry/namespace
This commit is contained in:
parent
1a533eb788
commit
3e2c5946c8
8 changed files with 264 additions and 14 deletions
|
@ -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<T: AstNode> {
|
||||
file: PathBuf,
|
||||
syntax_el: AstPtr<T>,
|
||||
|
@ -25,6 +29,10 @@ impl<T: AstNode> Loc<T> {
|
|||
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<PathBuf, SourceFile>,
|
||||
errors: Vec<Error>,
|
||||
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,
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
|
@ -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<RefCell<HashMap<PathBuf, SourceFile>>>,
|
||||
errors: Rc<RefCell<Vec<Error>>>,
|
||||
reg: Rc<RefCell<Registry>>,
|
||||
proj_dir: Rc<PathBuf>,
|
||||
cur_path: Vec<String>,
|
||||
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::<HashMap<String, Rc<Module>>>()
|
||||
}
|
||||
|
||||
fn dissolve(self) -> (HashMap<PathBuf, SourceFile>, Vec<Error>) {
|
||||
let Self { files, errors, .. } = self;
|
||||
(files.take(), errors.take())
|
||||
fn dissolve(self) -> (HashMap<PathBuf, SourceFile>, Vec<Error>, 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<PathBuf, SourceFile>, Vec<Error>) {
|
||||
) -> (Self, HashMap<PathBuf, SourceFile>, Vec<Error>, 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<String>,
|
||||
name: String,
|
||||
kind: ModuleKind,
|
||||
children: Rc<HashMap<String, Rc<Module>>>,
|
||||
parent: Option<Rc<Module>>,
|
||||
body: SyntaxNodePtr<Lang>,
|
||||
}
|
||||
|
||||
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
|
||||
.syntax()
|
||||
.children()
|
||||
// .map(|n| n.kind())
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
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<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) {
|
||||
|
@ -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))
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum ModuleKind {
|
||||
Inline(Loc<nodes::Mod>),
|
||||
File {
|
||||
|
|
103
crates/lang/src/ast/namespace.rs
Normal file
103
crates/lang/src/ast/namespace.rs
Normal 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,
|
||||
}
|
94
crates/lang/src/ast/path.rs
Normal file
94
crates/lang/src/ast/path.rs
Normal 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,
|
||||
}
|
Loading…
Reference in a new issue