use text::{TextRange, TextUnit}; use std::fmt; use std::cmp; mod file_builder; pub(crate) use self::file_builder::{FileBuilder, Sink}; pub use syntax_kinds::SyntaxKind; impl fmt::Debug for SyntaxKind { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { let name = self.info().name; f.write_str(name) } } pub(crate) struct SyntaxInfo { pub name: &'static str, } /// A token of Rust source. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)] pub struct Token { /// The kind of token. pub kind: SyntaxKind, /// The length of the token. pub len: TextUnit, } /// The contents of a Rust source file. #[derive(Debug)] pub struct File { text: String, nodes: Vec, errors: Vec, } impl File { /// The root node of this source file. pub fn root<'f>(&'f self) -> Node<'f> { assert!(!self.nodes.is_empty()); Node { file: self, idx: NodeIdx(0), } } } /// A reference to a token in a Rust source file. #[derive(Clone, Copy)] pub struct Node<'f> { file: &'f File, idx: NodeIdx, } impl<'f> Node<'f> { /// The kind of the token at this node. pub fn kind(&self) -> SyntaxKind { self.data().kind } /// The text range covered by the token at this node. pub fn range(&self) -> TextRange { self.data().range } /// The text at this node. pub fn text(&self) -> &'f str { &self.file.text.as_str()[self.range()] } /// The parent node to this node. pub fn parent(&self) -> Option> { self.as_node(self.data().parent) } /// The children nodes of this node. pub fn children(&self) -> Children<'f> { Children { next: self.as_node(self.data().first_child), } } /// Any errors contained in this node. pub fn errors(&self) -> SyntaxErrors<'f> { let pos = self.file.errors.iter().position(|e| e.node == self.idx); let next = pos.map(|i| ErrorIdx(i as u32)).map(|idx| SyntaxError { file: self.file, idx, }); SyntaxErrors { next } } fn data(&self) -> &'f NodeData { &self.file.nodes[self.idx] } fn as_node(&self, idx: Option) -> Option> { idx.map(|idx| Node { file: self.file, idx, }) } } impl<'f> fmt::Debug for Node<'f> { fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result { write!(fmt, "{:?}@{:?}", self.kind(), self.range()) } } impl<'f> cmp::PartialEq> for Node<'f> { fn eq(&self, other: &Node<'f>) -> bool { self.idx == other.idx && ::std::ptr::eq(self.file, other.file) } } impl<'f> cmp::Eq for Node<'f> {} #[derive(Clone, Copy, Debug)] pub struct SyntaxError<'f> { file: &'f File, idx: ErrorIdx, } impl<'f> SyntaxError<'f> { pub fn message(&self) -> &'f str { self.data().message.as_str() } pub fn after_child(&self) -> Option> { let idx = self.data().after_child?; Some(Node { file: self.file, idx, }) } fn data(&self) -> &'f SyntaxErrorData { &self.file.errors[self.idx] } fn next(&self) -> Option> { let next_idx = self.idx.0 + 1; if !((next_idx as usize) < self.file.errors.len()) { return None; } let result = SyntaxError { file: self.file, idx: ErrorIdx(next_idx), }; if result.data().node != self.data().node { return None; } Some(result) } } #[derive(Debug)] pub struct Children<'f> { next: Option>, } impl<'f> Iterator for Children<'f> { type Item = Node<'f>; fn next(&mut self) -> Option> { let next = self.next; self.next = next.and_then(|node| node.as_node(node.data().next_sibling)); next } } #[derive(Debug)] pub struct SyntaxErrors<'f> { next: Option>, } impl<'f> Iterator for SyntaxErrors<'f> { type Item = SyntaxError<'f>; fn next(&mut self) -> Option> { let next = self.next; self.next = next.as_ref().and_then(SyntaxError::next); next } } #[derive(Clone, Copy, Debug, PartialEq, Eq)] struct NodeIdx(u32); #[derive(Debug)] struct NodeData { kind: SyntaxKind, range: TextRange, parent: Option, first_child: Option, next_sibling: Option, } impl ::std::ops::Index for Vec { type Output = NodeData; fn index(&self, NodeIdx(idx): NodeIdx) -> &NodeData { &self[idx as usize] } } impl ::std::ops::IndexMut for Vec { fn index_mut(&mut self, NodeIdx(idx): NodeIdx) -> &mut NodeData { &mut self[idx as usize] } } #[derive(Clone, Copy, Debug)] struct ErrorIdx(u32); #[derive(Debug)] struct SyntaxErrorData { node: NodeIdx, message: String, after_child: Option, } impl ::std::ops::Index for Vec { type Output = SyntaxErrorData; fn index(&self, ErrorIdx(idx): ErrorIdx) -> &SyntaxErrorData { &self[idx as usize] } }