diff --git a/Cargo.toml b/Cargo.toml index 77f9c4a8d51..55dd9165ca0 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -5,7 +5,7 @@ authors = ["Aleksey Kladov "] license = "MIT OR Apache-2.0" [workspace] -members = [ "tools", "cli", "libeditor", "libanalysis" ] +members = [ "tools", "cli", "libeditor", "libanalysis", "codeless/server" ] [dependencies] unicode-xid = "0.1.0" diff --git a/cli/src/main.rs b/cli/src/main.rs index f6c66743f7f..45e0a1e4f72 100644 --- a/cli/src/main.rs +++ b/cli/src/main.rs @@ -10,7 +10,7 @@ use std::{ }; use clap::{App, Arg, SubCommand}; use tools::collect_tests; -use libeditor::File; +use libeditor::{ast, syntax_tree, symbols}; type Result = ::std::result::Result; @@ -44,14 +44,14 @@ fn main() -> Result<()> { let file = file()?; let elapsed = start.elapsed(); if !matches.is_present("no-dump") { - println!("{}", file.syntax_tree()); + println!("{}", syntax_tree(&file)); } eprintln!("parsing: {:?}", elapsed); ::std::mem::forget(file); } ("symbols", _) => { let file = file()?; - for s in file.symbols() { + for s in symbols(&file) { println!("{:?}", s); } } @@ -68,9 +68,9 @@ fn main() -> Result<()> { Ok(()) } -fn file() -> Result { +fn file() -> Result { let text = read_stdin()?; - Ok(File::new(&text)) + Ok(ast::File::parse(&text)) } fn read_stdin() -> Result { @@ -89,7 +89,7 @@ fn render_test(file: &Path, line: usize) -> Result<(String, String)> { None => bail!("No test found at line {} at {}", line, file.display()), Some((_start_line, test)) => test, }; - let file = File::new(&test.text); - let tree = file.syntax_tree(); + let file = ast::File::parse(&test.text); + let tree = syntax_tree(&file); Ok((test.text, tree)) } diff --git a/codeless/server/.gitignore b/codeless/server/.gitignore deleted file mode 100644 index 5a50b7f98af..00000000000 --- a/codeless/server/.gitignore +++ /dev/null @@ -1 +0,0 @@ -/target/* diff --git a/codeless/server/Cargo.toml b/codeless/server/Cargo.toml index 4c3dd345c97..f5c32b8787b 100644 --- a/codeless/server/Cargo.toml +++ b/codeless/server/Cargo.toml @@ -2,7 +2,6 @@ name = "m" version = "0.1.0" authors = ["Aleksey Kladov "] -[workspace] [dependencies] failure = "0.1.2" @@ -12,5 +11,8 @@ serde = "1.0.71" serde_derive = "1.0.71" drop_bomb = "0.1.0" crossbeam-channel = "0.2.4" +threadpool = "1.7.1" +flexi_logger = "0.9.0" +log = "0.4.3" libeditor = { path = "../../libeditor" } libanalysis = { path = "../../libanalysis" } diff --git a/codeless/server/src/dispatch.rs b/codeless/server/src/dispatch.rs index a9476acdebc..ee87fa6c310 100644 --- a/codeless/server/src/dispatch.rs +++ b/codeless/server/src/dispatch.rs @@ -24,8 +24,8 @@ impl Responder R::Params: DeserializeOwned, R::Result: Serialize, { - pub fn respond_with(self, io: &mut Io, f: impl FnOnce() -> Result) -> Result<()> { - match f() { + pub fn response(self, io: &mut Io, resp: Result) -> Result<()> { + match resp { Ok(res) => self.result(io, res)?, Err(e) => { self.error(io)?; diff --git a/codeless/server/src/io.rs b/codeless/server/src/io.rs index b84103d6556..5eafc694225 100644 --- a/codeless/server/src/io.rs +++ b/codeless/server/src/io.rs @@ -49,16 +49,21 @@ impl MsgReceiver { match self.chan.recv() { Some(msg) => Ok(msg), None => { - self.thread - .take() - .ok_or_else(|| format_err!("MsgReceiver thread panicked"))? - .join() - .map_err(|_| format_err!("MsgReceiver thread panicked"))??; - bail!("client disconnected") + self.cleanup()?; + unreachable!() } } } + fn cleanup(&mut self) -> Result<()> { + self.thread + .take() + .ok_or_else(|| format_err!("MsgReceiver thread panicked"))? + .join() + .map_err(|_| format_err!("MsgReceiver thread panicked"))??; + bail!("client disconnected") + } + fn stop(self) -> Result<()> { // Can't really self.thread.join() here, b/c it might be // blocking on read @@ -68,7 +73,7 @@ impl MsgReceiver { struct MsgSender { chan: Sender, - thread: Option>>, + thread: thread::JoinHandle>, } impl MsgSender { @@ -76,28 +81,14 @@ impl MsgSender { self.chan.send(msg) } - fn stop(mut self) -> Result<()> { - if let Some(thread) = self.thread.take() { - thread.join() - .map_err(|_| format_err!("MsgSender thread panicked"))?? - } + fn stop(self) -> Result<()> { + drop(self.chan); + self.thread.join() + .map_err(|_| format_err!("MsgSender thread panicked"))??; Ok(()) } } -impl Drop for MsgSender { - fn drop(&mut self) { - if let Some(thread) = self.thread.take() { - let res = thread.join(); - if thread::panicking() { - drop(res) - } else { - res.unwrap().unwrap() - } - } - } -} - pub struct Io { receiver: MsgReceiver, sender: MsgSender, @@ -109,7 +100,7 @@ impl Io { let (tx, rx) = bounded(16); MsgSender { chan: tx, - thread: Some(thread::spawn(move || { + thread: thread::spawn(move || { let stdout = stdout(); let mut stdout = stdout.lock(); for msg in rx { @@ -126,7 +117,7 @@ impl Io { write_msg_text(&mut stdout, &text)?; } Ok(()) - })), + }), } }; let receiver = { @@ -155,6 +146,14 @@ impl Io { self.receiver.recv() } + pub fn receiver(&mut self) -> &mut Receiver { + &mut self.receiver.chan + } + + pub fn cleanup_receiver(&mut self) -> Result<()> { + self.receiver.cleanup() + } + pub fn stop(self) -> Result<()> { self.receiver.stop()?; self.sender.stop()?; @@ -190,10 +189,12 @@ fn read_msg_text(inp: &mut impl BufRead) -> Result> { buf.resize(size, 0); inp.read_exact(&mut buf)?; let buf = String::from_utf8(buf)?; + debug!("< {}", buf); Ok(Some(buf)) } fn write_msg_text(out: &mut impl Write, msg: &str) -> Result<()> { + debug!("> {}", msg); write!(out, "Content-Length: {}\r\n\r\n", msg.len())?; out.write_all(msg.as_bytes())?; out.flush()?; diff --git a/codeless/server/src/main.rs b/codeless/server/src/main.rs index 11b6b70679d..92f6a400ca2 100644 --- a/codeless/server/src/main.rs +++ b/codeless/server/src/main.rs @@ -6,7 +6,12 @@ extern crate serde; extern crate serde_json; extern crate languageserver_types; extern crate drop_bomb; +#[macro_use] extern crate crossbeam_channel; +extern crate threadpool; +#[macro_use] +extern crate log; +extern crate flexi_logger; extern crate libeditor; extern crate libanalysis; @@ -16,16 +21,50 @@ mod req; mod dispatch; use languageserver_types::InitializeResult; +use threadpool::ThreadPool; +use crossbeam_channel::{bounded, Sender, Receiver}; +use flexi_logger::Logger; use libanalysis::WorldState; -use self::io::{Io, RawMsg}; + +use ::{ + io::{Io, RawMsg}, +}; pub type Result = ::std::result::Result; fn main() -> Result<()> { + Logger::with_env_or_str("m=trace") + .log_to_file() + .directory("log") + .start()?; + info!("starting server"); + match ::std::panic::catch_unwind(|| main_inner()) { + Ok(res) => { + info!("shutting down: {:?}", res); + res + } + Err(_) => { + error!("server panicked"); + bail!("server panicked") + }, + } +} + +fn main_inner() -> Result<()> { let mut io = Io::from_stdio(); - initialize(&mut io)?; - io.stop()?; - Ok(()) + let res = initialize(&mut io); + info!("shutting down IO..."); + let io_res = io.stop(); + info!("... IO is down"); + match (res, io_res) { + (Ok(()), Ok(())) => Ok(()), + (res, Ok(())) => res, + (Ok(()), io_res) => io_res, + (res, Err(io_err)) => { + error!("shutdown error: {:?}", io_err); + res + } + } } fn initialize(io: &mut Io) -> Result<()> { @@ -59,20 +98,69 @@ fn initialize(io: &mut Io) -> Result<()> { } } +type Thunk = Box FnBox<&'a mut Io, Result<()>>>; + fn initialized(io: &mut Io) -> Result<()> { - eprintln!("initialized"); - let world = WorldState::new(); + let mut world = WorldState::new(); + let mut pool = ThreadPool::new(4); + let (sender, receiver) = bounded::(16); + let res = main_loop(io, &mut world, &mut pool, sender, receiver.clone()); + info!("waiting for background jobs to finish..."); + receiver.for_each(drop); + info!("...background jobs have finished"); + res +} + +fn main_loop( + io: &mut Io, + world: &mut WorldState, + pool: &mut ThreadPool, + sender: Sender, + receiver: Receiver, +) -> Result<()> { + info!("server initialized, serving requests"); loop { - match io.recv()? { + enum Event { + Msg(RawMsg), + Thunk(Thunk), + ReceiverDead, + } + + let event = select! { + recv(io.receiver(), msg) => match msg { + Some(msg) => Event::Msg(msg), + None => Event::ReceiverDead, + }, + recv(receiver, thunk) => Event::Thunk(thunk.unwrap()), + }; + + let msg = match event { + Event::ReceiverDead => { + io.cleanup_receiver()?; + unreachable!(); + } + Event::Thunk(thunk) => { + thunk.call_box(io)?; + continue; + } + Event::Msg(msg) => msg, + }; + + match msg { RawMsg::Request(req) => { - let world = world.snapshot(); if let Some((params, resp)) = dispatch::expect::(io, req)? { - resp.respond_with(io, || { - let path = params.text_document.uri.to_file_path() - .map_err(|()| format_err!("invalid path"))?; - let file = world.file_syntax(&path)?; - Ok(libeditor::syntax_tree(&file)) - })? + let world = world.snapshot(); + let sender = sender.clone(); + pool.execute(move || { + let res: Result = (|| { + let path = params.text_document.uri.to_file_path() + .map_err(|()| format_err!("invalid path"))?; + let file = world.file_syntax(&path)?; + Ok(libeditor::syntax_tree(&file)) + })(); + + sender.send(Box::new(|io: &mut Io| resp.response(io, res))) + }); } } msg => { @@ -82,3 +170,13 @@ fn initialized(io: &mut Io) -> Result<()> { } } + +trait FnBox: Send { + fn call_box(self: Box, a: A) -> R; +} + +impl R + Send> FnBox for F { + fn call_box(self: Box, a: A) -> R { + (*self)(a) + } +} diff --git a/codeless/server/target/.rustc_info.json b/codeless/server/target/.rustc_info.json deleted file mode 100644 index a37ac201127..00000000000 --- a/codeless/server/target/.rustc_info.json +++ /dev/null @@ -1 +0,0 @@ -{"rustc_fingerprint":11898242945176772229,"outputs":{"15337506775154344876":["___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/matklad/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\ndebug_assertions\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\nunix\n",""],"1617349019360157463":["___\nlib___.rlib\nlib___.so\nlib___.so\nlib___.a\nlib___.so\n/home/matklad/.rustup/toolchains/stable-x86_64-unknown-linux-gnu\ndebug_assertions\nproc_macro\ntarget_arch=\"x86_64\"\ntarget_endian=\"little\"\ntarget_env=\"gnu\"\ntarget_family=\"unix\"\ntarget_feature=\"fxsr\"\ntarget_feature=\"sse\"\ntarget_feature=\"sse2\"\ntarget_os=\"linux\"\ntarget_pointer_width=\"64\"\nunix\n",""],"1164083562126845933":["rustc 1.28.0 (9634041f0 2018-07-30)\nbinary: rustc\ncommit-hash: 9634041f0e8c0f3191d2867311276f19d0a42564\ncommit-date: 2018-07-30\nhost: x86_64-unknown-linux-gnu\nrelease: 1.28.0\nLLVM version: 6.0\n",""]}} \ No newline at end of file diff --git a/codeless/server/target/debug/.cargo-lock b/codeless/server/target/debug/.cargo-lock deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/codeless/server/target/debug/libm.d b/codeless/server/target/debug/libm.d deleted file mode 100644 index 04d8bb9ed7f..00000000000 --- a/codeless/server/target/debug/libm.d +++ /dev/null @@ -1 +0,0 @@ -/home/matklad/projects/libsyntax2/codeless/server/target/debug/libm.rmeta: /home/matklad/projects/libsyntax2/codeless/server/src/caps.rs /home/matklad/projects/libsyntax2/codeless/server/src/dispatch.rs /home/matklad/projects/libsyntax2/codeless/server/src/io.rs /home/matklad/projects/libsyntax2/codeless/server/src/main.rs /home/matklad/projects/libsyntax2/codeless/server/src/req.rs /home/matklad/projects/libsyntax2/libanalysis/src/lib.rs /home/matklad/projects/libsyntax2/libeditor/src/extend_selection.rs /home/matklad/projects/libsyntax2/libeditor/src/lib.rs /home/matklad/projects/libsyntax2/src/algo/mod.rs /home/matklad/projects/libsyntax2/src/algo/walk.rs /home/matklad/projects/libsyntax2/src/ast/generated.rs /home/matklad/projects/libsyntax2/src/ast/mod.rs /home/matklad/projects/libsyntax2/src/grammar/attributes.rs /home/matklad/projects/libsyntax2/src/grammar/expressions/atom.rs /home/matklad/projects/libsyntax2/src/grammar/expressions/mod.rs /home/matklad/projects/libsyntax2/src/grammar/items/consts.rs /home/matklad/projects/libsyntax2/src/grammar/items/mod.rs /home/matklad/projects/libsyntax2/src/grammar/items/structs.rs /home/matklad/projects/libsyntax2/src/grammar/items/traits.rs /home/matklad/projects/libsyntax2/src/grammar/items/use_item.rs /home/matklad/projects/libsyntax2/src/grammar/mod.rs /home/matklad/projects/libsyntax2/src/grammar/params.rs /home/matklad/projects/libsyntax2/src/grammar/paths.rs /home/matklad/projects/libsyntax2/src/grammar/patterns.rs /home/matklad/projects/libsyntax2/src/grammar/type_args.rs /home/matklad/projects/libsyntax2/src/grammar/type_params.rs /home/matklad/projects/libsyntax2/src/grammar/types.rs /home/matklad/projects/libsyntax2/src/lexer/classes.rs /home/matklad/projects/libsyntax2/src/lexer/comments.rs /home/matklad/projects/libsyntax2/src/lexer/mod.rs /home/matklad/projects/libsyntax2/src/lexer/numbers.rs /home/matklad/projects/libsyntax2/src/lexer/ptr.rs /home/matklad/projects/libsyntax2/src/lexer/strings.rs /home/matklad/projects/libsyntax2/src/lib.rs /home/matklad/projects/libsyntax2/src/parser_api.rs /home/matklad/projects/libsyntax2/src/parser_impl/event.rs /home/matklad/projects/libsyntax2/src/parser_impl/input.rs /home/matklad/projects/libsyntax2/src/parser_impl/mod.rs /home/matklad/projects/libsyntax2/src/smol_str.rs /home/matklad/projects/libsyntax2/src/syntax_kinds/generated.rs /home/matklad/projects/libsyntax2/src/syntax_kinds/mod.rs /home/matklad/projects/libsyntax2/src/utils.rs /home/matklad/projects/libsyntax2/src/yellow/builder.rs /home/matklad/projects/libsyntax2/src/yellow/green.rs /home/matklad/projects/libsyntax2/src/yellow/mod.rs /home/matklad/projects/libsyntax2/src/yellow/red.rs /home/matklad/projects/libsyntax2/src/yellow/syntax.rs diff --git a/codeless/server/target/debug/libm.rmeta b/codeless/server/target/debug/libm.rmeta deleted file mode 100644 index e69de29bb2d..00000000000 diff --git a/codeless/src/extension.ts b/codeless/src/extension.ts index 712d93e0407..c64065e6bfc 100644 --- a/codeless/src/extension.ts +++ b/codeless/src/extension.ts @@ -43,10 +43,8 @@ export function deactivate(): Thenable { function startServer() { let run: Executable = { command: "cargo", - args: ["run"], - options: { - cwd: "./server" - } + args: ["run", "--package", "m"], + options: { cwd: "." } } let serverOptions: ServerOptions = { run, diff --git a/libeditor/src/lib.rs b/libeditor/src/lib.rs index 817a2d15b80..4e9631a8b89 100644 --- a/libeditor/src/lib.rs +++ b/libeditor/src/lib.rs @@ -6,9 +6,8 @@ use libsyntax2::{ SyntaxNodeRef, AstNode, algo::walk, SyntaxKind::*, - ast, }; -pub use libsyntax2::{TextRange, TextUnit}; +pub use libsyntax2::{TextRange, TextUnit, ast}; #[derive(Debug)] pub struct HighlightedRange { diff --git a/libeditor/tests/test.rs b/libeditor/tests/test.rs index ab8254d16ae..2a84c50806b 100644 --- a/libeditor/tests/test.rs +++ b/libeditor/tests/test.rs @@ -3,7 +3,7 @@ extern crate itertools; use std::fmt; use itertools::Itertools; -use libeditor::{File, TextRange}; +use libeditor::{ast, highlight, runnables, extend_selection, TextRange}; #[test] fn test_extend_selection() { @@ -12,9 +12,9 @@ fn test_extend_selection() { } "#); let range = TextRange::offset_len(18.into(), 0.into()); - let range = file.extend_selection(range).unwrap(); + let range = extend_selection(&file, range).unwrap(); assert_eq!(range, TextRange::from_to(17.into(), 18.into())); - let range = file.extend_selection(range).unwrap(); + let range = extend_selection(&file, range).unwrap(); assert_eq!(range, TextRange::from_to(15.into(), 20.into())); } @@ -25,7 +25,7 @@ fn test_highlighting() { fn main() {} println!("Hello, {}!", 92); "#); - let hls = file.highlight(); + let hls = highlight(&file); dbg_eq( &hls, r#"[HighlightedRange { range: [1; 11), tag: "comment" }, @@ -49,7 +49,7 @@ fn test_foo() {} #[ignore] fn test_foo() {} "#); - let runnables = file.runnables(); + let runnables = runnables(&file); dbg_eq( &runnables, r#"[Runnable { range: [1; 13), kind: Bin }, @@ -58,8 +58,8 @@ fn test_foo() {} ) } -fn file(text: &str) -> File { - File::new(text) +fn file(text: &str) -> ast::File { + ast::File::parse(text) } fn dbg_eq(actual: &impl fmt::Debug, expected: &str) { diff --git a/src/yellow/green.rs b/src/yellow/green.rs index 787968363b6..f505b26d7a2 100644 --- a/src/yellow/green.rs +++ b/src/yellow/green.rs @@ -56,12 +56,6 @@ impl GreenNode { } } -#[test] -fn assert_send_sync() { - fn f() {} - f::(); -} - #[derive(Clone, Debug)] pub(crate) struct GreenBranch { text_len: TextUnit, diff --git a/src/yellow/mod.rs b/src/yellow/mod.rs index 6129ecb99e1..ff3bb221b22 100644 --- a/src/yellow/mod.rs +++ b/src/yellow/mod.rs @@ -3,9 +3,60 @@ mod green; mod red; mod syntax; -pub use self::syntax::{SyntaxNode, SyntaxNodeRef, SyntaxRoot, TreeRoot, SyntaxError}; +use std::{ + ops::Deref, + sync::Arc, + ptr, +}; +pub use self::syntax::{SyntaxNode, SyntaxNodeRef, SyntaxError}; pub(crate) use self::{ builder::GreenBuilder, green::GreenNode, red::RedNode, }; + +pub trait TreeRoot: Deref + Clone + Send + Sync {} + +#[derive(Debug)] +pub struct SyntaxRoot { + red: RedNode, + pub(crate) errors: Vec, +} + +impl TreeRoot for Arc {} + +impl<'a> TreeRoot for &'a SyntaxRoot {} + +impl SyntaxRoot { + pub(crate) fn new(green: GreenNode, errors: Vec) -> SyntaxRoot { + SyntaxRoot { + red: RedNode::new_root(green), + errors, + } + } +} + +#[derive(Clone, Copy, PartialEq, Eq, Debug)] +pub(crate) struct RedPtr(ptr::NonNull); + +unsafe impl Send for RedPtr {} + +unsafe impl Sync for RedPtr {} + +impl RedPtr { + fn new(red: &RedNode) -> RedPtr { + RedPtr(red.into()) + } + + unsafe fn get<'a>(self, _root: &'a impl TreeRoot) -> &'a RedNode { + &*self.0.as_ptr() + } +} + +#[test] +fn assert_send_sync() { + fn f() {} + f::(); + f::(); + f::(); +} diff --git a/src/yellow/red.rs b/src/yellow/red.rs index f57c4a9b779..13ad44c65cf 100644 --- a/src/yellow/red.rs +++ b/src/yellow/red.rs @@ -1,7 +1,5 @@ -use std::ptr; - use parking_lot::RwLock; -use {yellow::GreenNode, TextUnit}; +use {yellow::{GreenNode, RedPtr}, TextUnit}; #[derive(Debug)] pub(crate) struct RedNode { @@ -12,7 +10,7 @@ pub(crate) struct RedNode { #[derive(Debug)] struct ParentData { - parent: ptr::NonNull, + parent: RedPtr, start_offset: TextUnit, index_in_parent: usize, } @@ -24,7 +22,7 @@ impl RedNode { fn new_child( green: GreenNode, - parent: ptr::NonNull, + parent: RedPtr, start_offset: TextUnit, index_in_parent: usize, ) -> RedNode { @@ -64,12 +62,12 @@ impl RedNode { self.green.children().len() } - pub(crate) fn get_child(&self, idx: usize) -> Option> { + pub(crate) fn get_child(&self, idx: usize) -> Option { if idx >= self.n_children() { return None; } match &self.children.read()[idx] { - Some(child) => return Some(child.into()), + Some(child) => return Some(RedPtr::new(child)), None => (), }; let green_children = self.green.children(); @@ -79,15 +77,15 @@ impl RedNode { .map(|x| x.text_len()) .sum::(); let child = - RedNode::new_child(green_children[idx].clone(), self.into(), start_offset, idx); + RedNode::new_child(green_children[idx].clone(), RedPtr::new(self), start_offset, idx); let mut children = self.children.write(); if children[idx].is_none() { children[idx] = Some(child) } - Some(children[idx].as_ref().unwrap().into()) + Some(RedPtr::new(children[idx].as_ref().unwrap())) } - pub(crate) fn parent(&self) -> Option> { + pub(crate) fn parent(&self) -> Option { Some(self.parent.as_ref()?.parent) } pub(crate) fn index_in_parent(&self) -> Option { diff --git a/src/yellow/syntax.rs b/src/yellow/syntax.rs index 2ba9281fc25..6e33310f1b7 100644 --- a/src/yellow/syntax.rs +++ b/src/yellow/syntax.rs @@ -1,25 +1,23 @@ -use std::{fmt, ops::Deref, ptr, sync::Arc}; +use std::{fmt, sync::Arc}; use { - yellow::{GreenNode, RedNode}, + yellow::{RedNode, TreeRoot, SyntaxRoot, RedPtr}, SyntaxKind::{self, *}, TextRange, TextUnit, }; -pub trait TreeRoot: Deref + Clone {} - -impl TreeRoot for Arc {} - -impl<'a> TreeRoot for &'a SyntaxRoot {} #[derive(Clone, Copy)] pub struct SyntaxNode> { pub(crate) root: R, // Guaranteed to not dangle, because `root` holds a // strong reference to red's ancestor - red: ptr::NonNull, + red: RedPtr, } +unsafe impl Send for SyntaxNode {} +unsafe impl Sync for SyntaxNode {} + impl PartialEq> for SyntaxNode { fn eq(&self, other: &SyntaxNode) -> bool { self.red == other.red @@ -30,21 +28,6 @@ impl Eq for SyntaxNode {} pub type SyntaxNodeRef<'a> = SyntaxNode<&'a SyntaxRoot>; -#[derive(Debug)] -pub struct SyntaxRoot { - red: RedNode, - pub(crate) errors: Vec, -} - -impl SyntaxRoot { - pub(crate) fn new(green: GreenNode, errors: Vec) -> SyntaxRoot { - SyntaxRoot { - red: RedNode::new_root(green), - errors, - } - } -} - #[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)] pub struct SyntaxError { pub msg: String, @@ -54,11 +37,8 @@ pub struct SyntaxError { impl SyntaxNode> { pub(crate) fn new_owned(root: SyntaxRoot) -> Self { let root = Arc::new(root); - let red_weak = ptr::NonNull::from(&root.red); - SyntaxNode { - root, - red: red_weak, - } + let red = RedPtr::new(&root.red); + SyntaxNode { root, red } } } @@ -66,7 +46,7 @@ impl SyntaxNode { pub fn as_ref<'a>(&'a self) -> SyntaxNode<&'a SyntaxRoot> { SyntaxNode { root: &*self.root, - red: ptr::NonNull::clone(&self.red), + red: self.red, } } @@ -120,7 +100,7 @@ impl SyntaxNode { } fn red(&self) -> &RedNode { - unsafe { self.red.as_ref() } + unsafe { self.red.get(&self.root) } } }