Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/syntax/src/parsing/text_tree_sink.rs')
-rw-r--r--crates/syntax/src/parsing/text_tree_sink.rs111
1 files changed, 63 insertions, 48 deletions
diff --git a/crates/syntax/src/parsing/text_tree_sink.rs b/crates/syntax/src/parsing/text_tree_sink.rs
index c9e7feb965..f40c549e3d 100644
--- a/crates/syntax/src/parsing/text_tree_sink.rs
+++ b/crates/syntax/src/parsing/text_tree_sink.rs
@@ -2,7 +2,7 @@
use std::mem;
-use parser::{LexedStr, ParseError, TreeSink};
+use parser::LexedStr;
use crate::{
ast,
@@ -12,10 +12,37 @@ use crate::{
SyntaxTreeBuilder, TextRange,
};
-/// Bridges the parser with our specific syntax tree representation.
-///
-/// `TextTreeSink` also handles attachment of trivia (whitespace) to nodes.
-pub(crate) struct TextTreeSink<'a> {
+pub(crate) fn build_tree(
+ lexed: LexedStr<'_>,
+ parser_output: parser::Output,
+ synthetic_root: bool,
+) -> (GreenNode, Vec<SyntaxError>, bool) {
+ let mut builder = Builder::new(lexed);
+
+ if synthetic_root {
+ builder.enter(SyntaxKind::SOURCE_FILE);
+ }
+
+ for event in parser_output.iter() {
+ match event {
+ parser::Step::Token { kind, n_input_tokens: n_raw_tokens } => {
+ builder.token(kind, n_raw_tokens)
+ }
+ parser::Step::Enter { kind } => builder.enter(kind),
+ parser::Step::Exit => builder.exit(),
+ parser::Step::Error { msg } => {
+ let text_pos = builder.lexed.text_start(builder.pos).try_into().unwrap();
+ builder.inner.error(msg.to_string(), text_pos);
+ }
+ }
+ }
+ if synthetic_root {
+ builder.exit()
+ }
+ builder.build()
+}
+
+struct Builder<'a> {
lexed: LexedStr<'a>,
pos: usize,
state: State,
@@ -28,7 +55,35 @@ enum State {
PendingFinish,
}
-impl<'a> TreeSink for TextTreeSink<'a> {
+impl<'a> Builder<'a> {
+ fn new(lexed: parser::LexedStr<'a>) -> Self {
+ Self { lexed, pos: 0, state: State::PendingStart, inner: SyntaxTreeBuilder::default() }
+ }
+
+ fn build(mut self) -> (GreenNode, Vec<SyntaxError>, bool) {
+ match mem::replace(&mut self.state, State::Normal) {
+ State::PendingFinish => {
+ self.eat_trivias();
+ self.inner.finish_node();
+ }
+ State::PendingStart | State::Normal => unreachable!(),
+ }
+
+ let (node, mut errors) = self.inner.finish_raw();
+ for (i, err) in self.lexed.errors() {
+ let text_range = self.lexed.text_range(i);
+ let text_range = TextRange::new(
+ text_range.start.try_into().unwrap(),
+ text_range.end.try_into().unwrap(),
+ );
+ errors.push(SyntaxError::new(err, text_range))
+ }
+
+ let is_eof = self.pos == self.lexed.len();
+
+ (node, errors, is_eof)
+ }
+
fn token(&mut self, kind: SyntaxKind, n_tokens: u8) {
match mem::replace(&mut self.state, State::Normal) {
State::PendingStart => unreachable!(),
@@ -39,7 +94,7 @@ impl<'a> TreeSink for TextTreeSink<'a> {
self.do_token(kind, n_tokens as usize);
}
- fn start_node(&mut self, kind: SyntaxKind) {
+ fn enter(&mut self, kind: SyntaxKind) {
match mem::replace(&mut self.state, State::Normal) {
State::PendingStart => {
self.inner.start_node(kind);
@@ -63,7 +118,7 @@ impl<'a> TreeSink for TextTreeSink<'a> {
self.eat_n_trivias(n_attached_trivias);
}
- fn finish_node(&mut self) {
+ fn exit(&mut self) {
match mem::replace(&mut self.state, State::PendingFinish) {
State::PendingStart => unreachable!(),
State::PendingFinish => self.inner.finish_node(),
@@ -71,46 +126,6 @@ impl<'a> TreeSink for TextTreeSink<'a> {
}
}
- fn error(&mut self, error: ParseError) {
- let text_pos = self.lexed.text_start(self.pos).try_into().unwrap();
- self.inner.error(error, text_pos);
- }
-}
-
-impl<'a> TextTreeSink<'a> {
- pub(super) fn new(lexed: parser::LexedStr<'a>) -> Self {
- Self { lexed, pos: 0, state: State::PendingStart, inner: SyntaxTreeBuilder::default() }
- }
-
- pub(super) fn finish_eof(mut self) -> (GreenNode, Vec<SyntaxError>, bool) {
- match mem::replace(&mut self.state, State::Normal) {
- State::PendingFinish => {
- self.eat_trivias();
- self.inner.finish_node();
- }
- State::PendingStart | State::Normal => unreachable!(),
- }
-
- let (node, mut errors) = self.inner.finish_raw();
- for (i, err) in self.lexed.errors() {
- let text_range = self.lexed.text_range(i);
- let text_range = TextRange::new(
- text_range.start.try_into().unwrap(),
- text_range.end.try_into().unwrap(),
- );
- errors.push(SyntaxError::new(err, text_range))
- }
-
- let is_eof = self.pos == self.lexed.len();
-
- (node, errors, is_eof)
- }
-
- pub(super) fn finish(self) -> (GreenNode, Vec<SyntaxError>) {
- let (node, errors, _eof) = self.finish_eof();
- (node, errors)
- }
-
fn eat_trivias(&mut self) {
while self.pos < self.lexed.len() {
let kind = self.lexed.kind(self.pos);