introduce tree builder
This commit is contained in:
@@ -36,7 +36,7 @@ pub use crate::{
|
|||||||
ast::AstNode,
|
ast::AstNode,
|
||||||
syntax_error::{SyntaxError, SyntaxErrorKind, Location},
|
syntax_error::{SyntaxError, SyntaxErrorKind, Location},
|
||||||
syntax_text::SyntaxText,
|
syntax_text::SyntaxText,
|
||||||
syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc},
|
syntax_node::{Direction, SyntaxNode, WalkEvent, TreeArc, SyntaxTreeBuilder},
|
||||||
ptr::{SyntaxNodePtr, AstPtr},
|
ptr::{SyntaxNodePtr, AstPtr},
|
||||||
parsing::{tokenize, Token},
|
parsing::{tokenize, Token},
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,13 +1,12 @@
|
|||||||
use std::mem;
|
use std::mem;
|
||||||
|
|
||||||
use ra_parser::{TreeSink, ParseError};
|
use ra_parser::{TreeSink, ParseError};
|
||||||
use rowan::GreenNodeBuilder;
|
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
SmolStr, SyntaxError, SyntaxErrorKind, TextUnit, TextRange,
|
SmolStr, SyntaxError, TextUnit, TextRange, SyntaxTreeBuilder,
|
||||||
SyntaxKind::{self, *},
|
SyntaxKind::{self, *},
|
||||||
parsing::Token,
|
parsing::Token,
|
||||||
syntax_node::{GreenNode, RaTypes},
|
syntax_node::GreenNode,
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Bridges the parser with our specific syntax tree representation.
|
/// Bridges the parser with our specific syntax tree representation.
|
||||||
@@ -19,8 +18,7 @@ pub(crate) struct TextTreeSink<'a> {
|
|||||||
text_pos: TextUnit,
|
text_pos: TextUnit,
|
||||||
token_pos: usize,
|
token_pos: usize,
|
||||||
state: State,
|
state: State,
|
||||||
errors: Vec<SyntaxError>,
|
inner: SyntaxTreeBuilder,
|
||||||
inner: GreenNodeBuilder<RaTypes>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
enum State {
|
enum State {
|
||||||
@@ -33,7 +31,7 @@ impl<'a> TreeSink for TextTreeSink<'a> {
|
|||||||
fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) {
|
fn leaf(&mut self, kind: SyntaxKind, n_tokens: u8) {
|
||||||
match mem::replace(&mut self.state, State::Normal) {
|
match mem::replace(&mut self.state, State::Normal) {
|
||||||
State::PendingStart => unreachable!(),
|
State::PendingStart => unreachable!(),
|
||||||
State::PendingFinish => self.inner.finish_internal(),
|
State::PendingFinish => self.inner.finish_branch(),
|
||||||
State::Normal => (),
|
State::Normal => (),
|
||||||
}
|
}
|
||||||
self.eat_trivias();
|
self.eat_trivias();
|
||||||
@@ -48,12 +46,12 @@ impl<'a> TreeSink for TextTreeSink<'a> {
|
|||||||
fn start_branch(&mut self, kind: SyntaxKind) {
|
fn start_branch(&mut self, kind: SyntaxKind) {
|
||||||
match mem::replace(&mut self.state, State::Normal) {
|
match mem::replace(&mut self.state, State::Normal) {
|
||||||
State::PendingStart => {
|
State::PendingStart => {
|
||||||
self.inner.start_internal(kind);
|
self.inner.start_branch(kind);
|
||||||
// No need to attach trivias to previous node: there is no
|
// No need to attach trivias to previous node: there is no
|
||||||
// previous node.
|
// previous node.
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
State::PendingFinish => self.inner.finish_internal(),
|
State::PendingFinish => self.inner.finish_branch(),
|
||||||
State::Normal => (),
|
State::Normal => (),
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -73,21 +71,20 @@ impl<'a> TreeSink for TextTreeSink<'a> {
|
|||||||
n_attached_trivias(kind, leading_trivias)
|
n_attached_trivias(kind, leading_trivias)
|
||||||
};
|
};
|
||||||
self.eat_n_trivias(n_trivias - n_attached_trivias);
|
self.eat_n_trivias(n_trivias - n_attached_trivias);
|
||||||
self.inner.start_internal(kind);
|
self.inner.start_branch(kind);
|
||||||
self.eat_n_trivias(n_attached_trivias);
|
self.eat_n_trivias(n_attached_trivias);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn finish_branch(&mut self) {
|
fn finish_branch(&mut self) {
|
||||||
match mem::replace(&mut self.state, State::PendingFinish) {
|
match mem::replace(&mut self.state, State::PendingFinish) {
|
||||||
State::PendingStart => unreachable!(),
|
State::PendingStart => unreachable!(),
|
||||||
State::PendingFinish => self.inner.finish_internal(),
|
State::PendingFinish => self.inner.finish_branch(),
|
||||||
State::Normal => (),
|
State::Normal => (),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn error(&mut self, error: ParseError) {
|
fn error(&mut self, error: ParseError) {
|
||||||
let error = SyntaxError::new(SyntaxErrorKind::ParseError(error), self.text_pos);
|
self.inner.error(error, self.text_pos)
|
||||||
self.errors.push(error)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -99,8 +96,7 @@ impl<'a> TextTreeSink<'a> {
|
|||||||
text_pos: 0.into(),
|
text_pos: 0.into(),
|
||||||
token_pos: 0,
|
token_pos: 0,
|
||||||
state: State::PendingStart,
|
state: State::PendingStart,
|
||||||
errors: Vec::new(),
|
inner: SyntaxTreeBuilder::default(),
|
||||||
inner: GreenNodeBuilder::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -108,12 +104,12 @@ impl<'a> TextTreeSink<'a> {
|
|||||||
match mem::replace(&mut self.state, State::Normal) {
|
match mem::replace(&mut self.state, State::Normal) {
|
||||||
State::PendingFinish => {
|
State::PendingFinish => {
|
||||||
self.eat_trivias();
|
self.eat_trivias();
|
||||||
self.inner.finish_internal()
|
self.inner.finish_branch()
|
||||||
}
|
}
|
||||||
State::PendingStart | State::Normal => unreachable!(),
|
State::PendingStart | State::Normal => unreachable!(),
|
||||||
}
|
}
|
||||||
|
|
||||||
(self.inner.finish(), self.errors)
|
self.inner.finish_raw()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn eat_trivias(&mut self) {
|
fn eat_trivias(&mut self) {
|
||||||
|
|||||||
@@ -11,11 +11,12 @@ use std::{
|
|||||||
borrow::Borrow,
|
borrow::Borrow,
|
||||||
};
|
};
|
||||||
|
|
||||||
use rowan::{Types, TransparentNewType};
|
use ra_parser::ParseError;
|
||||||
|
use rowan::{Types, TransparentNewType, GreenNodeBuilder};
|
||||||
|
|
||||||
use crate::{
|
use crate::{
|
||||||
SmolStr, SyntaxKind, TextRange, SyntaxText, SourceFile, AstNode,
|
SmolStr, SyntaxKind, TextUnit, TextRange, SyntaxText, SourceFile, AstNode,
|
||||||
syntax_error::SyntaxError,
|
syntax_error::{SyntaxError, SyntaxErrorKind},
|
||||||
};
|
};
|
||||||
|
|
||||||
pub use rowan::WalkEvent;
|
pub use rowan::WalkEvent;
|
||||||
@@ -276,3 +277,47 @@ fn has_short_text(kind: SyntaxKind) -> bool {
|
|||||||
_ => false,
|
_ => false,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct SyntaxTreeBuilder {
|
||||||
|
errors: Vec<SyntaxError>,
|
||||||
|
inner: GreenNodeBuilder<RaTypes>,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Default for SyntaxTreeBuilder {
|
||||||
|
fn default() -> SyntaxTreeBuilder {
|
||||||
|
SyntaxTreeBuilder { errors: Vec::new(), inner: GreenNodeBuilder::new() }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl SyntaxTreeBuilder {
|
||||||
|
pub(crate) fn finish_raw(self) -> (GreenNode, Vec<SyntaxError>) {
|
||||||
|
let green = self.inner.finish();
|
||||||
|
(green, self.errors)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish(self) -> TreeArc<SyntaxNode> {
|
||||||
|
let (green, errors) = self.finish_raw();
|
||||||
|
let node = SyntaxNode::new(green, errors);
|
||||||
|
if cfg!(debug_assertions) {
|
||||||
|
crate::validation::validate_block_structure(&node);
|
||||||
|
}
|
||||||
|
node
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn leaf(&mut self, kind: SyntaxKind, text: SmolStr) {
|
||||||
|
self.inner.leaf(kind, text)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn start_branch(&mut self, kind: SyntaxKind) {
|
||||||
|
self.inner.start_internal(kind)
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn finish_branch(&mut self) {
|
||||||
|
self.inner.finish_internal()
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn error(&mut self, error: ParseError, text_pos: TextUnit) {
|
||||||
|
let error = SyntaxError::new(SyntaxErrorKind::ParseError(error), text_pos);
|
||||||
|
self.errors.push(error)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user