2018-01-28 08:18:17 +00:00
|
|
|
//! This module provides a way to construct a `File`.
|
|
|
|
//! It is intended to be completely decoupled from the
|
|
|
|
//! parser, so as to allow to evolve the tree representation
|
|
|
|
//! and the parser algorithm independently.
|
|
|
|
//!
|
|
|
|
//! The `Sink` trait is the bridge between the parser and the
|
|
|
|
//! tree builder: the parser produces a stream of events like
|
|
|
|
//! `start node`, `finish node`, and `FileBuilder` converts
|
|
|
|
//! this stream to a real tree.
|
2018-07-29 10:51:55 +00:00
|
|
|
use std::sync::Arc;
|
|
|
|
use {
|
|
|
|
SyntaxKind, TextRange, TextUnit,
|
|
|
|
yellow::GreenNode
|
|
|
|
};
|
|
|
|
use SError;
|
2017-12-31 17:30:21 +00:00
|
|
|
|
2018-01-28 08:18:17 +00:00
|
|
|
pub(crate) trait Sink {
|
2017-12-31 21:13:56 +00:00
|
|
|
fn leaf(&mut self, kind: SyntaxKind, len: TextUnit);
|
|
|
|
fn start_internal(&mut self, kind: SyntaxKind);
|
|
|
|
fn finish_internal(&mut self);
|
2018-07-29 11:37:48 +00:00
|
|
|
fn error(&mut self, err: String);
|
2018-01-07 07:55:43 +00:00
|
|
|
}
|
2018-07-29 10:51:55 +00:00
|
|
|
|
|
|
|
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);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2018-07-29 11:37:48 +00:00
|
|
|
fn error(&mut self, message: String) {
|
|
|
|
self.errors.push(SError { message, offset: self.pos })
|
2018-07-29 10:51:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
impl SyntaxKind {
|
|
|
|
fn is_trivia(self) -> bool {
|
|
|
|
match self {
|
|
|
|
SyntaxKind::WHITESPACE | SyntaxKind::DOC_COMMENT | SyntaxKind::COMMENT => true,
|
|
|
|
_ => false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|