mirror of
https://github.com/rust-lang/rust-analyzer
synced 2024-12-25 20:43:21 +00:00
File builder growndwork
This commit is contained in:
parent
9c804accf1
commit
9e4c288201
3 changed files with 120 additions and 0 deletions
|
@ -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 {
|
impl ops::Add<TextUnit> for TextUnit {
|
||||||
type Output = TextUnit;
|
type Output = TextUnit;
|
||||||
fn add(self, rhs: TextUnit) -> TextUnit {
|
fn add(self, rhs: TextUnit) -> TextUnit {
|
||||||
|
|
111
src/tree/file_builder.rs
Normal file
111
src/tree/file_builder.rs
Normal 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())
|
||||||
|
}
|
|
@ -3,6 +3,9 @@ use syntax_kinds::syntax_info;
|
||||||
|
|
||||||
use std::fmt;
|
use std::fmt;
|
||||||
|
|
||||||
|
mod file_builder;
|
||||||
|
pub use self::file_builder::FileBuilder;
|
||||||
|
|
||||||
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
#[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
|
||||||
pub struct SyntaxKind(pub(crate) u32);
|
pub struct SyntaxKind(pub(crate) u32);
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue