Introduce red-green syntax tree
This commit is contained in:
@@ -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<GreenNode>,
|
||||
pos: TextUnit,
|
||||
root: Option<GreenNode>,
|
||||
errors: Vec<SError>,
|
||||
}
|
||||
|
||||
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<SError>) {
|
||||
(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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user