From 4e91c23c796988e3934afabf619185333f85c116 Mon Sep 17 00:00:00 2001 From: Aleksey Kladov Date: Tue, 12 Feb 2019 18:41:57 +0300 Subject: rename yellow -> syntax_node why yellow in the first place? Its red + green. --- crates/ra_syntax/src/syntax_node/builder.rs | 41 +++++++ crates/ra_syntax/src/syntax_node/syntax_error.rs | 142 ++++++++++++++++++++++ crates/ra_syntax/src/syntax_node/syntax_text.rs | 144 +++++++++++++++++++++++ 3 files changed, 327 insertions(+) create mode 100644 crates/ra_syntax/src/syntax_node/builder.rs create mode 100644 crates/ra_syntax/src/syntax_node/syntax_error.rs create mode 100644 crates/ra_syntax/src/syntax_node/syntax_text.rs (limited to 'crates/ra_syntax/src/syntax_node') diff --git a/crates/ra_syntax/src/syntax_node/builder.rs b/crates/ra_syntax/src/syntax_node/builder.rs new file mode 100644 index 000000000..8abd0f051 --- /dev/null +++ b/crates/ra_syntax/src/syntax_node/builder.rs @@ -0,0 +1,41 @@ +use crate::{ + parser_impl::Sink, + syntax_node::{GreenNode, RaTypes, SyntaxError}, + SmolStr, SyntaxKind, +}; +use rowan::GreenNodeBuilder; + +pub(crate) struct GreenBuilder { + errors: Vec, + inner: GreenNodeBuilder, +} + +impl GreenBuilder { + pub(crate) fn new() -> GreenBuilder { + GreenBuilder { errors: Vec::new(), inner: GreenNodeBuilder::new() } + } +} + +impl Sink for GreenBuilder { + type Tree = (GreenNode, Vec); + + fn leaf(&mut self, kind: SyntaxKind, text: SmolStr) { + self.inner.leaf(kind, text); + } + + fn start_branch(&mut self, kind: SyntaxKind) { + self.inner.start_internal(kind) + } + + fn finish_branch(&mut self) { + self.inner.finish_internal(); + } + + fn error(&mut self, error: SyntaxError) { + self.errors.push(error) + } + + fn finish(self) -> (GreenNode, Vec) { + (self.inner.finish(), self.errors) + } +} diff --git a/crates/ra_syntax/src/syntax_node/syntax_error.rs b/crates/ra_syntax/src/syntax_node/syntax_error.rs new file mode 100644 index 000000000..412cf82cc --- /dev/null +++ b/crates/ra_syntax/src/syntax_node/syntax_error.rs @@ -0,0 +1,142 @@ +use std::fmt; + +use crate::{TextRange, TextUnit}; + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct SyntaxError { + kind: SyntaxErrorKind, + location: Location, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum Location { + Offset(TextUnit), + Range(TextRange), +} + +impl Into for TextUnit { + fn into(self) -> Location { + Location::Offset(self) + } +} + +impl Into for TextRange { + fn into(self) -> Location { + Location::Range(self) + } +} + +impl SyntaxError { + pub fn new>(kind: SyntaxErrorKind, loc: L) -> SyntaxError { + SyntaxError { kind, location: loc.into() } + } + + pub fn kind(&self) -> SyntaxErrorKind { + self.kind.clone() + } + + pub fn location(&self) -> Location { + self.location.clone() + } + + pub fn offset(&self) -> TextUnit { + match self.location { + Location::Offset(offset) => offset, + Location::Range(range) => range.start(), + } + } + + pub fn add_offset(mut self, plus_offset: TextUnit) -> SyntaxError { + self.location = match self.location { + Location::Range(range) => Location::Range(range + plus_offset), + Location::Offset(offset) => Location::Offset(offset + plus_offset), + }; + + self + } +} + +impl fmt::Display for SyntaxError { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.kind.fmt(f) + } +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub enum SyntaxErrorKind { + ParseError(ParseError), + UnescapedCodepoint, + EmptyChar, + UnclosedChar, + OverlongChar, + EmptyByte, + UnclosedByte, + OverlongByte, + ByteOutOfRange, + UnescapedByte, + EmptyByteEscape, + InvalidByteEscape, + TooShortByteCodeEscape, + MalformedByteCodeEscape, + UnicodeEscapeForbidden, + EmptyAsciiEscape, + InvalidAsciiEscape, + TooShortAsciiCodeEscape, + AsciiCodeEscapeOutOfRange, + MalformedAsciiCodeEscape, + UnclosedUnicodeEscape, + MalformedUnicodeEscape, + EmptyUnicodeEcape, + OverlongUnicodeEscape, + UnicodeEscapeOutOfRange, + UnclosedString, + InvalidSuffix, + InvalidBlockAttr, +} + +#[derive(Debug, Clone, PartialEq, Eq, Hash)] +pub struct ParseError(pub String); + +impl fmt::Display for SyntaxErrorKind { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + use self::SyntaxErrorKind::*; + match self { + UnescapedCodepoint => write!(f, "This codepoint should always be escaped"), + EmptyAsciiEscape => write!(f, "Empty escape sequence"), + InvalidAsciiEscape => write!(f, "Invalid escape sequence"), + EmptyChar => write!(f, "Empty char literal"), + UnclosedChar => write!(f, "Unclosed char literal"), + OverlongChar => write!(f, "Char literal should be one character long"), + EmptyByte => write!(f, "Empty byte literal"), + UnclosedByte => write!(f, "Unclosed byte literal"), + OverlongByte => write!(f, "Byte literal should be one character long"), + ByteOutOfRange => write!(f, "Byte should be a valid ASCII character"), + UnescapedByte => write!(f, "This byte should always be escaped"), + EmptyByteEscape => write!(f, "Empty escape sequence"), + InvalidByteEscape => write!(f, "Invalid escape sequence"), + TooShortByteCodeEscape => write!(f, "Escape sequence should have two digits"), + MalformedByteCodeEscape => write!(f, "Escape sequence should be a hexadecimal number"), + UnicodeEscapeForbidden => { + write!(f, "Unicode escapes are not allowed in byte literals or byte strings") + } + TooShortAsciiCodeEscape => write!(f, "Escape sequence should have two digits"), + AsciiCodeEscapeOutOfRange => { + write!(f, "Escape sequence should be between \\x00 and \\x7F") + } + MalformedAsciiCodeEscape => write!(f, "Escape sequence should be a hexadecimal number"), + UnclosedUnicodeEscape => write!(f, "Missing `}}`"), + MalformedUnicodeEscape => write!(f, "Malformed unicode escape sequence"), + EmptyUnicodeEcape => write!(f, "Empty unicode escape sequence"), + OverlongUnicodeEscape => { + write!(f, "Unicode escape sequence should have at most 6 digits") + } + UnicodeEscapeOutOfRange => write!(f, "Unicode escape code should be at most 0x10FFFF"), + UnclosedString => write!(f, "Unclosed string literal"), + InvalidSuffix => write!(f, "Invalid literal suffix"), + InvalidBlockAttr => { + write!(f, "A block in this position cannot accept inner attributes") + } + ParseError(msg) => write!(f, "{}", msg.0), + } + } +} diff --git a/crates/ra_syntax/src/syntax_node/syntax_text.rs b/crates/ra_syntax/src/syntax_node/syntax_text.rs new file mode 100644 index 000000000..84e5b231a --- /dev/null +++ b/crates/ra_syntax/src/syntax_node/syntax_text.rs @@ -0,0 +1,144 @@ +use std::{fmt, ops}; + +use crate::{SyntaxNode, TextRange, TextUnit}; + +#[derive(Clone)] +pub struct SyntaxText<'a> { + node: &'a SyntaxNode, + range: TextRange, +} + +impl<'a> SyntaxText<'a> { + pub(crate) fn new(node: &'a SyntaxNode) -> SyntaxText<'a> { + SyntaxText { node, range: node.range() } + } + + pub fn chunks(&self) -> impl Iterator { + let range = self.range; + self.node.descendants().filter_map(move |node| { + let text = node.leaf_text()?; + let range = range.intersection(&node.range())?; + let range = range - node.range().start(); + Some(&text[range]) + }) + } + + pub fn push_to(&self, buf: &mut String) { + self.chunks().for_each(|it| buf.push_str(it)); + } + + pub fn to_string(&self) -> String { + self.chunks().collect() + } + + pub fn contains(&self, c: char) -> bool { + self.chunks().any(|it| it.contains(c)) + } + + pub fn find(&self, c: char) -> Option { + let mut acc: TextUnit = 0.into(); + for chunk in self.chunks() { + if let Some(pos) = chunk.find(c) { + let pos: TextUnit = (pos as u32).into(); + return Some(acc + pos); + } + acc += TextUnit::of_str(chunk); + } + None + } + + pub fn len(&self) -> TextUnit { + self.range.len() + } + + pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> { + let range = range.restrict(self.range).unwrap_or_else(|| { + panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range) + }); + SyntaxText { node: self.node, range } + } + + pub fn char_at(&self, offset: impl Into) -> Option { + let mut start: TextUnit = 0.into(); + let offset = offset.into(); + for chunk in self.chunks() { + let end = start + TextUnit::of_str(chunk); + if start <= offset && offset < end { + let off: usize = u32::from(offset - start) as usize; + return Some(chunk[off..].chars().next().unwrap()); + } + start = end; + } + None + } +} + +impl<'a> fmt::Debug for SyntaxText<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Debug::fmt(&self.to_string(), f) + } +} + +impl<'a> fmt::Display for SyntaxText<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + fmt::Display::fmt(&self.to_string(), f) + } +} + +pub trait SyntaxTextSlice: fmt::Debug { + fn restrict(&self, range: TextRange) -> Option; +} + +impl SyntaxTextSlice for TextRange { + fn restrict(&self, range: TextRange) -> Option { + self.intersection(&range) + } +} + +impl SyntaxTextSlice for ops::RangeTo { + fn restrict(&self, range: TextRange) -> Option { + if !range.contains_inclusive(self.end) { + return None; + } + Some(TextRange::from_to(range.start(), self.end)) + } +} + +impl SyntaxTextSlice for ops::RangeFrom { + fn restrict(&self, range: TextRange) -> Option { + if !range.contains_inclusive(self.start) { + return None; + } + Some(TextRange::from_to(self.start, range.end())) + } +} + +impl SyntaxTextSlice for ops::Range { + fn restrict(&self, range: TextRange) -> Option { + TextRange::from_to(self.start, self.end).restrict(range) + } +} + +impl From> for String { + fn from(text: SyntaxText) -> String { + text.to_string() + } +} + +impl PartialEq for SyntaxText<'_> { + fn eq(&self, mut rhs: &str) -> bool { + for chunk in self.chunks() { + if !rhs.starts_with(chunk) { + return false; + } + rhs = &rhs[chunk.len()..]; + } + rhs.is_empty() + } +} + +impl PartialEq<&'_ str> for SyntaxText<'_> { + fn eq(&self, rhs: &&str) -> bool { + self == *rhs + } +} -- cgit v1.2.3