2018-01-28 11:18:17 +03: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-01-27 18:31:23 -05:00
|
|
|
use {SyntaxKind, TextRange, TextUnit};
|
|
|
|
use super::{File, NodeData, NodeIdx, SyntaxErrorData};
|
2017-12-31 20:30:21 +03:00
|
|
|
|
2018-01-28 11:18:17 +03:00
|
|
|
pub(crate) trait Sink {
|
2018-01-01 00:13:56 +03:00
|
|
|
fn leaf(&mut self, kind: SyntaxKind, len: TextUnit);
|
|
|
|
fn start_internal(&mut self, kind: SyntaxKind);
|
|
|
|
fn finish_internal(&mut self);
|
2018-02-09 22:44:50 +03:00
|
|
|
fn error(&mut self, err: ErrorMsg);
|
2018-01-01 00:13:56 +03:00
|
|
|
}
|
|
|
|
|
2018-01-27 20:29:14 -05:00
|
|
|
#[derive(Debug)]
|
2018-01-28 11:18:17 +03:00
|
|
|
pub(crate) struct FileBuilder {
|
2017-12-31 20:30:21 +03:00
|
|
|
text: String,
|
|
|
|
nodes: Vec<NodeData>,
|
2018-01-07 10:10:35 +03:00
|
|
|
errors: Vec<SyntaxErrorData>,
|
2018-02-09 22:44:50 +03:00
|
|
|
in_progress: Vec<(NodeIdx, Option<NodeIdx>)>,
|
|
|
|
// (parent, last_child)
|
2017-12-31 20:30:21 +03:00
|
|
|
pos: TextUnit,
|
|
|
|
}
|
|
|
|
|
2018-01-01 00:13:56 +03:00
|
|
|
impl Sink for FileBuilder {
|
|
|
|
fn leaf(&mut self, kind: SyntaxKind, len: TextUnit) {
|
2017-12-31 20:30:21 +03:00
|
|
|
let leaf = NodeData {
|
|
|
|
kind,
|
2018-07-28 13:07:10 +03:00
|
|
|
range: TextRange::offset_len(self.pos, len),
|
2017-12-31 20:30:21 +03:00
|
|
|
parent: None,
|
|
|
|
first_child: None,
|
|
|
|
next_sibling: None,
|
|
|
|
};
|
|
|
|
self.pos += len;
|
|
|
|
let id = self.push_child(leaf);
|
|
|
|
self.add_len(id);
|
|
|
|
}
|
|
|
|
|
2018-01-01 00:13:56 +03:00
|
|
|
fn start_internal(&mut self, kind: SyntaxKind) {
|
2017-12-31 20:30:21 +03:00
|
|
|
let node = NodeData {
|
|
|
|
kind,
|
2018-07-28 13:07:10 +03:00
|
|
|
range: TextRange::offset_len(self.pos, 0.into()),
|
2017-12-31 20:30:21 +03:00
|
|
|
parent: None,
|
|
|
|
first_child: None,
|
|
|
|
next_sibling: None,
|
|
|
|
};
|
|
|
|
let id = if self.in_progress.is_empty() {
|
|
|
|
self.new_node(node)
|
|
|
|
} else {
|
|
|
|
self.push_child(node)
|
|
|
|
};
|
|
|
|
self.in_progress.push((id, None))
|
|
|
|
}
|
|
|
|
|
2018-01-01 00:13:56 +03:00
|
|
|
fn finish_internal(&mut self) {
|
2018-01-27 18:31:23 -05:00
|
|
|
let (id, _) = self.in_progress
|
|
|
|
.pop()
|
|
|
|
.expect("trying to complete a node, but there are no in-progress nodes");
|
2017-12-31 20:30:21 +03:00
|
|
|
if !self.in_progress.is_empty() {
|
|
|
|
self.add_len(id);
|
|
|
|
}
|
|
|
|
}
|
2018-01-07 10:55:43 +03:00
|
|
|
|
2018-02-09 22:44:50 +03:00
|
|
|
fn error(&mut self, err: ErrorMsg) {
|
|
|
|
let &(node, after_child) = self.in_progress.last().unwrap();
|
|
|
|
self.errors.push(SyntaxErrorData {
|
|
|
|
node,
|
2018-02-11 16:53:57 +03:00
|
|
|
message: err.msg,
|
2018-02-09 22:44:50 +03:00
|
|
|
after_child,
|
|
|
|
})
|
2018-01-07 10:55:43 +03:00
|
|
|
}
|
2018-01-01 00:13:56 +03:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FileBuilder {
|
|
|
|
pub fn new(text: String) -> FileBuilder {
|
|
|
|
FileBuilder {
|
|
|
|
text,
|
|
|
|
nodes: Vec::new(),
|
2018-01-07 10:10:35 +03:00
|
|
|
errors: Vec::new(),
|
2018-01-01 00:13:56 +03:00
|
|
|
in_progress: Vec::new(),
|
2018-07-28 13:07:10 +03:00
|
|
|
pos: 0.into(),
|
2018-01-01 00:13:56 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn finish(self) -> File {
|
2018-01-01 22:13:04 +03:00
|
|
|
assert!(
|
|
|
|
self.in_progress.is_empty(),
|
2018-01-07 14:56:08 +03:00
|
|
|
"some nodes in FileBuilder are unfinished: {:?}",
|
2018-01-27 18:31:23 -05:00
|
|
|
self.in_progress
|
|
|
|
.iter()
|
|
|
|
.map(|&(idx, _)| self.nodes[idx].kind)
|
2018-01-07 14:56:08 +03:00
|
|
|
.collect::<Vec<_>>()
|
2018-01-01 22:13:04 +03:00
|
|
|
);
|
2018-01-20 23:25:34 +03:00
|
|
|
assert_eq!(
|
2018-01-27 18:31:23 -05:00
|
|
|
self.pos,
|
|
|
|
(self.text.len() as u32).into(),
|
2018-01-01 22:13:04 +03:00
|
|
|
"nodes in FileBuilder do not cover the whole file"
|
|
|
|
);
|
2018-01-01 00:13:56 +03:00
|
|
|
File {
|
|
|
|
text: self.text,
|
|
|
|
nodes: self.nodes,
|
2018-01-07 10:10:35 +03:00
|
|
|
errors: self.errors,
|
2018-01-01 00:13:56 +03:00
|
|
|
}
|
|
|
|
}
|
2017-12-31 20:30:21 +03:00
|
|
|
|
|
|
|
fn new_node(&mut self, data: NodeData) -> NodeIdx {
|
|
|
|
let id = NodeIdx(self.nodes.len() as u32);
|
|
|
|
self.nodes.push(data);
|
|
|
|
id
|
|
|
|
}
|
|
|
|
|
|
|
|
fn push_child(&mut self, mut child: NodeData) -> NodeIdx {
|
|
|
|
child.parent = Some(self.current_id());
|
|
|
|
let id = self.new_node(child);
|
2018-01-01 22:13:04 +03:00
|
|
|
{
|
|
|
|
let (parent, sibling) = *self.in_progress.last().unwrap();
|
|
|
|
let slot = if let Some(idx) = sibling {
|
|
|
|
&mut self.nodes[idx].next_sibling
|
|
|
|
} else {
|
|
|
|
&mut self.nodes[parent].first_child
|
|
|
|
};
|
|
|
|
fill(slot, id);
|
2017-12-31 20:30:21 +03:00
|
|
|
}
|
2018-01-01 22:13:04 +03:00
|
|
|
self.in_progress.last_mut().unwrap().1 = Some(id);
|
2017-12-31 20:30:21 +03:00
|
|
|
id
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_len(&mut self, child: NodeIdx) {
|
2017-12-31 20:37:34 +03:00
|
|
|
let range = self.nodes[child].range;
|
2017-12-31 20:30:21 +03:00
|
|
|
grow(&mut self.current_parent().range, range);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn current_id(&self) -> NodeIdx {
|
|
|
|
self.in_progress.last().unwrap().0
|
|
|
|
}
|
|
|
|
|
|
|
|
fn current_parent(&mut self) -> &mut NodeData {
|
2017-12-31 20:37:34 +03:00
|
|
|
let idx = self.current_id();
|
|
|
|
&mut self.nodes[idx]
|
2017-12-31 20:30:21 +03:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
fn fill<T>(slot: &mut Option<T>, value: T) {
|
|
|
|
assert!(slot.is_none());
|
|
|
|
*slot = Some(value);
|
|
|
|
}
|
|
|
|
|
|
|
|
fn grow(left: &mut TextRange, right: TextRange) {
|
|
|
|
assert_eq!(left.end(), right.start());
|
|
|
|
*left = TextRange::from_to(left.start(), right.end())
|
2018-01-07 10:55:43 +03:00
|
|
|
}
|
|
|
|
|
2018-02-09 22:44:50 +03:00
|
|
|
#[derive(Default)]
|
|
|
|
pub(crate) struct ErrorMsg {
|
2018-02-11 16:53:57 +03:00
|
|
|
pub(crate) msg: String,
|
2018-01-07 10:55:43 +03:00
|
|
|
}
|