File builder growndwork

This commit is contained in:
Aleksey Kladov 2017-12-31 20:30:21 +03:00
parent 9c804accf1
commit 9e4c288201
3 changed files with 120 additions and 0 deletions

View file

@ -32,6 +32,12 @@ impl From<TextUnit> for u32 {
}
}
impl From<u32> for TextUnit {
fn from(tu: u32) -> TextUnit {
TextUnit::new(tu)
}
}
impl ops::Add<TextUnit> for TextUnit {
type Output = TextUnit;
fn add(self, rhs: TextUnit) -> TextUnit {

111
src/tree/file_builder.rs Normal file
View file

@ -0,0 +1,111 @@
use {SyntaxKind, TextUnit, TextRange};
use super::{NodeData, NodeIdx, File};
pub struct FileBuilder {
text: String,
nodes: Vec<NodeData>,
in_progress: Vec<(NodeIdx, Option<NodeIdx>)>, // (parent, last_child)
pos: TextUnit,
}
impl FileBuilder {
pub fn new(text: String) -> FileBuilder {
FileBuilder {
text,
nodes: Vec::new(),
in_progress: Vec::new(),
pos: TextUnit::new(0),
}
}
pub fn finish(self) -> File {
assert!(self.in_progress.is_empty());
assert!(self.pos == (self.text.len() as u32).into());
File {
text: self.text,
nodes: self.nodes,
}
}
pub fn leaf(&mut self, kind: SyntaxKind, len: TextUnit) {
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);
}
pub fn start_internal(&mut self, kind: SyntaxKind) {
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))
}
pub fn finish_internal(&mut self) {
let (id, _) = self.in_progress.pop().unwrap();
if !self.in_progress.is_empty() {
self.add_len(id);
}
}
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);
if let Some(sibling) = self.current_sibling() {
fill(&mut sibling.next_sibling, id);
return id
}
fill(&mut self.current_parent().first_child, id);
id
}
fn add_len(&mut self, child: NodeIdx) {
let range = self.nodes[child.0 as usize].range;
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 {
let NodeIdx(idx) = self.current_id();
&mut self.nodes[idx as usize]
}
fn current_sibling(&mut self) -> Option<&mut NodeData> {
let NodeIdx(idx) = self.in_progress.last().unwrap().1?;
Some(&mut self.nodes[idx as usize])
}
}
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())
}

View file

@ -3,6 +3,9 @@ use syntax_kinds::syntax_info;
use std::fmt;
mod file_builder;
pub use self::file_builder::FileBuilder;
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
pub struct SyntaxKind(pub(crate) u32);