use clap::{App, Arg, SubCommand};
use join_to_string::join;
-use ra_ide_api_light::{extend_selection, file_structure, syntax_tree};
+use ra_ide_api_light::{extend_selection, file_structure};
use ra_syntax::{SourceFile, TextRange, TreeArc, AstNode};
use tools::collect_tests;
use flexi_logger::Logger;
let file = file()?;
let elapsed = start.elapsed();
if !matches.is_present("no-dump") {
- println!("{}", syntax_tree(&file));
+ println!("{}", file.syntax().debug_dump());
}
eprintln!("parsing: {:?}", elapsed);
::std::mem::forget(file);
Some((_start_line, test)) => test,
};
let file = SourceFile::parse(&test.text);
- let tree = syntax_tree(&file);
+ let tree = file.syntax().debug_dump();
Ok((test.text, tree))
}
use std::sync::Arc;
-use ra_syntax::{SourceFile, TreeArc, TextRange, TextUnit};
+use ra_syntax::{SourceFile, TreeArc, TextRange, TextUnit, AstNode};
use ra_text_edit::TextEdit;
use ra_db::{
SourceDatabase, CheckCanceled,
/// Returns a syntax tree represented as `String`, for debug purposes.
// FIXME: use a better name here.
pub fn syntax_tree(&self, file_id: FileId) -> String {
- let file = self.db.parse(file_id);
- ra_ide_api_light::syntax_tree(&file)
+ self.db.parse(file_id).syntax().debug_dump()
}
/// Returns an edit to remove all newlines in the range, cleaning up minor
res
}
-pub fn syntax_tree(file: &SourceFile) -> String {
- ::ra_syntax::utils::dump_tree(file.syntax())
-}
-
#[cfg(test)]
mod tests {
use ra_syntax::AstNode;
fuzz_target!(|data: &[u8]| {
if let Ok(text) = std::str::from_utf8(data) {
- ra_syntax::utils::check_fuzz_invariants(text)
+ ra_syntax::check_fuzz_invariants(text)
}
});
pub mod algo;
pub mod ast;
-/// Utilities for simple uses of the parser.
-pub mod utils;
pub use rowan::{SmolStr, TextRange, TextUnit};
pub use ra_parser::SyntaxKind;
fn new(green: GreenNode, errors: Vec<SyntaxError>) -> TreeArc<SourceFile> {
let root = SyntaxNode::new(green, errors);
if cfg!(debug_assertions) {
- utils::validate_block_structure(&root);
+ validation::validate_block_structure(&root);
}
assert_eq!(root.kind(), SyntaxKind::SOURCE_FILE);
TreeArc::cast(root)
errors
}
}
+
+pub fn check_fuzz_invariants(text: &str) {
+ let file = SourceFile::parse(text);
+ let root = file.syntax();
+ validation::validate_block_structure(root);
+ let _ = file.errors();
+}
mod tests {
use test_utils::{extract_range, assert_eq_text};
- use crate::{SourceFile, AstNode, utils::dump_tree};
+ use crate::{SourceFile, AstNode};
use super::*;
fn do_check<F>(before: &str, replace_with: &str, reparser: F)
};
assert_eq_text!(
- &dump_tree(fully_reparsed.syntax()),
- &dump_tree(incrementally_reparsed.syntax()),
+ &fully_reparsed.syntax().debug_dump(),
+ &incrementally_reparsed.syntax().debug_dump(),
)
}
//! The *real* implementation is in the (language-agnostic) `rowan` crate, this
//! modules just wraps its API.
-use std::{fmt, borrow::Borrow};
+use std::{fmt::{self, Write}, borrow::Borrow};
use rowan::{Types, TransparentNewType};
use crate::{
- SmolStr, SyntaxKind, TextRange, SyntaxText,
+ SmolStr, SyntaxKind, TextRange, SyntaxText, SourceFile, AstNode,
syntax_error::SyntaxError,
};
WalkEvent::Leave(n) => WalkEvent::Leave(SyntaxNode::from_repr(n)),
})
}
+
+ pub fn debug_dump(&self) -> String {
+ let mut errors: Vec<_> = match self.ancestors().find_map(SourceFile::cast) {
+ Some(file) => file.errors(),
+ None => self.root_data().to_vec(),
+ };
+ errors.sort_by_key(|e| e.offset());
+ let mut err_pos = 0;
+ let mut level = 0;
+ let mut buf = String::new();
+ macro_rules! indent {
+ () => {
+ for _ in 0..level {
+ buf.push_str(" ");
+ }
+ };
+ }
+
+ for event in self.preorder() {
+ match event {
+ WalkEvent::Enter(node) => {
+ indent!();
+ writeln!(buf, "{:?}", node).unwrap();
+ if node.first_child().is_none() {
+ let off = node.range().end();
+ while err_pos < errors.len() && errors[err_pos].offset() <= off {
+ indent!();
+ writeln!(buf, "err: `{}`", errors[err_pos]).unwrap();
+ err_pos += 1;
+ }
+ }
+ level += 1;
+ }
+ WalkEvent::Leave(_) => level -= 1,
+ }
+ }
+
+ assert_eq!(level, 0);
+ for err in errors[err_pos..].iter() {
+ writeln!(buf, "err: `{}`", err).unwrap();
+ }
+
+ buf
+ }
}
impl ToOwned for SyntaxNode {
+++ /dev/null
-use std::{str, fmt::Write};
-
-use crate::{SourceFile, SyntaxKind, WalkEvent, AstNode, SyntaxNode};
-
-/// Parse a file and create a string representation of the resulting parse tree.
-pub fn dump_tree(syntax: &SyntaxNode) -> String {
- let mut errors: Vec<_> = match syntax.ancestors().find_map(SourceFile::cast) {
- Some(file) => file.errors(),
- None => syntax.root_data().to_vec(),
- };
- errors.sort_by_key(|e| e.offset());
- let mut err_pos = 0;
- let mut level = 0;
- let mut buf = String::new();
- macro_rules! indent {
- () => {
- for _ in 0..level {
- buf.push_str(" ");
- }
- };
- }
-
- for event in syntax.preorder() {
- match event {
- WalkEvent::Enter(node) => {
- indent!();
- writeln!(buf, "{:?}", node).unwrap();
- if node.first_child().is_none() {
- let off = node.range().end();
- while err_pos < errors.len() && errors[err_pos].offset() <= off {
- indent!();
- writeln!(buf, "err: `{}`", errors[err_pos]).unwrap();
- err_pos += 1;
- }
- }
- level += 1;
- }
- WalkEvent::Leave(_) => level -= 1,
- }
- }
-
- assert_eq!(level, 0);
- for err in errors[err_pos..].iter() {
- writeln!(buf, "err: `{}`", err).unwrap();
- }
-
- buf
-}
-
-pub fn check_fuzz_invariants(text: &str) {
- let file = SourceFile::parse(text);
- let root = file.syntax();
- validate_block_structure(root);
- let _ = file.errors();
-}
-
-pub(crate) fn validate_block_structure(root: &SyntaxNode) {
- let mut stack = Vec::new();
- for node in root.descendants() {
- match node.kind() {
- SyntaxKind::L_CURLY => stack.push(node),
- SyntaxKind::R_CURLY => {
- if let Some(pair) = stack.pop() {
- assert_eq!(
- node.parent(),
- pair.parent(),
- "\nunpaired curleys:\n{}\n{}\n",
- root.text(),
- dump_tree(root),
- );
- assert!(
- node.next_sibling().is_none() && pair.prev_sibling().is_none(),
- "\nfloating curlys at {:?}\nfile:\n{}\nerror:\n{}\n",
- node,
- root.text(),
- node.text(),
- );
- }
- }
- _ => (),
- }
- }
-}
mod block;
use crate::{
- SourceFile, SyntaxError, AstNode,
+ SourceFile, SyntaxError, AstNode, SyntaxNode,
+ SyntaxKind::{L_CURLY, R_CURLY},
ast,
algo::visit::{visitor_ctx, VisitorCtx},
};
let mut errors = Vec::new();
for node in file.syntax().descendants() {
let _ = visitor_ctx(&mut errors)
- .visit::<ast::Byte, _>(self::byte::validate_byte_node)
- .visit::<ast::ByteString, _>(self::byte_string::validate_byte_string_node)
- .visit::<ast::Char, _>(self::char::validate_char_node)
- .visit::<ast::String, _>(self::string::validate_string_node)
- .visit::<ast::Block, _>(self::block::validate_block_node)
+ .visit::<ast::Byte, _>(byte::validate_byte_node)
+ .visit::<ast::ByteString, _>(byte_string::validate_byte_string_node)
+ .visit::<ast::Char, _>(char::validate_char_node)
+ .visit::<ast::String, _>(string::validate_string_node)
+ .visit::<ast::Block, _>(block::validate_block_node)
.accept(node);
}
errors
}
+
+pub(crate) fn validate_block_structure(root: &SyntaxNode) {
+ let mut stack = Vec::new();
+ for node in root.descendants() {
+ match node.kind() {
+ L_CURLY => stack.push(node),
+ R_CURLY => {
+ if let Some(pair) = stack.pop() {
+ assert_eq!(
+ node.parent(),
+ pair.parent(),
+ "\nunpaired curleys:\n{}\n{}\n",
+ root.text(),
+ root.debug_dump(),
+ );
+ assert!(
+ node.next_sibling().is_none() && pair.prev_sibling().is_none(),
+ "\nfloating curlys at {:?}\nfile:\n{}\nerror:\n{}\n",
+ node,
+ root.text(),
+ node.text(),
+ );
+ }
+ }
+ _ => (),
+ }
+ }
+}
};
use test_utils::{project_dir, dir_tests, read_text, collect_tests};
-use ra_syntax::{
- SourceFile, AstNode,
- utils::{check_fuzz_invariants, dump_tree},
-};
+use ra_syntax::{SourceFile, AstNode, check_fuzz_invariants};
#[test]
fn lexer_tests() {
"There should be no errors in the file {:?}",
path.display()
);
- dump_tree(file.syntax())
+ file.syntax().debug_dump()
});
dir_tests(&test_data_dir(), &["parser/err", "parser/inline/err"], |text, path| {
let file = SourceFile::parse(text);
"There should be errors in the file {:?}",
path.display()
);
- dump_tree(file.syntax())
+ file.syntax().debug_dump()
});
}