From 1c6180aabc767332d196bc4ab78624421d94eea9 Mon Sep 17 00:00:00 2001 From: Schrottkatze Date: Sun, 23 Jun 2024 20:32:10 +0200 Subject: [PATCH] lang: current state for archival purposes --- Cargo.lock | 328 ++++++++++++++++++ crates/lang/Cargo.toml | 3 + crates/lang/src/lib.rs | 2 +- crates/lang/src/lst_parser/output.rs | 5 + crates/lang/src/world.rs | 10 +- crates/lang/src/world/files.rs | 67 ++-- crates/lang/src/world/modules.rs | 157 ++++++++- crates/lang/src/world/nodes.rs | 2 +- crates/lang/src/world/world_creation_pool.rs | 173 +++++++-- .../world/world_creation_pool/wait_blocker.rs | 87 +++++ 10 files changed, 775 insertions(+), 59 deletions(-) create mode 100644 crates/lang/src/world/world_creation_pool/wait_blocker.rs diff --git a/Cargo.lock b/Cargo.lock index cd7e5fc..92c691e 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -82,6 +82,133 @@ dependencies = [ "yansi", ] +[[package]] +name = "async-channel" +version = "2.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "89b47800b0be77592da0afd425cc03468052844aff33b84e33cc696f64e77b6a" +dependencies = [ + "concurrent-queue", + "event-listener-strategy", + "futures-core", + "pin-project-lite", +] + +[[package]] +name = "async-executor" +version = "1.12.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c8828ec6e544c02b0d6691d21ed9f9218d0384a82542855073c2a3f58304aaf0" +dependencies = [ + "async-task", + "concurrent-queue", + "fastrand", + "futures-lite", + "slab", +] + +[[package]] +name = "async-fs" +version = "2.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ebcd09b382f40fcd159c2d695175b2ae620ffa5f3bd6f664131efff4e8b9e04a" +dependencies = [ + "async-lock", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-io" +version = "2.3.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0d6baa8f0178795da0e71bc42c9e5d13261aac7ee549853162e66a241ba17964" +dependencies = [ + "async-lock", + "cfg-if", + "concurrent-queue", + "futures-io", + "futures-lite", + "parking", + "polling", + "rustix", + "slab", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-lock" +version = "3.4.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ff6e472cdea888a4bd64f342f09b3f50e1886d32afe8df3d663c01140b811b18" +dependencies = [ + "event-listener", + "event-listener-strategy", + "pin-project-lite", +] + +[[package]] +name = "async-net" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "b948000fad4873c1c9339d60f2623323a0cfd3816e5181033c6a5cb68b2accf7" +dependencies = [ + "async-io", + "blocking", + "futures-lite", +] + +[[package]] +name = "async-process" +version = "2.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "f7eda79bbd84e29c2b308d1dc099d7de8dcc7035e48f4bf5dc4a531a44ff5e2a" +dependencies = [ + "async-channel", + "async-io", + "async-lock", + "async-signal", + "async-task", + "blocking", + "cfg-if", + "event-listener", + "futures-lite", + "rustix", + "tracing", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-signal" +version = "0.2.8" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "794f185324c2f00e771cd9f1ae8b5ac68be2ca7abb129a87afd6e86d228bc54d" +dependencies = [ + "async-io", + "async-lock", + "atomic-waker", + "cfg-if", + "futures-core", + "futures-io", + "rustix", + "signal-hook-registry", + "slab", + "windows-sys 0.52.0", +] + +[[package]] +name = "async-task" +version = "4.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8b75356056920673b02621b35afd0f7dda9306d03c79a30f5c56c44cf256e3de" + +[[package]] +name = "atomic-waker" +version = "1.1.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "1505bd5d3d116872e7271a6d4e16d81d0c8570876c8de68093a09ac269d8aac0" + [[package]] name = "autocfg" version = "1.1.0" @@ -121,6 +248,19 @@ dependencies = [ "serde", ] +[[package]] +name = "blocking" +version = "1.6.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "703f41c54fc768e63e091340b424302bb1c29ef4aa0c7f10fe849dfb114d29ea" +dependencies = [ + "async-channel", + "async-task", + "futures-io", + "futures-lite", + "piper", +] + [[package]] name = "bytemuck" version = "1.14.0" @@ -191,6 +331,15 @@ version = "1.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "acbf1af155f9b9ef647e42cdc158db4b64a1b61f743629225fde6f3e0be2a7c7" +[[package]] +name = "concurrent-queue" +version = "2.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4ca0197aee26d1ae37445ee532fefce43251d24cc7c166799f4d46817f1d3973" +dependencies = [ + "crossbeam-utils", +] + [[package]] name = "countme" version = "3.0.1" @@ -366,6 +515,12 @@ version = "0.1.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9bda8e21c04aca2ae33ffc2fd8c23134f3cac46db123ba97bd9d3f3b8a4a85e1" +[[package]] +name = "easy-parallel" +version = "3.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "2afbb9b0aef60e4f0d2b18129b6c0dff035a6f7dbbd17c2f38c1432102ee223c" + [[package]] name = "ego-tree" version = "0.6.2" @@ -405,6 +560,16 @@ version = "1.0.1" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "5443807d6dff69373d433ab9ef5378ad8df50ca6298caf15de6e52e24aaf54d5" +[[package]] +name = "errno" +version = "0.3.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "534c5cf6194dfab3db3242765c03bbe257cf92f22b38f6bc0c58d59108a820ba" +dependencies = [ + "libc", + "windows-sys 0.52.0", +] + [[package]] name = "eval" version = "0.1.0" @@ -415,6 +580,27 @@ dependencies = [ "serde", ] +[[package]] +name = "event-listener" +version = "5.3.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6032be9bd27023a771701cc49f9f053c751055f71efb2e0ae5c15809093675ba" +dependencies = [ + "concurrent-queue", + "parking", + "pin-project-lite", +] + +[[package]] +name = "event-listener-strategy" +version = "0.5.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "0f214dc438f977e6d4e3500aaa277f5ad94ca83fbbd9b1a15713ce2344ccc5a1" +dependencies = [ + "event-listener", + "pin-project-lite", +] + [[package]] name = "exr" version = "1.71.0" @@ -431,6 +617,12 @@ dependencies = [ "zune-inflate", ] +[[package]] +name = "fastrand" +version = "2.1.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "9fc0510504f03c51ada170672ac806f1f105a88aa97a5281117e1ddc3368e51a" + [[package]] name = "fdeflate" version = "0.3.3" @@ -471,6 +663,31 @@ version = "1.0.7" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "3f9eec918d3f24069decb9af1554cad7c880e2da24a9afd88aca000531ab82c1" +[[package]] +name = "futures-core" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "dfc6580bb841c5a68e9ef15c77ccc837b40a7504914d52e47b8b0e9bbda25a1d" + +[[package]] +name = "futures-io" +version = "0.3.30" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a44623e20b9681a318efdd71c299b6b222ed6f231972bfe2f224ebad6311f0c1" + +[[package]] +name = "futures-lite" +version = "2.3.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52527eb5074e35e9339c6b4e8d12600c7128b68fb25dcb9fa9dec18f7c25f3a5" +dependencies = [ + "fastrand", + "futures-core", + "futures-io", + "parking", + "pin-project-lite", +] + [[package]] name = "getrandom" version = "0.2.12" @@ -610,8 +827,10 @@ dependencies = [ "crossbeam", "dashmap", "drop_bomb", + "easy-parallel", "ego-tree", "enumset", + "futures-lite", "indexmap", "indoc", "logos", @@ -619,6 +838,7 @@ dependencies = [ "owo-colors", "petgraph", "rowan", + "smol", ] [[package]] @@ -650,6 +870,12 @@ dependencies = [ "redox_syscall 0.4.1", ] +[[package]] +name = "linux-raw-sys" +version = "0.4.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "78b3ae25bc7c8c38cec158d1f2757ee79e9b3740fbc7ccf0e59e4b08d793fa89" + [[package]] name = "lock_api" version = "0.4.11" @@ -788,6 +1014,12 @@ dependencies = [ "supports-color", ] +[[package]] +name = "parking" +version = "2.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bb813b8af86854136c6922af0598d719255ecb2179515e6e7730d468f05c9cae" + [[package]] name = "parking_lot_core" version = "0.9.10" @@ -853,6 +1085,23 @@ dependencies = [ "siphasher", ] +[[package]] +name = "pin-project-lite" +version = "0.2.14" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "bda66fc9667c18cb2758a2ac84d1167245054bcf85d5d1aaa6923f45801bdd02" + +[[package]] +name = "piper" +version = "0.2.3" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "ae1d5c74c9876f070d3e8fd503d748c7d974c3e48da8f41350fa5222ef9b4391" +dependencies = [ + "atomic-waker", + "fastrand", + "futures-io", +] + [[package]] name = "png" version = "0.17.10" @@ -866,6 +1115,21 @@ dependencies = [ "miniz_oxide", ] +[[package]] +name = "polling" +version = "3.7.1" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "5e6a007746f34ed64099e88783b0ae369eaa3da6392868ba262e2af9b8fbaea1" +dependencies = [ + "cfg-if", + "concurrent-queue", + "hermit-abi", + "pin-project-lite", + "rustix", + "tracing", + "windows-sys 0.52.0", +] + [[package]] name = "powerfmt" version = "0.2.0" @@ -1010,6 +1274,19 @@ version = "1.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2" +[[package]] +name = "rustix" +version = "0.38.34" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "70dc5ec042f7a43c4a73241207cecc9873a06d45debb38b329f8541d85c2730f" +dependencies = [ + "bitflags 2.4.1", + "errno", + "libc", + "linux-raw-sys", + "windows-sys 0.52.0", +] + [[package]] name = "ryu" version = "1.0.16" @@ -1053,6 +1330,15 @@ dependencies = [ "serde", ] +[[package]] +name = "signal-hook-registry" +version = "1.4.2" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a9e9e0b4211b72e7b8b6e85c807d36c212bdb33ea8587f7569562a84df5465b1" +dependencies = [ + "libc", +] + [[package]] name = "simd-adler32" version = "0.3.7" @@ -1065,12 +1351,38 @@ version = "0.3.11" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "38b58827f4464d87d377d175e90bf58eb00fd8716ff0a62f80356b5e61555d0d" +[[package]] +name = "slab" +version = "0.4.9" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "8f92a496fb766b417c996b9c5e57daf2f7ad3b0bebe1ccfca4856390e3d3bb67" +dependencies = [ + "autocfg", +] + [[package]] name = "smallvec" version = "1.11.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "4dccd0940a2dcdf68d092b8cbab7dc0ad8fa938bf95787e1b916b0e3d0e8e970" +[[package]] +name = "smol" +version = "2.0.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "e635339259e51ef85ac7aa29a1cd991b957047507288697a690e80ab97d07cad" +dependencies = [ + "async-channel", + "async-executor", + "async-fs", + "async-io", + "async-lock", + "async-net", + "async-process", + "blocking", + "futures-lite", +] + [[package]] name = "spin" version = "0.9.8" @@ -1174,6 +1486,22 @@ version = "0.1.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ef927ca75afb808a4d64dd374f00a2adf8d0fcff8e7b184af886c3c87ec4a3f3" +[[package]] +name = "tracing" +version = "0.1.40" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c3523ab5a71916ccf420eebdf5521fcef02141234bbc0b8a49f2fdc4544364ef" +dependencies = [ + "pin-project-lite", + "tracing-core", +] + +[[package]] +name = "tracing-core" +version = "0.1.32" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c06d3da6113f116aaee68e4d601191614c9053067f9ab7f6edbcb161237daa54" + [[package]] name = "unicode-ident" version = "1.0.12" diff --git a/crates/lang/Cargo.toml b/crates/lang/Cargo.toml index 0323c98..f50073a 100644 --- a/crates/lang/Cargo.toml +++ b/crates/lang/Cargo.toml @@ -20,6 +20,9 @@ num_cpus = "1.16" dashmap = "5.5.3" crossbeam = "0.8.4" owo-colors = {version = "4", features = ["supports-colors"]} +smol = "2" +futures-lite = "2.3" +easy-parallel = "3.3.1" [lints] workspace = true diff --git a/crates/lang/src/lib.rs b/crates/lang/src/lib.rs index c8b48f6..f48385e 100644 --- a/crates/lang/src/lib.rs +++ b/crates/lang/src/lib.rs @@ -1,4 +1,4 @@ -#![feature(type_alias_impl_trait, lint_reasons)] +#![feature(type_alias_impl_trait, lint_reasons, box_into_inner)] use crate::lst_parser::syntax_kind::SyntaxKind; diff --git a/crates/lang/src/lst_parser/output.rs b/crates/lang/src/lst_parser/output.rs index af483ab..ce96fb5 100644 --- a/crates/lang/src/lst_parser/output.rs +++ b/crates/lang/src/lst_parser/output.rs @@ -209,4 +209,9 @@ impl Output { pub fn errors(&self) -> Vec { self.errors.clone() } + + pub fn dissolve(self) -> (GreenNode, Vec) { + let Self { green_node, errors } = self; + (green_node, errors) + } } diff --git a/crates/lang/src/world.rs b/crates/lang/src/world.rs index 8a2506b..2f32cab 100644 --- a/crates/lang/src/world.rs +++ b/crates/lang/src/world.rs @@ -1,11 +1,19 @@ use std::{ fmt::Display, path::{Path, PathBuf}, + sync::{Arc, Mutex}, }; use crate::world::world_creation_pool::WorldCreationPool; -use self::{files::Files, registry::Registry}; +use easy_parallel::Parallel; +use futures_lite::future; +use smol::{ + channel::{unbounded, Sender}, + Executor, +}; + +use self::{error::Error, files::Files, registry::Registry}; pub mod error; pub mod files; diff --git a/crates/lang/src/world/files.rs b/crates/lang/src/world/files.rs index ca61d83..b4a1309 100644 --- a/crates/lang/src/world/files.rs +++ b/crates/lang/src/world/files.rs @@ -7,50 +7,55 @@ use std::{ use dashmap::DashMap; use rowan::ast::{AstNode, AstPtr}; -use crate::lst_parser::{ - error::SyntaxError, grammar::source_file, input::Input, output::Output, syntax_kind, Parser, +use crate::{ + lst_parser::{ + error::SyntaxError, grammar::source_file, input::Input, output::Output, syntax_kind, Parser, + }, + Lang, }; use super::{error::Error, modules::Module, nodes}; -pub struct Loc { +#[derive(Clone)] +pub struct Loc> { file: FileId, syntax: AstPtr, } -#[derive(Clone)] -pub struct Files(Arc); - -impl Files { - pub fn new() -> Self { - Self(Arc::new(FilesInner::new())) +impl> Loc { + pub fn new(node: N, file: FileId) -> Self { + Self { + file, + syntax: AstPtr::new(&node), + } } - pub fn add_and_parse(&self, file: &Path) -> Result<(FileId, Vec), std::io::Error> { - self.0.add_and_parse(file) + pub fn file(&self) -> FileId { + self.file } - pub fn get(&self, id: FileId) -> Arc { - self.0.get(id) + pub fn syntax(&self) -> AstPtr { + self.syntax.clone() } } /// global file store /// contains all known files etc. -struct FilesInner { - paths: Mutex>, - store: DashMap>, +#[derive(Clone)] +pub struct Files { + paths: Arc>>, + store: Arc>>, } -impl FilesInner { - fn new() -> Self { +impl Files { + pub fn new() -> Self { Self { - paths: Mutex::new(Vec::new()), - store: DashMap::new(), + paths: Arc::new(Mutex::new(Vec::new())), + store: Arc::new(DashMap::new()), } } - fn add_and_parse(&self, path: &Path) -> Result<(FileId, Vec), std::io::Error> { + pub fn add_and_parse(&self, path: &Path) -> Result<(FileId, Vec), std::io::Error> { let (file, errors) = SourceFile::read_and_parse(&path)?; // add file to paths and unlock again @@ -73,7 +78,7 @@ impl FilesInner { )) } - fn get(&self, id: FileId) -> Arc { + pub fn get(&self, id: FileId) -> Arc { let path = { let paths = self.paths.lock().unwrap(); paths[id.0].clone() @@ -81,10 +86,19 @@ impl FilesInner { self.store.get(&path).unwrap().clone() } + + pub fn get_path(&self, id: FileId) -> PathBuf { + let paths = self.paths.lock().unwrap(); + paths[id.0].clone() + } + + pub fn path_store(&self) -> Arc>> { + self.paths.clone() + } } pub struct SourceFile { - pub lst: Mutex, + pub lst: RwLock, root_module: Option>, } @@ -100,14 +114,15 @@ impl SourceFile { let events = parser.finish(); let out = Output::from_parser_output(toks, events); - let lst = out.syntax(); + // let lst = out.syntax(); + let (lst, errors) = out.dissolve(); Ok(( Self { - lst: Mutex::new(nodes::Root::cast(lst).unwrap()), + lst: RwLock::new(lst), root_module: None, }, - out.errors(), + errors, )) } } diff --git a/crates/lang/src/world/modules.rs b/crates/lang/src/world/modules.rs index 0f6d060..676553b 100644 --- a/crates/lang/src/world/modules.rs +++ b/crates/lang/src/world/modules.rs @@ -1,14 +1,18 @@ -use std::sync::Arc; +use std::{ + string::String, + sync::{Arc, Mutex}, +}; use dashmap::{DashMap, DashSet}; -use rowan::ast::AstNode; +use rowan::ast::{AstNode, AstPtr}; + +use crate::SyntaxNode; use super::{ files::{FileId, Loc}, nodes, registry::ItemPath, - world_creation_pool::WorkerCtx, - // world_creation_pool::WorkerCtx, + world_creation_pool::{wait_blocker::WaitBlocker, Task, WorkerCtx}, }; pub struct Module { @@ -21,18 +25,151 @@ pub struct Module { } impl Module { - pub fn parse_file(ctx: WorkerCtx, file: FileId, decl: Option>) { - let f = ctx.files.get(file); + pub fn parse_mod_body( + ctx: &WorkerCtx, + tree: SyntaxNode, + path: ItemPath, + file: FileId, + ) -> (DashMap>>>>, Vec) { + let children: Vec<(String, Arc>>>, nodes::Mod)> = tree + .children() + .filter_map(|c| nodes::Mod::cast(c)) + .map(|m| { + let name = nodes::ModName::cast(m.syntax().first_child().unwrap()) + .expect("ModName should always be first child of Mod"); + ( + name.syntax().text().to_string(), + Arc::new(Mutex::new(None)), + m, + ) + }) + .collect(); + let retv: DashMap>>>> = children + .iter() + .map(|(name, mod_r, _)| (name.to_owned(), mod_r.clone())) + .collect(); + let tasks = children + .into_iter() + .map(|(name, mod_r, loc)| { + let mut path = path.clone(); + path.push(name); + Task::ParseMod(Loc::new(loc, file), mod_r, path) + }) + .collect::>(); - let tree = f.lst.lock().unwrap(); + (retv, tasks) + } + pub fn parse_file0( + ctx: &mut WorkerCtx, + file: FileId, + path: ItemPath, + decl: Option>, + ) { + let tree = ctx.get_tree(file); - let children = (&*tree).syntax().children(); + let (retv, tasks) = Self::parse_mod_body(ctx, tree, path.clone(), file); + + ctx.send_tasks( + Task::ParseFileMod1 { + file, + decl, + ret: retv.into(), + path, + }, + tasks, + ) + } + + pub fn parse_mod( + ctx: &mut WorkerCtx, + loc: Loc, + path: ItemPath, + ret: Arc>>, + blocker: WaitBlocker, + ) { + let mod_decl = ctx.resolve_loc(loc); + let children = mod_decl.syntax().children().collect::>(); + + if children.len() == 1 { + // TODO: file mod + todo!() + } else if children.len() == 2 { + // inline mod + } + } + + pub fn parse_inline_mod( + ctx: &mut WorkerCtx, + decl: Loc, + path: ItemPath, + ret: Arc>>>, + blocker: WaitBlocker, + ) { + let mod_decl_children = ctx + .resolve_loc(decl.clone()) + .syntax() + .children() + .collect::>(); + + assert_eq!(mod_decl_children.len(), 2); + + let name = nodes::ModName::cast(mod_decl_children[0].clone()).unwrap(); + let body = nodes::ModBody::cast(mod_decl_children[1].clone()).unwrap(); + + let (retv, tasks) = + Self::parse_mod_body(ctx, body.syntax().clone(), path.clone(), decl.file()); + + ctx.send_tasks( + Task::CompleteMod { + ret_self: ret, + body: ModuleBody::Inline(Loc::new(body, decl.file())), + decl: Some(decl), + path, + child_mods: retv.into(), + blocker, + }, + tasks, + ) + } + + pub fn complete_mod( + ctx: &mut WorkerCtx, + decl: Option>, + ret_self: Arc>>>, + body: ModuleBody, + path: ItemPath, + child_mods: Arc>>>>>, + blocker: WaitBlocker, + ) { + assert!(child_mods + .iter() + .all(|item| item.value().lock().unwrap().is_some())); + + let module = Arc::new(Module { + decl, + body, + own_path: path, + child_modules: Arc::new( + Arc::<_>::unwrap_or_clone(child_mods) + .into_iter() + .map(|(name, module)| { + let module = module.lock().unwrap().take().unwrap(); + (name, module) + }) + .collect(), + ), + child_defs: Arc::default(), + }); + + let mut ret_self = ret_self.lock().unwrap(); + *ret_self = Some(module); + drop(blocker); } } struct Def; -enum ModuleBody { - InLine(Loc), +pub enum ModuleBody { + Inline(Loc), File(FileId), } diff --git a/crates/lang/src/world/nodes.rs b/crates/lang/src/world/nodes.rs index c77399a..303a3a1 100644 --- a/crates/lang/src/world/nodes.rs +++ b/crates/lang/src/world/nodes.rs @@ -4,7 +4,7 @@ use rowan::Language; macro_rules! ast_nodes { ($($ast:ident, $kind:ident);+) => { $( - #[derive(Debug, PartialEq, Eq, Hash)] + #[derive(Debug, Clone, PartialEq, Eq, Hash)] #[repr(transparent)] pub struct $ast(SyntaxNode); impl rowan::ast::AstNode for $ast { diff --git a/crates/lang/src/world/world_creation_pool.rs b/crates/lang/src/world/world_creation_pool.rs index fd04e65..651d7eb 100644 --- a/crates/lang/src/world/world_creation_pool.rs +++ b/crates/lang/src/world/world_creation_pool.rs @@ -1,14 +1,28 @@ -use std::{path::PathBuf, thread}; +use std::{ + collections::HashMap, + path::PathBuf, + sync::{Arc, Mutex}, + thread, +}; use crossbeam::channel::{Receiver, Sender}; +use dashmap::DashMap; +use rowan::ast::{AstNode, AstPtr}; + +use crate::{Lang, SyntaxNode}; + +use self::wait_blocker::WaitBlocker; use super::{ error::Error, files::{FileId, Files, Loc}, + modules::{Module, ModuleBody}, nodes, - registry::Registry, + registry::{ItemPath, Registry}, }; +pub mod wait_blocker; + pub(super) struct WorldCreationPool { workers: Vec, tx: Sender, @@ -24,7 +38,7 @@ impl WorldCreationPool { i, files.clone(), reg.clone(), - JobSender(tx.clone()), + tx.clone(), rx.clone(), )) } @@ -33,12 +47,31 @@ impl WorldCreationPool { } } -pub struct JobSender(Sender); - enum Job { - ParseFileMod { + WaitingFor(WaitBlocker, Task), + Awaited(WaitBlocker, Task), +} + +pub enum Task { + ParseMod(Loc, Arc>>>, ItemPath), + ParseFileMod0 { file: FileId, decl: Option>, + path: ItemPath, + }, + ParseFileMod1 { + file: FileId, + decl: Option>, + path: ItemPath, + ret: Arc>>>>>, + }, + CompleteMod { + ret_self: Arc>>>, + decl: Option>, + body: ModuleBody, + path: ItemPath, + child_mods: Arc>>>>>, + blocker: WaitBlocker, }, OpenFile(PathBuf), } @@ -51,26 +84,104 @@ struct Worker { pub struct WorkerCtx { errors: Vec, - pub files: Files, + files: Files, + local_files: HashMap, pub reg: Registry, - pub tx: JobSender, + tx: Sender, +} + +impl WorkerCtx { + pub fn get_tree(&mut self, id: FileId) -> SyntaxNode { + let p = self.files.get_path(id); + if self.local_files.contains_key(&p) { + self.local_files[&p].clone() + } else { + let f = self.files.get(id); + let lst = SyntaxNode::new_root(f.lst.read().unwrap().clone()); + self.local_files.insert(p, lst.clone()); + lst + } + } + + pub fn resolve_loc>(&mut self, loc: Loc) -> N { + let f = self.get_tree(loc.file()); + + loc.syntax().to_node(&f) + } + + pub fn send_tasks(&self, task: Task, dependencies: Vec) { + let blocker = WaitBlocker::new(); + for dep_task in dependencies { + self.tx + .send(Job::Awaited(blocker.clone(), dep_task)) + .unwrap(); + } + self.tx.send(Job::WaitingFor(blocker, task)).unwrap(); + } } impl Worker { - fn new(id: usize, files: Files, reg: Registry, sender: JobSender, rx: Receiver) -> Self { - let ctx = WorkerCtx { - errors: Vec::new(), - files, - reg, - tx: sender, - }; - + fn new(id: usize, files: Files, reg: Registry, sender: Sender, rx: Receiver) -> Self { let thread_handle = thread::spawn(move || { - for msg in rx { - match msg { - Job::ParseFileMod { file, decl } => todo!(), - Job::OpenFile(path) => todo!(), + let ctx = WorkerCtx { + errors: Vec::new(), + local_files: HashMap::new(), + files, + reg, + tx: sender, + }; + + for job in &rx { + // if matches!(job, Job::WithCond(_, _)) { + + // } + match job { + Job::WaitingFor(blocker, task) => { + if blocker.is_ready() { + Self::do_task(&ctx, task, None) + } else if rx.is_empty() { + if let Some(blocker) = + blocker.wait_for(std::time::Duration::from_millis(50)) + { + ctx.tx.send(Job::WaitingFor(blocker, task)).unwrap(); + } else { + Self::do_task(&ctx, task, None) + } + } else { + ctx.tx.send(Job::WaitingFor(blocker, task)).unwrap(); + } + } + Job::Awaited(blocker, task) => { + Self::do_task(&ctx, task, Some(blocker.clone())); + drop(blocker) + } } + + // if let Job::WithCond(blocker, job_inner) = job_msg { + // if blocker.is_ready() { + // job = Box::::into_inner(job_inner); + // } else if rx.is_empty() { + // if let Some(blocker) = + // blocker.wait_for(std::time::Duration::from_millis(50)) + // { + // job = Job::WithCond(blocker, job_inner); + // } else { + // job = Box::::into_inner(job_inner); + // } + // } else { + // job = Job::WithCond(blocker, job_inner); + // } + // } else { + // job = job_msg; + // } + + // match job { + // Job::ParseFileMod { file, decl } => todo!(), + // Job::OpenFile(path) => todo!(), + // Job::WithCond(blocker, job) => { + // ctx.tx.send(Job::WithCond(blocker, job)).unwrap() + // } + // } } }); @@ -79,4 +190,26 @@ impl Worker { thread: thread_handle, } } + + fn do_task(ctx: &WorkerCtx, task: Task, blocker: Option) { + match task { + Task::ParseMod(_, _, _) => todo!(), + Task::ParseFileMod0 { file, decl, path } => todo!(), + Task::ParseFileMod1 { + file, + decl, + path, + ret, + } => todo!(), + Task::CompleteMod { + ret_self, + decl, + body, + path, + child_mods, + blocker, + } => todo!(), + Task::OpenFile(_) => todo!(), + } + } } diff --git a/crates/lang/src/world/world_creation_pool/wait_blocker.rs b/crates/lang/src/world/world_creation_pool/wait_blocker.rs new file mode 100644 index 0000000..2d23d8a --- /dev/null +++ b/crates/lang/src/world/world_creation_pool/wait_blocker.rs @@ -0,0 +1,87 @@ +use std::{ + sync::{Arc, Condvar, Mutex}, + time::Duration, +}; + +/// like a WaitGroup from crossbeam, but can also just check if it's the last one +pub struct WaitBlocker { + inner: Arc, +} + +struct Inner { + waiting: Mutex, + cvar: Condvar, +} + +impl WaitBlocker { + pub fn new() -> Self { + Self { + inner: Arc::new(Inner { + waiting: Mutex::new(1), + cvar: Condvar::new(), + }), + } + } + + pub fn wait(self) { + if *self.inner.waiting.lock().unwrap() == 1 { + return; + } + + let inner = self.inner.clone(); + drop(self); + + inner + .cvar + .wait_while(inner.waiting.lock().unwrap(), |w| *w > 0); + } + + pub fn wait_for(self, dur: Duration) -> Option { + if *self.inner.waiting.lock().unwrap() == 1 { + return None; + } + + let inner = self.inner.clone(); + drop(self); + + let (_, timeout_res) = inner + .cvar + .wait_timeout_while(inner.waiting.lock().unwrap(), dur, |w| *w > 0) + .unwrap(); + + if timeout_res.timed_out() { + None + } else { + { + let mut w = inner.waiting.lock().unwrap(); + *w += 1; + } + Some(Self { inner }) + } + } + + pub fn is_ready(&self) -> bool { + *self.inner.waiting.lock().unwrap() == 1 + } +} + +impl Clone for WaitBlocker { + fn clone(&self) -> Self { + let mut w = self.inner.waiting.lock().unwrap(); + *w += 1; + drop(w); + Self { + inner: self.inner.clone(), + } + } +} + +impl Drop for WaitBlocker { + fn drop(&mut self) { + let mut w = self.inner.waiting.lock().unwrap(); + *w -= 1; + if *w == 0 { + self.inner.cvar.notify_all() + } + } +}