aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_syntax/src/yellow
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_syntax/src/yellow')
-rw-r--r--crates/ra_syntax/src/yellow/builder.rs64
-rw-r--r--crates/ra_syntax/src/yellow/green.rs90
-rw-r--r--crates/ra_syntax/src/yellow/mod.rs100
-rw-r--r--crates/ra_syntax/src/yellow/red.rs113
-rw-r--r--crates/ra_syntax/src/yellow/syntax.rs215
-rw-r--r--crates/ra_syntax/src/yellow/syntax_text.rs122
6 files changed, 704 insertions, 0 deletions
diff --git a/crates/ra_syntax/src/yellow/builder.rs b/crates/ra_syntax/src/yellow/builder.rs
new file mode 100644
index 000000000..e4ab37899
--- /dev/null
+++ b/crates/ra_syntax/src/yellow/builder.rs
@@ -0,0 +1,64 @@
1use {
2 parser_impl::Sink,
3 yellow::{GreenNode, SyntaxError},
4 SyntaxKind, TextRange, TextUnit,
5};
6
7pub(crate) struct GreenBuilder<'a> {
8 text: &'a str,
9 parents: Vec<(SyntaxKind, usize)>,
10 children: Vec<GreenNode>,
11 pos: TextUnit,
12 errors: Vec<SyntaxError>,
13}
14
15impl<'a> Sink<'a> for GreenBuilder<'a> {
16 type Tree = (GreenNode, Vec<SyntaxError>);
17
18 fn new(text: &'a str) -> Self {
19 GreenBuilder {
20 text,
21 parents: Vec::new(),
22 children: Vec::new(),
23 pos: 0.into(),
24 errors: Vec::new(),
25 }
26 }
27
28 fn leaf(&mut self, kind: SyntaxKind, len: TextUnit) {
29 let range = TextRange::offset_len(self.pos, len);
30 self.pos += len;
31 let text = &self.text[range];
32 self.children.push(
33 GreenNode::new_leaf(kind, text)
34 );
35 }
36
37 fn start_internal(&mut self, kind: SyntaxKind) {
38 let len = self.children.len();
39 self.parents.push((kind, len));
40 }
41
42 fn finish_internal(&mut self) {
43 let (kind, first_child) = self.parents.pop().unwrap();
44 let children: Vec<_> = self.children
45 .drain(first_child..)
46 .collect();
47 self.children.push(
48 GreenNode::new_branch(kind, children.into_boxed_slice())
49 );
50 }
51
52 fn error(&mut self, message: String) {
53 self.errors.push(SyntaxError {
54 msg: message,
55 offset: self.pos,
56 })
57 }
58
59 fn finish(mut self) -> (GreenNode, Vec<SyntaxError>) {
60 assert_eq!(self.children.len(), 1);
61 let root = self.children.pop().unwrap();
62 (root, self.errors)
63 }
64}
diff --git a/crates/ra_syntax/src/yellow/green.rs b/crates/ra_syntax/src/yellow/green.rs
new file mode 100644
index 000000000..8fb691643
--- /dev/null
+++ b/crates/ra_syntax/src/yellow/green.rs
@@ -0,0 +1,90 @@
1use std::sync::Arc;
2
3use smol_str::SmolStr;
4
5use {SyntaxKind, TextUnit};
6
7#[derive(Clone, Debug)]
8pub(crate) enum GreenNode {
9 Leaf {
10 kind: SyntaxKind,
11 text: SmolStr,
12 },
13 Branch(Arc<GreenBranch>),
14}
15
16impl GreenNode {
17 pub(crate) fn new_leaf(kind: SyntaxKind, text: &str) -> GreenNode {
18 GreenNode::Leaf { kind, text: SmolStr::new(text) }
19 }
20
21 pub(crate) fn new_branch(kind: SyntaxKind, children: Box<[GreenNode]>) -> GreenNode {
22 GreenNode::Branch(Arc::new(GreenBranch::new(kind, children)))
23 }
24
25 pub fn kind(&self) -> SyntaxKind {
26 match self {
27 GreenNode::Leaf { kind, .. } => *kind,
28 GreenNode::Branch(b) => b.kind(),
29 }
30 }
31
32 pub fn text_len(&self) -> TextUnit {
33 match self {
34 GreenNode::Leaf { text, .. } => TextUnit::from(text.len() as u32),
35 GreenNode::Branch(b) => b.text_len(),
36 }
37 }
38
39 pub fn children(&self) -> &[GreenNode] {
40 match self {
41 GreenNode::Leaf { .. } => &[],
42 GreenNode::Branch(b) => b.children(),
43 }
44 }
45
46 pub fn leaf_text_ref(&self) -> Option<&SmolStr> {
47 match self {
48 GreenNode::Leaf { text, .. } => Some(text),
49 GreenNode::Branch(_) => None,
50 }
51 }
52}
53
54#[derive(Clone, Debug)]
55pub(crate) struct GreenBranch {
56 text_len: TextUnit,
57 kind: SyntaxKind,
58 children: Box<[GreenNode]>,
59}
60
61impl GreenBranch {
62 fn new(kind: SyntaxKind, children: Box<[GreenNode]>) -> GreenBranch {
63 let text_len = children.iter().map(|x| x.text_len()).sum::<TextUnit>();
64 GreenBranch {
65 text_len,
66 kind,
67 children,
68 }
69 }
70
71 pub fn kind(&self) -> SyntaxKind {
72 self.kind
73 }
74
75 pub fn text_len(&self) -> TextUnit {
76 self.text_len
77 }
78
79 pub fn children(&self) -> &[GreenNode] {
80 &*self.children
81 }
82}
83
84#[test]
85fn test_sizes() {
86 use std::mem::size_of;
87 println!("GreenBranch = {}", size_of::<GreenBranch>());
88 println!("GreenNode = {}", size_of::<GreenNode>());
89 println!("SmolStr = {}", size_of::<SmolStr>());
90}
diff --git a/crates/ra_syntax/src/yellow/mod.rs b/crates/ra_syntax/src/yellow/mod.rs
new file mode 100644
index 000000000..0596e702f
--- /dev/null
+++ b/crates/ra_syntax/src/yellow/mod.rs
@@ -0,0 +1,100 @@
1mod builder;
2mod green;
3mod red;
4mod syntax;
5mod syntax_text;
6
7use std::{
8 sync::Arc,
9 ptr,
10};
11pub use self::syntax::{SyntaxNode, SyntaxNodeRef, SyntaxError, SyntaxNodeChildren};
12pub(crate) use self::{
13 builder::GreenBuilder,
14 green::GreenNode,
15 red::RedNode,
16 syntax_text::SyntaxText,
17};
18
19#[derive(Debug)]
20pub struct SyntaxRoot {
21 red: RedNode,
22 pub(crate) errors: Vec<SyntaxError>,
23}
24
25pub trait TreeRoot: Clone + Send + Sync {
26 fn borrowed(&self) -> RefRoot;
27 fn owned(&self) -> OwnedRoot;
28
29 #[doc(hidden)]
30 fn syntax_root(&self) -> &SyntaxRoot;
31}
32#[derive(Clone, Debug)]
33pub struct OwnedRoot(Arc<SyntaxRoot>);
34#[derive(Clone, Copy, Debug)]
35pub struct RefRoot<'a>(&'a OwnedRoot); // TODO: shared_from_this instead of double indirection
36
37impl<'a> RefRoot<'a> {
38 fn syntax_root(&self) -> &'a SyntaxRoot {
39 self.0.syntax_root()
40 }
41}
42
43impl TreeRoot for OwnedRoot {
44 fn borrowed(&self) -> RefRoot {
45 RefRoot(&self)
46 }
47 fn owned(&self) -> OwnedRoot {
48 self.clone()
49 }
50
51 fn syntax_root(&self) -> &SyntaxRoot {
52 &*self.0
53 }
54}
55
56impl<'a> TreeRoot for RefRoot<'a> {
57 fn borrowed(&self) -> RefRoot {
58 *self
59 }
60 fn owned(&self) -> OwnedRoot {
61 self.0.clone()
62 }
63 fn syntax_root(&self) -> &SyntaxRoot {
64 self.0.syntax_root()
65 }
66}
67
68impl SyntaxRoot {
69 pub(crate) fn new(green: GreenNode, errors: Vec<SyntaxError>) -> SyntaxRoot {
70 SyntaxRoot {
71 red: RedNode::new_root(green),
72 errors,
73 }
74 }
75}
76
77#[derive(Clone, Copy, PartialEq, Eq, Debug, Hash)]
78pub(crate) struct RedPtr(ptr::NonNull<RedNode>);
79
80unsafe impl Send for RedPtr {}
81
82unsafe impl Sync for RedPtr {}
83
84impl RedPtr {
85 fn new(red: &RedNode) -> RedPtr {
86 RedPtr(red.into())
87 }
88
89 unsafe fn get<'a>(self, _root: &'a SyntaxRoot) -> &'a RedNode {
90 &*self.0.as_ptr()
91 }
92}
93
94#[test]
95fn assert_send_sync() {
96 fn f<T: Send + Sync>() {}
97 f::<GreenNode>();
98 f::<RedNode>();
99 f::<SyntaxNode>();
100}
diff --git a/crates/ra_syntax/src/yellow/red.rs b/crates/ra_syntax/src/yellow/red.rs
new file mode 100644
index 000000000..84cfe4fba
--- /dev/null
+++ b/crates/ra_syntax/src/yellow/red.rs
@@ -0,0 +1,113 @@
1use parking_lot::RwLock;
2use {yellow::{GreenNode, RedPtr}, TextUnit};
3
4#[derive(Debug)]
5pub(crate) struct RedNode {
6 green: GreenNode,
7 parent: Option<ParentData>,
8 children: RwLock<Box<[RedChild]>>,
9}
10
11#[derive(Debug)]
12enum RedChild {
13 Zigot(TextUnit),
14 Child(RedNode)
15}
16
17impl RedChild {
18 fn set(&mut self, node: RedNode) -> &RedNode {
19 match self {
20 RedChild::Child(node) => return node,
21 RedChild::Zigot(_) => {
22 *self = RedChild::Child(node);
23 match self {
24 RedChild::Child(node) => return node,
25 RedChild::Zigot(_) => unreachable!()
26 }
27 }
28 }
29 }
30}
31
32#[derive(Debug)]
33struct ParentData {
34 parent: RedPtr,
35 start_offset: TextUnit,
36 index_in_parent: usize,
37}
38
39impl RedNode {
40 pub fn new_root(green: GreenNode) -> RedNode {
41 RedNode::new(green, None)
42 }
43
44 fn new_child(
45 green: GreenNode,
46 parent: RedPtr,
47 start_offset: TextUnit,
48 index_in_parent: usize,
49 ) -> RedNode {
50 let parent_data = ParentData {
51 parent,
52 start_offset,
53 index_in_parent,
54 };
55 RedNode::new(green, Some(parent_data))
56 }
57
58 fn new(green: GreenNode, parent: Option<ParentData>) -> RedNode {
59 let mut start_offset = parent.as_ref().map(|it| it.start_offset).unwrap_or(0.into());
60 let children = green.children()
61 .iter()
62 .map(|child| {
63 let off = start_offset;
64 start_offset += child.text_len();
65 RedChild::Zigot(off)
66 })
67 .collect::<Vec<_>>()
68 .into_boxed_slice();
69 RedNode {
70 green,
71 parent,
72 children: RwLock::new(children),
73 }
74 }
75
76 pub(crate) fn green(&self) -> &GreenNode {
77 &self.green
78 }
79
80 pub(crate) fn start_offset(&self) -> TextUnit {
81 match &self.parent {
82 None => 0.into(),
83 Some(p) => p.start_offset,
84 }
85 }
86
87 pub(crate) fn n_children(&self) -> usize {
88 self.green.children().len()
89 }
90
91 pub(crate) fn get_child(&self, idx: usize) -> Option<RedPtr> {
92 if idx >= self.n_children() {
93 return None;
94 }
95 let start_offset = match &self.children.read()[idx] {
96 RedChild::Child(child) => return Some(RedPtr::new(child)),
97 RedChild::Zigot(start_offset) => *start_offset,
98 };
99 let green_children = self.green.children();
100 let child =
101 RedNode::new_child(green_children[idx].clone(), RedPtr::new(self), start_offset, idx);
102 let mut children = self.children.write();
103 let child = children[idx].set(child);
104 Some(RedPtr::new(child))
105 }
106
107 pub(crate) fn parent(&self) -> Option<RedPtr> {
108 Some(self.parent.as_ref()?.parent)
109 }
110 pub(crate) fn index_in_parent(&self) -> Option<usize> {
111 Some(self.parent.as_ref()?.index_in_parent)
112 }
113}
diff --git a/crates/ra_syntax/src/yellow/syntax.rs b/crates/ra_syntax/src/yellow/syntax.rs
new file mode 100644
index 000000000..1d99cab4a
--- /dev/null
+++ b/crates/ra_syntax/src/yellow/syntax.rs
@@ -0,0 +1,215 @@
1use std::{
2 fmt, sync::Arc,
3 hash::{Hasher, Hash},
4 ops::Range,
5};
6
7use smol_str::SmolStr;
8
9use {
10 yellow::{GreenNode, RedNode, TreeRoot, SyntaxRoot, RedPtr, RefRoot, OwnedRoot, SyntaxText},
11 SyntaxKind::{self, *},
12 TextRange, TextUnit,
13};
14
15
16#[derive(Clone, Copy)]
17pub struct SyntaxNode<R: TreeRoot = OwnedRoot> {
18 pub(crate) root: R,
19 // Guaranteed to not dangle, because `root` holds a
20 // strong reference to red's ancestor
21 red: RedPtr,
22}
23
24unsafe impl<R: TreeRoot> Send for SyntaxNode<R> {}
25unsafe impl<R: TreeRoot> Sync for SyntaxNode<R> {}
26
27impl<R1: TreeRoot, R2: TreeRoot> PartialEq<SyntaxNode<R1>> for SyntaxNode<R2> {
28 fn eq(&self, other: &SyntaxNode<R1>) -> bool {
29 self.red == other.red
30 }
31}
32
33impl<R: TreeRoot> Eq for SyntaxNode<R> {}
34impl<R: TreeRoot> Hash for SyntaxNode<R> {
35 fn hash<H: Hasher>(&self, state: &mut H) {
36 self.red.hash(state)
37 }
38}
39
40pub type SyntaxNodeRef<'a> = SyntaxNode<RefRoot<'a>>;
41
42#[test]
43fn syntax_node_ref_is_copy() {
44 fn assert_copy<T: Copy>(){}
45 assert_copy::<SyntaxNodeRef>()
46}
47
48#[derive(Debug, Clone, PartialEq, Eq, Hash, Ord, PartialOrd)]
49pub struct SyntaxError {
50 pub msg: String,
51 pub offset: TextUnit,
52}
53
54impl SyntaxNode<OwnedRoot> {
55 pub(crate) fn new_owned(root: SyntaxRoot) -> Self {
56 let root = OwnedRoot(Arc::new(root));
57 let red = RedPtr::new(&root.syntax_root().red);
58 SyntaxNode { root, red }
59 }
60}
61
62impl<'a> SyntaxNode<RefRoot<'a>> {
63 pub(crate) fn leaf_text_ref(self) -> Option<&'a SmolStr> {
64 let red = unsafe { self.red.get(self.root.syntax_root()) };
65 red.green().leaf_text_ref()
66 }
67}
68
69impl<R: TreeRoot> SyntaxNode<R> {
70 pub fn borrowed<'a>(&'a self) -> SyntaxNodeRef<'a> {
71 SyntaxNode {
72 root: self.root.borrowed(),
73 red: self.red,
74 }
75 }
76
77 pub fn owned(&self) -> SyntaxNode {
78 SyntaxNode {
79 root: self.root.owned(),
80 red: self.red,
81 }
82 }
83
84 pub fn kind(&self) -> SyntaxKind {
85 self.red().green().kind()
86 }
87
88 pub fn range(&self) -> TextRange {
89 let red = self.red();
90 TextRange::offset_len(red.start_offset(), red.green().text_len())
91 }
92
93 pub fn text(&self) -> SyntaxText {
94 SyntaxText::new(self.borrowed())
95 }
96
97 pub fn children(&self) -> SyntaxNodeChildren<R> {
98 SyntaxNodeChildren {
99 parent: self.clone(),
100 iter: (0..self.red().n_children())
101 }
102 }
103
104 pub fn parent(&self) -> Option<SyntaxNode<R>> {
105 let parent = self.red().parent()?;
106 Some(SyntaxNode {
107 root: self.root.clone(),
108 red: parent,
109 })
110 }
111
112 pub fn first_child(&self) -> Option<SyntaxNode<R>> {
113 let red = self.red().get_child(0)?;
114 Some(SyntaxNode { root: self.root.clone(), red })
115 }
116
117 pub fn last_child(&self) -> Option<SyntaxNode<R>> {
118 let n = self.red().n_children();
119 let n = n.checked_sub(1)?;
120 let red = self.red().get_child(n)?;
121 Some(SyntaxNode { root: self.root.clone(), red })
122 }
123
124 pub fn next_sibling(&self) -> Option<SyntaxNode<R>> {
125 let red = self.red();
126 let parent = self.parent()?;
127 let next_sibling_idx = red.index_in_parent()? + 1;
128 let sibling_red = parent.red().get_child(next_sibling_idx)?;
129 Some(SyntaxNode {
130 root: self.root.clone(),
131 red: sibling_red,
132 })
133 }
134
135 pub fn prev_sibling(&self) -> Option<SyntaxNode<R>> {
136 let red = self.red();
137 let parent = self.parent()?;
138 let prev_sibling_idx = red.index_in_parent()?.checked_sub(1)?;
139 let sibling_red = parent.red().get_child(prev_sibling_idx)?;
140 Some(SyntaxNode {
141 root: self.root.clone(),
142 red: sibling_red,
143 })
144 }
145
146 pub fn is_leaf(&self) -> bool {
147 self.first_child().is_none()
148 }
149
150 pub fn leaf_text(&self) -> Option<SmolStr> {
151 self.borrowed().leaf_text_ref().map(|it| it.clone())
152 }
153
154 pub(crate) fn replace_with(&self, green: GreenNode) -> GreenNode {
155 assert_eq!(self.kind(), green.kind());
156 match self.parent() {
157 None => green,
158 Some(parent) => {
159 let children: Vec<_> = parent.children().map(|child| {
160 if child == *self {
161 green.clone()
162 } else {
163 child.red().green().clone()
164 }
165 }).collect();
166 let new_parent = GreenNode::new_branch(
167 parent.kind(),
168 children.into_boxed_slice(),
169 );
170 parent.replace_with(new_parent)
171 },
172 }
173 }
174
175 fn red(&self) -> &RedNode {
176 unsafe { self.red.get(self.root.syntax_root()) }
177 }
178}
179
180impl<R: TreeRoot> fmt::Debug for SyntaxNode<R> {
181 fn fmt(&self, fmt: &mut fmt::Formatter) -> fmt::Result {
182 write!(fmt, "{:?}@{:?}", self.kind(), self.range())?;
183 if has_short_text(self.kind()) {
184 write!(fmt, " \"{}\"", self.text())?;
185 }
186 Ok(())
187 }
188}
189
190#[derive(Debug)]
191pub struct SyntaxNodeChildren<R: TreeRoot> {
192 parent: SyntaxNode<R>,
193 iter: Range<usize>,
194}
195
196impl<R: TreeRoot> Iterator for SyntaxNodeChildren<R> {
197 type Item = SyntaxNode<R>;
198
199 fn next(&mut self) -> Option<SyntaxNode<R>> {
200 self.iter.next().map(|i| {
201 let red = self.parent.red();
202 SyntaxNode {
203 root: self.parent.root.clone(),
204 red: red.get_child(i).unwrap(),
205 }
206 })
207 }
208}
209
210fn has_short_text(kind: SyntaxKind) -> bool {
211 match kind {
212 IDENT | LIFETIME | INT_NUMBER | FLOAT_NUMBER => true,
213 _ => false,
214 }
215}
diff --git a/crates/ra_syntax/src/yellow/syntax_text.rs b/crates/ra_syntax/src/yellow/syntax_text.rs
new file mode 100644
index 000000000..280bedd78
--- /dev/null
+++ b/crates/ra_syntax/src/yellow/syntax_text.rs
@@ -0,0 +1,122 @@
1use std::{
2 fmt, ops,
3};
4
5use {
6 SyntaxNodeRef, TextRange, TextUnit,
7 algo::walk::preorder,
8 text_utils::{intersect, contains_offset_nonstrict},
9};
10
11#[derive(Clone)]
12pub struct SyntaxText<'a> {
13 node: SyntaxNodeRef<'a>,
14 range: TextRange,
15}
16
17impl<'a> SyntaxText<'a> {
18 pub(crate) fn new(node: SyntaxNodeRef<'a>) -> SyntaxText<'a> {
19 SyntaxText {
20 node,
21 range: node.range()
22 }
23 }
24 pub fn chunks(&self) -> impl Iterator<Item=&'a str> {
25 let range = self.range;
26 preorder(self.node)
27 .filter_map(move |node| {
28 let text = node.leaf_text_ref()?;
29 let range = intersect(range, node.range())?;
30 let range = range - node.range().start();
31 Some(&text[range])
32 })
33 }
34 pub fn push_to(&self, buf: &mut String) {
35 self.chunks().for_each(|it| buf.push_str(it));
36 }
37 pub fn to_string(&self) -> String {
38 self.chunks().collect()
39 }
40 pub fn contains(&self, c: char) -> bool {
41 self.chunks().any(|it| it.contains(c))
42 }
43 pub fn find(&self, c: char) -> Option<TextUnit> {
44 let mut acc: TextUnit = 0.into();
45 for chunk in self.chunks() {
46 if let Some(pos) = chunk.find(c) {
47 let pos: TextUnit = (pos as u32).into();
48 return Some(acc + pos);
49 }
50 acc += TextUnit::of_str(chunk);
51 }
52 None
53 }
54 pub fn len(&self) -> TextUnit {
55 self.range.len()
56 }
57 pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> {
58 let range = range.restrict(self.range)
59 .unwrap_or_else(|| {
60 panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range)
61 });
62 SyntaxText { node: self.node, range }
63 }
64 pub fn char_at(&self, offset: TextUnit) -> Option<char> {
65 let mut start: TextUnit = 0.into();
66 for chunk in self.chunks() {
67 let end = start + TextUnit::of_str(chunk);
68 if start <= offset && offset < end {
69 let off: usize = u32::from(offset - start) as usize;
70 return Some(chunk[off..].chars().next().unwrap());
71 }
72 start = end;
73 }
74 None
75 }
76}
77
78impl<'a> fmt::Debug for SyntaxText<'a> {
79 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
80 fmt::Debug::fmt(&self.to_string(), f)
81 }
82}
83
84impl<'a> fmt::Display for SyntaxText<'a> {
85 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
86 fmt::Display::fmt(&self.to_string(), f)
87 }
88}
89
90pub trait SyntaxTextSlice: fmt::Debug {
91 fn restrict(&self, range: TextRange) -> Option<TextRange>;
92}
93
94impl SyntaxTextSlice for TextRange {
95 fn restrict(&self, range: TextRange) -> Option<TextRange> {
96 intersect(*self, range)
97 }
98}
99
100impl SyntaxTextSlice for ops::RangeTo<TextUnit> {
101 fn restrict(&self, range: TextRange) -> Option<TextRange> {
102 if !contains_offset_nonstrict(range, self.end) {
103 return None;
104 }
105 Some(TextRange::from_to(range.start(), self.end))
106 }
107}
108
109impl SyntaxTextSlice for ops::RangeFrom<TextUnit> {
110 fn restrict(&self, range: TextRange) -> Option<TextRange> {
111 if !contains_offset_nonstrict(range, self.start) {
112 return None;
113 }
114 Some(TextRange::from_to(self.start, range.end()))
115 }
116}
117
118impl SyntaxTextSlice for ops::Range<TextUnit> {
119 fn restrict(&self, range: TextRange) -> Option<TextRange> {
120 TextRange::from_to(self.start, self.end).restrict(range)
121 }
122}