2018-01-28 00:31:23 +01:00
|
|
|
use {SyntaxKind, TextRange, TextUnit};
|
|
|
|
use super::{File, NodeData, NodeIdx, SyntaxErrorData};
|
2017-12-31 18:30:21 +01:00
|
|
|
|
2017-12-31 22:13:56 +01:00
|
|
|
pub trait Sink {
|
|
|
|
fn leaf(&mut self, kind: SyntaxKind, len: TextUnit);
|
|
|
|
fn start_internal(&mut self, kind: SyntaxKind);
|
|
|
|
fn finish_internal(&mut self);
|
2018-01-07 08:55:43 +01:00
|
|
|
fn error(&mut self) -> ErrorBuilder;
|
2017-12-31 22:13:56 +01:00
|
|
|
}
|
|
|
|
|
2017-12-31 18:30:21 +01:00
|
|
|
pub struct FileBuilder {
|
|
|
|
text: String,
|
|
|
|
nodes: Vec<NodeData>,
|
2018-01-07 08:10:35 +01:00
|
|
|
errors: Vec<SyntaxErrorData>,
|
2017-12-31 18:30:21 +01:00
|
|
|
in_progress: Vec<(NodeIdx, Option<NodeIdx>)>, // (parent, last_child)
|
|
|
|
pos: TextUnit,
|
|
|
|
}
|
|
|
|
|
2017-12-31 22:13:56 +01:00
|
|
|
impl Sink for FileBuilder {
|
|
|
|
fn leaf(&mut self, kind: SyntaxKind, len: TextUnit) {
|
2017-12-31 18:30:21 +01:00
|
|
|
let leaf = NodeData {
|
|
|
|
kind,
|
|
|
|
range: TextRange::from_len(self.pos, len),
|
|
|
|
parent: None,
|
|
|
|
first_child: None,
|
|
|
|
next_sibling: None,
|
|
|
|
};
|
|
|
|
self.pos += len;
|
|
|
|
let id = self.push_child(leaf);
|
|
|
|
self.add_len(id);
|
|
|
|
}
|
|
|
|
|
2017-12-31 22:13:56 +01:00
|
|
|
fn start_internal(&mut self, kind: SyntaxKind) {
|
2017-12-31 18:30:21 +01:00
|
|
|
let node = NodeData {
|
|
|
|
kind,
|
|
|
|
range: TextRange::from_len(self.pos, 0.into()),
|
|
|
|
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))
|
|
|
|
}
|
|
|
|
|
2017-12-31 22:13:56 +01:00
|
|
|
fn finish_internal(&mut self) {
|
2018-01-28 00:31:23 +01:00
|
|
|
let (id, _) = self.in_progress
|
|
|
|
.pop()
|
|
|
|
.expect("trying to complete a node, but there are no in-progress nodes");
|
2017-12-31 18:30:21 +01:00
|
|
|
if !self.in_progress.is_empty() {
|
|
|
|
self.add_len(id);
|
|
|
|
}
|
|
|
|
}
|
2018-01-07 08:55:43 +01:00
|
|
|
|
|
|
|
fn error(&mut self) -> ErrorBuilder {
|
|
|
|
ErrorBuilder::new(self)
|
|
|
|
}
|
2017-12-31 22:13:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl FileBuilder {
|
|
|
|
pub fn new(text: String) -> FileBuilder {
|
|
|
|
FileBuilder {
|
|
|
|
text,
|
|
|
|
nodes: Vec::new(),
|
2018-01-07 08:10:35 +01:00
|
|
|
errors: Vec::new(),
|
2017-12-31 22:13:56 +01:00
|
|
|
in_progress: Vec::new(),
|
|
|
|
pos: TextUnit::new(0),
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
pub fn finish(self) -> File {
|
2018-01-01 20:13:04 +01:00
|
|
|
assert!(
|
|
|
|
self.in_progress.is_empty(),
|
2018-01-07 12:56:08 +01:00
|
|
|
"some nodes in FileBuilder are unfinished: {:?}",
|
2018-01-28 00:31:23 +01:00
|
|
|
self.in_progress
|
|
|
|
.iter()
|
|
|
|
.map(|&(idx, _)| self.nodes[idx].kind)
|
2018-01-07 12:56:08 +01:00
|
|
|
.collect::<Vec<_>>()
|
2018-01-01 20:13:04 +01:00
|
|
|
);
|
2018-01-20 21:25:34 +01:00
|
|
|
assert_eq!(
|
2018-01-28 00:31:23 +01:00
|
|
|
self.pos,
|
|
|
|
(self.text.len() as u32).into(),
|
2018-01-01 20:13:04 +01:00
|
|
|
"nodes in FileBuilder do not cover the whole file"
|
|
|
|
);
|
2017-12-31 22:13:56 +01:00
|
|
|
File {
|
|
|
|
text: self.text,
|
|
|
|
nodes: self.nodes,
|
2018-01-07 08:10:35 +01:00
|
|
|
errors: self.errors,
|
2017-12-31 22:13:56 +01:00
|
|
|
}
|
|
|
|
}
|
2017-12-31 18:30:21 +01: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 20:13:04 +01: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 18:30:21 +01:00
|
|
|
}
|
2018-01-01 20:13:04 +01:00
|
|
|
self.in_progress.last_mut().unwrap().1 = Some(id);
|
2017-12-31 18:30:21 +01:00
|
|
|
id
|
|
|
|
}
|
|
|
|
|
|
|
|
fn add_len(&mut self, child: NodeIdx) {
|
2017-12-31 18:37:34 +01:00
|
|
|
let range = self.nodes[child].range;
|
2017-12-31 18:30:21 +01: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 18:37:34 +01:00
|
|
|
let idx = self.current_id();
|
|
|
|
&mut self.nodes[idx]
|
2017-12-31 18:30:21 +01: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 08:55:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub struct ErrorBuilder<'f> {
|
|
|
|
message: Option<String>,
|
2018-01-28 00:31:23 +01:00
|
|
|
builder: &'f mut FileBuilder,
|
2018-01-07 08:55:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
impl<'f> ErrorBuilder<'f> {
|
|
|
|
fn new(builder: &'f mut FileBuilder) -> Self {
|
2018-01-28 00:31:23 +01:00
|
|
|
ErrorBuilder {
|
|
|
|
message: None,
|
|
|
|
builder,
|
|
|
|
}
|
2018-01-07 08:55:43 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
pub fn message<M: Into<String>>(mut self, m: M) -> Self {
|
|
|
|
self.message = Some(m.into());
|
|
|
|
self
|
|
|
|
}
|
|
|
|
|
2018-01-07 10:13:01 +01:00
|
|
|
pub fn emit(self) {
|
2018-01-07 08:55:43 +01:00
|
|
|
let message = self.message.expect("Error message not set");
|
2018-01-07 11:09:13 +01:00
|
|
|
let &(node, after_child) = self.builder.in_progress.last().unwrap();
|
2018-01-28 00:31:23 +01:00
|
|
|
self.builder.errors.push(SyntaxErrorData {
|
|
|
|
node,
|
|
|
|
message,
|
|
|
|
after_child,
|
|
|
|
})
|
2018-01-07 08:55:43 +01:00
|
|
|
}
|
|
|
|
}
|