From c12450fb4e30c3418555e47d045bb9fd4318a10a Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Sun, 29 Jul 2018 13:51:55 +0300 Subject: Introduce red-green syntax tree --- src/tree/file_builder.rs | 72 +++++++++++++++++++++++++++++++++++++++++++++++- src/tree/mod.rs | 2 +- 2 files changed, 72 insertions(+), 2 deletions(-) (limited to 'src/tree') diff --git a/src/tree/file_builder.rs b/src/tree/file_builder.rs index 712602168..4983006cd 100644 --- a/src/tree/file_builder.rs +++ b/src/tree/file_builder.rs @@ -7,8 +7,13 @@ //! tree builder: the parser produces a stream of events like //! `start node`, `finish node`, and `FileBuilder` converts //! this stream to a real tree. -use {SyntaxKind, TextRange, TextUnit}; +use std::sync::Arc; +use { + SyntaxKind, TextRange, TextUnit, + yellow::GreenNode +}; use super::{File, NodeData, NodeIdx, SyntaxErrorData}; +use SError; pub(crate) trait Sink { fn leaf(&mut self, kind: SyntaxKind, len: TextUnit); @@ -159,3 +164,68 @@ fn grow(left: &mut TextRange, right: TextRange) { pub(crate) struct ErrorMsg { pub(crate) msg: String, } + +pub(crate) struct GreenBuilder { + text: String, + stack: Vec, + pos: TextUnit, + root: Option, + errors: Vec, +} + +impl GreenBuilder { + pub(crate) fn new(text: String) -> GreenBuilder { + GreenBuilder { + text, + stack: Vec::new(), + pos: 0.into(), + root: None, + errors: Vec::new(), + } + } + + pub(crate) fn finish(self) -> (GreenNode, Vec) { + (self.root.unwrap(), self.errors) + } +} + +impl Sink for GreenBuilder { + fn leaf(&mut self, kind: SyntaxKind, len: TextUnit) { + let range = TextRange::offset_len(self.pos, len); + self.pos += len; + let text = self.text[range].to_owned(); + let parent = self.stack.last_mut().unwrap(); + if kind.is_trivia() { + parent.push_trivia(kind, text); + } else { + let node = GreenNode::new_leaf(kind, text); + parent.push_child(Arc::new(node)); + } + } + + fn start_internal(&mut self, kind: SyntaxKind) { + self.stack.push(GreenNode::new_branch(kind)) + } + + fn finish_internal(&mut self) { + let node = self.stack.pop().unwrap(); + if let Some(parent) = self.stack.last_mut() { + parent.push_child(Arc::new(node)) + } else { + self.root = Some(node); + } + } + + fn error(&mut self, err: ErrorMsg) { + self.errors.push(SError { message: err.msg, offset: self.pos }) + } +} +impl SyntaxKind { + fn is_trivia(self) -> bool { + match self { + SyntaxKind::WHITESPACE | SyntaxKind::DOC_COMMENT | SyntaxKind::COMMENT => true, + _ => false + } + } +} + diff --git a/src/tree/mod.rs b/src/tree/mod.rs index f7b16d7b5..7abe17592 100644 --- a/src/tree/mod.rs +++ b/src/tree/mod.rs @@ -2,7 +2,7 @@ mod file_builder; use ::{TextRange, TextUnit}; use std::{fmt, cmp}; -pub(crate) use self::file_builder::{ErrorMsg, FileBuilder, Sink}; +pub(crate) use self::file_builder::{ErrorMsg, FileBuilder, Sink, GreenBuilder}; pub use syntax_kinds::SyntaxKind; -- cgit v1.2.3