aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/syntax_node
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/syntax_node')
-rw-r--r--crates/ra_syntax/src/syntax_node/builder.rs41
-rw-r--r--crates/ra_syntax/src/syntax_node/syntax_error.rs142
-rw-r--r--crates/ra_syntax/src/syntax_node/syntax_text.rs144
3 files changed, 327 insertions, 0 deletions
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 @@
1use crate::{
2 parser_impl::Sink,
3 syntax_node::{GreenNode, RaTypes, SyntaxError},
4 SmolStr, SyntaxKind,
5};
6use rowan::GreenNodeBuilder;
7
8pub(crate) struct GreenBuilder {
9 errors: Vec<SyntaxError>,
10 inner: GreenNodeBuilder<RaTypes>,
11}
12
13impl GreenBuilder {
14 pub(crate) fn new() -> GreenBuilder {
15 GreenBuilder { errors: Vec::new(), inner: GreenNodeBuilder::new() }
16 }
17}
18
19impl Sink for GreenBuilder {
20 type Tree = (GreenNode, Vec<SyntaxError>);
21
22 fn leaf(&mut self, kind: SyntaxKind, text: SmolStr) {
23 self.inner.leaf(kind, text);
24 }
25
26 fn start_branch(&mut self, kind: SyntaxKind) {
27 self.inner.start_internal(kind)
28 }
29
30 fn finish_branch(&mut self) {
31 self.inner.finish_internal();
32 }
33
34 fn error(&mut self, error: SyntaxError) {
35 self.errors.push(error)
36 }
37
38 fn finish(self) -> (GreenNode, Vec<SyntaxError>) {
39 (self.inner.finish(), self.errors)
40 }
41}
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 @@
1use std::fmt;
2
3use crate::{TextRange, TextUnit};
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
6pub struct SyntaxError {
7 kind: SyntaxErrorKind,
8 location: Location,
9}
10
11#[derive(Debug, Clone, PartialEq, Eq, Hash)]
12pub enum Location {
13 Offset(TextUnit),
14 Range(TextRange),
15}
16
17impl Into<Location> for TextUnit {
18 fn into(self) -> Location {
19 Location::Offset(self)
20 }
21}
22
23impl Into<Location> for TextRange {
24 fn into(self) -> Location {
25 Location::Range(self)
26 }
27}
28
29impl SyntaxError {
30 pub fn new<L: Into<Location>>(kind: SyntaxErrorKind, loc: L) -> SyntaxError {
31 SyntaxError { kind, location: loc.into() }
32 }
33
34 pub fn kind(&self) -> SyntaxErrorKind {
35 self.kind.clone()
36 }
37
38 pub fn location(&self) -> Location {
39 self.location.clone()
40 }
41
42 pub fn offset(&self) -> TextUnit {
43 match self.location {
44 Location::Offset(offset) => offset,
45 Location::Range(range) => range.start(),
46 }
47 }
48
49 pub fn add_offset(mut self, plus_offset: TextUnit) -> SyntaxError {
50 self.location = match self.location {
51 Location::Range(range) => Location::Range(range + plus_offset),
52 Location::Offset(offset) => Location::Offset(offset + plus_offset),
53 };
54
55 self
56 }
57}
58
59impl fmt::Display for SyntaxError {
60 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
61 self.kind.fmt(f)
62 }
63}
64
65#[derive(Debug, Clone, PartialEq, Eq, Hash)]
66pub enum SyntaxErrorKind {
67 ParseError(ParseError),
68 UnescapedCodepoint,
69 EmptyChar,
70 UnclosedChar,
71 OverlongChar,
72 EmptyByte,
73 UnclosedByte,
74 OverlongByte,
75 ByteOutOfRange,
76 UnescapedByte,
77 EmptyByteEscape,
78 InvalidByteEscape,
79 TooShortByteCodeEscape,
80 MalformedByteCodeEscape,
81 UnicodeEscapeForbidden,
82 EmptyAsciiEscape,
83 InvalidAsciiEscape,
84 TooShortAsciiCodeEscape,
85 AsciiCodeEscapeOutOfRange,
86 MalformedAsciiCodeEscape,
87 UnclosedUnicodeEscape,
88 MalformedUnicodeEscape,
89 EmptyUnicodeEcape,
90 OverlongUnicodeEscape,
91 UnicodeEscapeOutOfRange,
92 UnclosedString,
93 InvalidSuffix,
94 InvalidBlockAttr,
95}
96
97#[derive(Debug, Clone, PartialEq, Eq, Hash)]
98pub struct ParseError(pub String);
99
100impl fmt::Display for SyntaxErrorKind {
101 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
102 use self::SyntaxErrorKind::*;
103 match self {
104 UnescapedCodepoint => write!(f, "This codepoint should always be escaped"),
105 EmptyAsciiEscape => write!(f, "Empty escape sequence"),
106 InvalidAsciiEscape => write!(f, "Invalid escape sequence"),
107 EmptyChar => write!(f, "Empty char literal"),
108 UnclosedChar => write!(f, "Unclosed char literal"),
109 OverlongChar => write!(f, "Char literal should be one character long"),
110 EmptyByte => write!(f, "Empty byte literal"),
111 UnclosedByte => write!(f, "Unclosed byte literal"),
112 OverlongByte => write!(f, "Byte literal should be one character long"),
113 ByteOutOfRange => write!(f, "Byte should be a valid ASCII character"),
114 UnescapedByte => write!(f, "This byte should always be escaped"),
115 EmptyByteEscape => write!(f, "Empty escape sequence"),
116 InvalidByteEscape => write!(f, "Invalid escape sequence"),
117 TooShortByteCodeEscape => write!(f, "Escape sequence should have two digits"),
118 MalformedByteCodeEscape => write!(f, "Escape sequence should be a hexadecimal number"),
119 UnicodeEscapeForbidden => {
120 write!(f, "Unicode escapes are not allowed in byte literals or byte strings")
121 }
122 TooShortAsciiCodeEscape => write!(f, "Escape sequence should have two digits"),
123 AsciiCodeEscapeOutOfRange => {
124 write!(f, "Escape sequence should be between \\x00 and \\x7F")
125 }
126 MalformedAsciiCodeEscape => write!(f, "Escape sequence should be a hexadecimal number"),
127 UnclosedUnicodeEscape => write!(f, "Missing `}}`"),
128 MalformedUnicodeEscape => write!(f, "Malformed unicode escape sequence"),
129 EmptyUnicodeEcape => write!(f, "Empty unicode escape sequence"),
130 OverlongUnicodeEscape => {
131 write!(f, "Unicode escape sequence should have at most 6 digits")
132 }
133 UnicodeEscapeOutOfRange => write!(f, "Unicode escape code should be at most 0x10FFFF"),
134 UnclosedString => write!(f, "Unclosed string literal"),
135 InvalidSuffix => write!(f, "Invalid literal suffix"),
136 InvalidBlockAttr => {
137 write!(f, "A block in this position cannot accept inner attributes")
138 }
139 ParseError(msg) => write!(f, "{}", msg.0),
140 }
141 }
142}
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 @@
1use std::{fmt, ops};
2
3use crate::{SyntaxNode, TextRange, TextUnit};
4
5#[derive(Clone)]
6pub struct SyntaxText<'a> {
7 node: &'a SyntaxNode,
8 range: TextRange,
9}
10
11impl<'a> SyntaxText<'a> {
12 pub(crate) fn new(node: &'a SyntaxNode) -> SyntaxText<'a> {
13 SyntaxText { node, range: node.range() }
14 }
15
16 pub fn chunks(&self) -> impl Iterator<Item = &'a str> {
17 let range = self.range;
18 self.node.descendants().filter_map(move |node| {
19 let text = node.leaf_text()?;
20 let range = range.intersection(&node.range())?;
21 let range = range - node.range().start();
22 Some(&text[range])
23 })
24 }
25
26 pub fn push_to(&self, buf: &mut String) {
27 self.chunks().for_each(|it| buf.push_str(it));
28 }
29
30 pub fn to_string(&self) -> String {
31 self.chunks().collect()
32 }
33
34 pub fn contains(&self, c: char) -> bool {
35 self.chunks().any(|it| it.contains(c))
36 }
37
38 pub fn find(&self, c: char) -> Option<TextUnit> {
39 let mut acc: TextUnit = 0.into();
40 for chunk in self.chunks() {
41 if let Some(pos) = chunk.find(c) {
42 let pos: TextUnit = (pos as u32).into();
43 return Some(acc + pos);
44 }
45 acc += TextUnit::of_str(chunk);
46 }
47 None
48 }
49
50 pub fn len(&self) -> TextUnit {
51 self.range.len()
52 }
53
54 pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> {
55 let range = range.restrict(self.range).unwrap_or_else(|| {
56 panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range)
57 });
58 SyntaxText { node: self.node, range }
59 }
60
61 pub fn char_at(&self, offset: impl Into<TextUnit>) -> Option<char> {
62 let mut start: TextUnit = 0.into();
63 let offset = offset.into();
64 for chunk in self.chunks() {
65 let end = start + TextUnit::of_str(chunk);
66 if start <= offset && offset < end {
67 let off: usize = u32::from(offset - start) as usize;
68 return Some(chunk[off..].chars().next().unwrap());
69 }
70 start = end;
71 }
72 None
73 }
74}
75
76impl<'a> fmt::Debug for SyntaxText<'a> {
77 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
78 fmt::Debug::fmt(&self.to_string(), f)
79 }
80}
81
82impl<'a> fmt::Display for SyntaxText<'a> {
83 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
84 fmt::Display::fmt(&self.to_string(), f)
85 }
86}
87
88pub trait SyntaxTextSlice: fmt::Debug {
89 fn restrict(&self, range: TextRange) -> Option<TextRange>;
90}
91
92impl SyntaxTextSlice for TextRange {
93 fn restrict(&self, range: TextRange) -> Option<TextRange> {
94 self.intersection(&range)
95 }
96}
97
98impl SyntaxTextSlice for ops::RangeTo<TextUnit> {
99 fn restrict(&self, range: TextRange) -> Option<TextRange> {
100 if !range.contains_inclusive(self.end) {
101 return None;
102 }
103 Some(TextRange::from_to(range.start(), self.end))
104 }
105}
106
107impl SyntaxTextSlice for ops::RangeFrom<TextUnit> {
108 fn restrict(&self, range: TextRange) -> Option<TextRange> {
109 if !range.contains_inclusive(self.start) {
110 return None;
111 }
112 Some(TextRange::from_to(self.start, range.end()))
113 }
114}
115
116impl SyntaxTextSlice for ops::Range<TextUnit> {
117 fn restrict(&self, range: TextRange) -> Option<TextRange> {
118 TextRange::from_to(self.start, self.end).restrict(range)
119 }
120}
121
122impl From<SyntaxText<'_>> for String {
123 fn from(text: SyntaxText) -> String {
124 text.to_string()
125 }
126}
127
128impl PartialEq<str> for SyntaxText<'_> {
129 fn eq(&self, mut rhs: &str) -> bool {
130 for chunk in self.chunks() {
131 if !rhs.starts_with(chunk) {
132 return false;
133 }
134 rhs = &rhs[chunk.len()..];
135 }
136 rhs.is_empty()
137 }
138}
139
140impl PartialEq<&'_ str> for SyntaxText<'_> {
141 fn eq(&self, rhs: &&str) -> bool {
142 self == *rhs
143 }
144}