forked from katzen-cafe/iowo
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::{
|
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,
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
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