aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src')
-rw-r--r--crates/ra_syntax/src/parser_impl/event.rs11
-rw-r--r--crates/ra_syntax/src/parser_impl/mod.rs12
-rw-r--r--crates/ra_syntax/src/reparsing.rs12
-rw-r--r--crates/ra_syntax/src/string_lexing/mod.rs10
-rw-r--r--crates/ra_syntax/src/utils.rs8
-rw-r--r--crates/ra_syntax/src/validation.rs99
-rw-r--r--crates/ra_syntax/src/yellow/builder.rs11
-rw-r--r--crates/ra_syntax/src/yellow/mod.rs10
-rw-r--r--crates/ra_syntax/src/yellow/syntax_error.rs42
9 files changed, 153 insertions, 62 deletions
diff --git a/crates/ra_syntax/src/parser_impl/event.rs b/crates/ra_syntax/src/parser_impl/event.rs
index 79fa21389..ced09bcff 100644
--- a/crates/ra_syntax/src/parser_impl/event.rs
+++ b/crates/ra_syntax/src/parser_impl/event.rs
@@ -13,6 +13,10 @@ use crate::{
13 SmolStr, 13 SmolStr,
14 SyntaxKind::{self, *}, 14 SyntaxKind::{self, *},
15 TextRange, TextUnit, 15 TextRange, TextUnit,
16 yellow::syntax_error::{
17 ParseError,
18 SyntaxErrorKind,
19 },
16}; 20};
17use std::mem; 21use std::mem;
18 22
@@ -75,7 +79,7 @@ pub(crate) enum Event {
75 }, 79 },
76 80
77 Error { 81 Error {
78 msg: String, 82 msg: ParseError,
79 }, 83 },
80} 84}
81 85
@@ -157,7 +161,10 @@ impl<'a, S: Sink> EventProcessor<'a, S> {
157 .sum::<TextUnit>(); 161 .sum::<TextUnit>();
158 self.leaf(kind, len, n_raw_tokens); 162 self.leaf(kind, len, n_raw_tokens);
159 } 163 }
160 Event::Error { msg } => self.sink.error(msg, self.text_pos), 164 Event::Error { msg } => self.sink.error(
165 SyntaxErrorKind::ParseError(msg),
166 TextRange::offset_len(self.text_pos, 1.into()),
167 ),
161 } 168 }
162 } 169 }
163 self.sink 170 self.sink
diff --git a/crates/ra_syntax/src/parser_impl/mod.rs b/crates/ra_syntax/src/parser_impl/mod.rs
index 2b026d61e..ade25770b 100644
--- a/crates/ra_syntax/src/parser_impl/mod.rs
+++ b/crates/ra_syntax/src/parser_impl/mod.rs
@@ -10,7 +10,11 @@ use crate::{
10 event::{Event, EventProcessor}, 10 event::{Event, EventProcessor},
11 input::{InputPosition, ParserInput}, 11 input::{InputPosition, ParserInput},
12 }, 12 },
13 SmolStr, TextUnit, 13 SmolStr, TextRange,
14 yellow::syntax_error::{
15 ParseError,
16 SyntaxErrorKind,
17 },
14}; 18};
15 19
16use crate::SyntaxKind::{self, EOF, TOMBSTONE}; 20use crate::SyntaxKind::{self, EOF, TOMBSTONE};
@@ -21,7 +25,7 @@ pub(crate) trait Sink {
21 fn leaf(&mut self, kind: SyntaxKind, text: SmolStr); 25 fn leaf(&mut self, kind: SyntaxKind, text: SmolStr);
22 fn start_internal(&mut self, kind: SyntaxKind); 26 fn start_internal(&mut self, kind: SyntaxKind);
23 fn finish_internal(&mut self); 27 fn finish_internal(&mut self);
24 fn error(&mut self, message: String, offset: TextUnit); 28 fn error(&mut self, kind: SyntaxErrorKind, offset: TextRange);
25 fn finish(self) -> Self::Tree; 29 fn finish(self) -> Self::Tree;
26} 30}
27 31
@@ -144,7 +148,9 @@ impl<'t> ParserImpl<'t> {
144 } 148 }
145 149
146 pub(super) fn error(&mut self, msg: String) { 150 pub(super) fn error(&mut self, msg: String) {
147 self.event(Event::Error { msg }) 151 self.event(Event::Error {
152 msg: ParseError(msg),
153 })
148 } 154 }
149 155
150 pub(super) fn complete(&mut self, pos: u32, kind: SyntaxKind) { 156 pub(super) fn complete(&mut self, pos: u32, kind: SyntaxKind) {
diff --git a/crates/ra_syntax/src/reparsing.rs b/crates/ra_syntax/src/reparsing.rs
index b3b51b3e4..9f5baf1ef 100644
--- a/crates/ra_syntax/src/reparsing.rs
+++ b/crates/ra_syntax/src/reparsing.rs
@@ -165,19 +165,19 @@ fn merge_errors(
165) -> Vec<SyntaxError> { 165) -> Vec<SyntaxError> {
166 let mut res = Vec::new(); 166 let mut res = Vec::new();
167 for e in old_errors { 167 for e in old_errors {
168 if e.offset <= old_node.range().start() { 168 if e.range.start() <= old_node.range().start() {
169 res.push(e) 169 res.push(e)
170 } else if e.offset >= old_node.range().end() { 170 } else if e.range.start() >= old_node.range().end() {
171 res.push(SyntaxError { 171 res.push(SyntaxError {
172 msg: e.msg, 172 kind: e.kind,
173 offset: e.offset + TextUnit::of_str(&edit.insert) - edit.delete.len(), 173 range: e.range + TextUnit::of_str(&edit.insert) - edit.delete.len(),
174 }) 174 })
175 } 175 }
176 } 176 }
177 for e in new_errors { 177 for e in new_errors {
178 res.push(SyntaxError { 178 res.push(SyntaxError {
179 msg: e.msg, 179 kind: e.kind,
180 offset: e.offset + old_node.range().start(), 180 range: e.range + old_node.range().start(),
181 }) 181 })
182 } 182 }
183 res 183 res
diff --git a/crates/ra_syntax/src/string_lexing/mod.rs b/crates/ra_syntax/src/string_lexing/mod.rs
index 6b52c62c3..f0812ff28 100644
--- a/crates/ra_syntax/src/string_lexing/mod.rs
+++ b/crates/ra_syntax/src/string_lexing/mod.rs
@@ -100,10 +100,6 @@ impl<'a> Parser<'a> {
100 // Char parsing methods 100 // Char parsing methods
101 101
102 fn parse_unicode_escape(&mut self, start: TextUnit) -> CharComponent { 102 fn parse_unicode_escape(&mut self, start: TextUnit) -> CharComponent {
103 // Note: validation of UnicodeEscape will be done elsewhere:
104 // * Only hex digits or underscores allowed
105 // * Max 6 chars
106 // * Within allowed range (must be at most 10FFFF)
107 match self.peek() { 103 match self.peek() {
108 Some('{') => { 104 Some('{') => {
109 self.advance(); 105 self.advance();
@@ -127,9 +123,6 @@ impl<'a> Parser<'a> {
127 } 123 }
128 124
129 fn parse_ascii_code_escape(&mut self, start: TextUnit) -> CharComponent { 125 fn parse_ascii_code_escape(&mut self, start: TextUnit) -> CharComponent {
130 // Note: validation of AsciiCodeEscape will be done elsewhere:
131 // * First digit is octal
132 // * Second digit is hex
133 let code_start = self.get_pos(); 126 let code_start = self.get_pos();
134 while let Some(next) = self.peek() { 127 while let Some(next) = self.peek() {
135 if next == '\'' || (self.get_pos() - code_start == 2.into()) { 128 if next == '\'' || (self.get_pos() - code_start == 2.into()) {
@@ -144,9 +137,6 @@ impl<'a> Parser<'a> {
144 } 137 }
145 138
146 fn parse_escape(&mut self, start: TextUnit) -> CharComponent { 139 fn parse_escape(&mut self, start: TextUnit) -> CharComponent {
147 // Note: validation of AsciiEscape will be done elsewhere:
148 // * The escape sequence is non-empty
149 // * The escape sequence is valid
150 if self.peek().is_none() { 140 if self.peek().is_none() {
151 return CharComponent::new(TextRange::from_to(start, start), AsciiEscape); 141 return CharComponent::new(TextRange::from_to(start, start), AsciiEscape);
152 } 142 }
diff --git a/crates/ra_syntax/src/utils.rs b/crates/ra_syntax/src/utils.rs
index 00f00139a..f55568d94 100644
--- a/crates/ra_syntax/src/utils.rs
+++ b/crates/ra_syntax/src/utils.rs
@@ -4,7 +4,7 @@ use std::fmt::Write;
4/// Parse a file and create a string representation of the resulting parse tree. 4/// Parse a file and create a string representation of the resulting parse tree.
5pub fn dump_tree(syntax: SyntaxNodeRef) -> String { 5pub fn dump_tree(syntax: SyntaxNodeRef) -> String {
6 let mut errors: Vec<_> = syntax.root_data().to_vec(); 6 let mut errors: Vec<_> = syntax.root_data().to_vec();
7 errors.sort_by_key(|e| e.offset); 7 errors.sort_by_key(|e| e.range.start());
8 let mut err_pos = 0; 8 let mut err_pos = 0;
9 let mut level = 0; 9 let mut level = 0;
10 let mut buf = String::new(); 10 let mut buf = String::new();
@@ -23,9 +23,9 @@ pub fn dump_tree(syntax: SyntaxNodeRef) -> String {
23 writeln!(buf, "{:?}", node).unwrap(); 23 writeln!(buf, "{:?}", node).unwrap();
24 if node.first_child().is_none() { 24 if node.first_child().is_none() {
25 let off = node.range().end(); 25 let off = node.range().end();
26 while err_pos < errors.len() && errors[err_pos].offset <= off { 26 while err_pos < errors.len() && errors[err_pos].range.start() <= off {
27 indent!(); 27 indent!();
28 writeln!(buf, "err: `{}`", errors[err_pos].msg).unwrap(); 28 writeln!(buf, "err: `{}`", errors[err_pos].kind).unwrap();
29 err_pos += 1; 29 err_pos += 1;
30 } 30 }
31 } 31 }
@@ -37,7 +37,7 @@ pub fn dump_tree(syntax: SyntaxNodeRef) -> String {
37 37
38 assert_eq!(level, 0); 38 assert_eq!(level, 0);
39 for err in errors[err_pos..].iter() { 39 for err in errors[err_pos..].iter() {
40 writeln!(buf, "err: `{}`", err.msg).unwrap(); 40 writeln!(buf, "err: `{}`", err.kind).unwrap();
41 } 41 }
42 42
43 buf 43 buf
diff --git a/crates/ra_syntax/src/validation.rs b/crates/ra_syntax/src/validation.rs
index 03d98eff4..06e6e7505 100644
--- a/crates/ra_syntax/src/validation.rs
+++ b/crates/ra_syntax/src/validation.rs
@@ -1,40 +1,93 @@
1use crate::{ 1use crate::{
2 algo::visit::{visitor_ctx, VisitorCtx},
2 ast::{self, AstNode}, 3 ast::{self, AstNode},
3 File, 4 File,
4 string_lexing, 5 string_lexing::{self, CharComponentKind},
5 yellow::{ 6 yellow::{
6 SyntaxError, 7 SyntaxError,
8 SyntaxErrorKind::*,
7 }, 9 },
8}; 10};
9 11
10pub(crate) fn validate(file: &File) -> Vec<SyntaxError> { 12pub(crate) fn validate(file: &File) -> Vec<SyntaxError> {
11 let mut errors = Vec::new(); 13 let mut errors = Vec::new();
12 for d in file.root.borrowed().descendants() { 14 for node in file.root.borrowed().descendants() {
13 if let Some(c) = ast::Char::cast(d) { 15 let _ = visitor_ctx(&mut errors)
14 let components = &mut string_lexing::parse_char_literal(c.text()); 16 .visit::<ast::Char, _>(validate_char)
15 let len = components.count(); 17 .accept(node);
18 }
19 errors
20}
16 21
17 if !components.has_closing_quote { 22fn validate_char(node: ast::Char, errors: &mut Vec<SyntaxError>) {
18 errors.push(SyntaxError { 23 let mut components = string_lexing::parse_char_literal(node.text());
19 msg: "Unclosed char literal".to_string(), 24 let mut len = 0;
20 offset: d.range().start(), 25 for component in &mut components {
21 }); 26 len += 1;
22 }
23 27
24 if len == 0 { 28 // Validate escapes
25 errors.push(SyntaxError { 29 let text = &node.text()[component.range];
26 msg: "Empty char literal".to_string(), 30 let range = component.range + node.syntax().range().start();
27 offset: d.range().start(), 31 use self::CharComponentKind::*;
28 }); 32 match component.kind {
33 AsciiEscape => {
34 if text.len() == 1 {
35 // Escape sequence consists only of leading `\`
36 errors.push(SyntaxError {
37 kind: EmptyAsciiEscape,
38 range: range,
39 });
40 } else {
41 let escape_code = text.chars().skip(1).next().unwrap();
42 if !is_ascii_escape(escape_code) {
43 errors.push(SyntaxError {
44 kind: InvalidAsciiEscape,
45 range: range,
46 });
47 }
48 }
29 } 49 }
30 50 AsciiCodeEscape => {
31 if len > 1 { 51 // TODO:
32 errors.push(SyntaxError { 52 // * First digit is octal
33 msg: "Character literal should be only one character long".to_string(), 53 // * Second digit is hex
34 offset: d.range().start(), 54 }
35 }); 55 UnicodeEscape => {
56 // TODO:
57 // * Only hex digits or underscores allowed
58 // * Max 6 chars
59 // * Within allowed range (must be at most 10FFFF)
36 } 60 }
61 // Code points are always valid
62 CodePoint => (),
37 } 63 }
38 } 64 }
39 errors 65
66 if !components.has_closing_quote {
67 errors.push(SyntaxError {
68 kind: UnclosedChar,
69 range: node.syntax().range(),
70 });
71 }
72
73 if len == 0 {
74 errors.push(SyntaxError {
75 kind: EmptyChar,
76 range: node.syntax().range(),
77 });
78 }
79
80 if len > 1 {
81 errors.push(SyntaxError {
82 kind: LongChar,
83 range: node.syntax().range(),
84 });
85 }
86}
87
88fn is_ascii_escape(code: char) -> bool {
89 match code {
90 '\'' | '"' | 'n' | 'r' | 't' | '0' => true,
91 _ => false,
92 }
40} 93}
diff --git a/crates/ra_syntax/src/yellow/builder.rs b/crates/ra_syntax/src/yellow/builder.rs
index d64053409..dbe2df125 100644
--- a/crates/ra_syntax/src/yellow/builder.rs
+++ b/crates/ra_syntax/src/yellow/builder.rs
@@ -1,7 +1,7 @@
1use crate::{ 1use crate::{
2 parser_impl::Sink, 2 parser_impl::Sink,
3 yellow::{GreenNode, RaTypes, SyntaxError}, 3 yellow::{GreenNode, RaTypes, SyntaxError, SyntaxErrorKind},
4 SmolStr, SyntaxKind, TextUnit, 4 SmolStr, SyntaxKind, TextRange,
5}; 5};
6use rowan::GreenNodeBuilder; 6use rowan::GreenNodeBuilder;
7 7
@@ -34,11 +34,8 @@ impl Sink for GreenBuilder {
34 self.inner.finish_internal(); 34 self.inner.finish_internal();
35 } 35 }
36 36
37 fn error(&mut self, message: String, offset: TextUnit) { 37 fn error(&mut self, kind: SyntaxErrorKind, range: TextRange) {
38 let error = SyntaxError { 38 let error = SyntaxError { kind, range };
39 msg: message,
40 offset,
41 };
42 self.errors.push(error) 39 self.errors.push(error)
43 } 40 }
44 41
diff --git a/crates/ra_syntax/src/yellow/mod.rs b/crates/ra_syntax/src/yellow/mod.rs
index 650917214..fd2b5bd33 100644
--- a/crates/ra_syntax/src/yellow/mod.rs
+++ b/crates/ra_syntax/src/yellow/mod.rs
@@ -1,8 +1,9 @@
1mod builder; 1mod builder;
2pub mod syntax_error;
2mod syntax_text; 3mod syntax_text;
3 4
4use self::syntax_text::SyntaxText; 5use self::syntax_text::SyntaxText;
5use crate::{SmolStr, SyntaxKind, TextRange, TextUnit}; 6use crate::{SmolStr, SyntaxKind, TextRange};
6use rowan::Types; 7use rowan::Types;
7use std::{ 8use std::{
8 fmt, 9 fmt,
@@ -10,6 +11,7 @@ use std::{
10}; 11};
11 12
12pub(crate) use self::builder::GreenBuilder; 13pub(crate) use self::builder::GreenBuilder;
14pub use self::syntax_error::{SyntaxError, SyntaxErrorKind};
13pub use rowan::{TreeRoot, WalkEvent}; 15pub use rowan::{TreeRoot, WalkEvent};
14 16
15#[derive(Debug, Clone, Copy)] 17#[derive(Debug, Clone, Copy)]
@@ -24,12 +26,6 @@ pub type RefRoot<'a> = ::rowan::RefRoot<'a, RaTypes>;
24 26
25pub type GreenNode = ::rowan::GreenNode<RaTypes>; 27pub type GreenNode = ::rowan::GreenNode<RaTypes>;
26 28
27#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
28pub struct SyntaxError {
29 pub msg: String,
30 pub offset: TextUnit,
31}
32
33#[derive(Clone, Copy)] 29#[derive(Clone, Copy)]
34pub struct SyntaxNode<R: TreeRoot<RaTypes> = OwnedRoot>(::rowan::SyntaxNode<RaTypes, R>); 30pub struct SyntaxNode<R: TreeRoot<RaTypes> = OwnedRoot>(::rowan::SyntaxNode<RaTypes, R>);
35pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>; 31pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>;
diff --git a/crates/ra_syntax/src/yellow/syntax_error.rs b/crates/ra_syntax/src/yellow/syntax_error.rs
new file mode 100644
index 000000000..e8c818dc6
--- /dev/null
+++ b/crates/ra_syntax/src/yellow/syntax_error.rs
@@ -0,0 +1,42 @@
1use std::fmt;
2
3use crate::TextRange;
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
6pub struct SyntaxError {
7 pub kind: SyntaxErrorKind,
8 pub range: TextRange,
9}
10
11impl SyntaxError {
12 pub fn new(kind: SyntaxErrorKind, range: TextRange) -> SyntaxError {
13 SyntaxError { kind, range }
14 }
15}
16
17#[derive(Debug, Clone, PartialEq, Eq, Hash)]
18pub enum SyntaxErrorKind {
19 ParseError(ParseError),
20 EmptyChar,
21 UnclosedChar,
22 LongChar,
23 EmptyAsciiEscape,
24 InvalidAsciiEscape,
25}
26
27#[derive(Debug, Clone, PartialEq, Eq, Hash)]
28pub struct ParseError(pub String);
29
30impl fmt::Display for SyntaxErrorKind {
31 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
32 use self::SyntaxErrorKind::*;
33 match self {
34 EmptyAsciiEscape => write!(f, "Empty escape sequence"),
35 InvalidAsciiEscape => write!(f, "Invalid escape sequence"),
36 EmptyChar => write!(f, "Empty char literal"),
37 UnclosedChar => write!(f, "Unclosed char literal"),
38 LongChar => write!(f, "Char literal should be one character long"),
39 ParseError(msg) => write!(f, "{}", msg.0),
40 }
41 }
42}