aboutsummaryrefslogtreecommitdiff
path: root/crates/libsyntax2/src/yellow
diff options
context:
space:
mode:
authorAleksey Kladov <[email protected]>2018-08-28 12:06:30 +0100
committerAleksey Kladov <[email protected]>2018-08-28 12:06:30 +0100
commit7e74af32268f9b0783ca94107b0b10d52e4ebe5e (patch)
tree179d818c695a27ceee3f8193e219234854190f9a /crates/libsyntax2/src/yellow
parent363f466627db373fab23d1df94b7382223b8675a (diff)
Avoid materializing strings
Diffstat (limited to 'crates/libsyntax2/src/yellow')
-rw-r--r--crates/libsyntax2/src/yellow/green.rs16
-rw-r--r--crates/libsyntax2/src/yellow/mod.rs10
-rw-r--r--crates/libsyntax2/src/yellow/syntax.rs19
-rw-r--r--crates/libsyntax2/src/yellow/syntax_text.rs101
4 files changed, 127 insertions, 19 deletions
diff --git a/crates/libsyntax2/src/yellow/green.rs b/crates/libsyntax2/src/yellow/green.rs
index 700f2704f..59aefb0de 100644
--- a/crates/libsyntax2/src/yellow/green.rs
+++ b/crates/libsyntax2/src/yellow/green.rs
@@ -43,21 +43,13 @@ impl GreenNode {
43 } 43 }
44 } 44 }
45 45
46 pub fn text(&self) -> String { 46 pub fn leaf_text(&self) -> Option<SmolStr> {
47 let mut buff = String::new(); 47 self.leaf_text_ref().map(Clone::clone)
48 go(self, &mut buff);
49 return buff;
50 fn go(node: &GreenNode, buff: &mut String) {
51 match node {
52 GreenNode::Leaf { text, .. } => buff.push_str(text.as_str()),
53 GreenNode::Branch(b) => b.children().iter().for_each(|child| go(child, buff)),
54 }
55 }
56 } 48 }
57 49
58 pub fn leaf_text(&self) -> Option<SmolStr> { 50 pub fn leaf_text_ref(&self) -> Option<&SmolStr> {
59 match self { 51 match self {
60 GreenNode::Leaf { text, .. } => Some(text.clone()), 52 GreenNode::Leaf { text, .. } => Some(text),
61 GreenNode::Branch(_) => None, 53 GreenNode::Branch(_) => None,
62 } 54 }
63 } 55 }
diff --git a/crates/libsyntax2/src/yellow/mod.rs b/crates/libsyntax2/src/yellow/mod.rs
index b94c794fe..82eda79d6 100644
--- a/crates/libsyntax2/src/yellow/mod.rs
+++ b/crates/libsyntax2/src/yellow/mod.rs
@@ -2,6 +2,7 @@ mod builder;
2mod green; 2mod green;
3mod red; 3mod red;
4mod syntax; 4mod syntax;
5mod syntax_text;
5 6
6use std::{ 7use std::{
7 sync::Arc, 8 sync::Arc,
@@ -12,6 +13,7 @@ pub(crate) use self::{
12 builder::GreenBuilder, 13 builder::GreenBuilder,
13 green::GreenNode, 14 green::GreenNode,
14 red::RedNode, 15 red::RedNode,
16 syntax_text::SyntaxText,
15}; 17};
16 18
17#[derive(Debug)] 19#[derive(Debug)]
@@ -32,6 +34,12 @@ pub struct OwnedRoot(Arc<SyntaxRoot>);
32#[derive(Clone, Copy, Debug)] 34#[derive(Clone, Copy, Debug)]
33pub struct RefRoot<'a>(&'a OwnedRoot); // TODO: shared_from_this instead of double indirection 35pub struct RefRoot<'a>(&'a OwnedRoot); // TODO: shared_from_this instead of double indirection
34 36
37impl<'a> RefRoot<'a> {
38 fn syntax_root(&self) -> &'a SyntaxRoot {
39 self.0.syntax_root()
40 }
41}
42
35impl TreeRoot for OwnedRoot { 43impl TreeRoot for OwnedRoot {
36 fn borrowed(&self) -> RefRoot { 44 fn borrowed(&self) -> RefRoot {
37 RefRoot(&self) 45 RefRoot(&self)
@@ -78,7 +86,7 @@ impl RedPtr {
78 RedPtr(red.into()) 86 RedPtr(red.into())
79 } 87 }
80 88
81 unsafe fn get<'a>(self, _root: &'a impl TreeRoot) -> &'a RedNode { 89 unsafe fn get<'a>(self, _root: &'a SyntaxRoot) -> &'a RedNode {
82 &*self.0.as_ptr() 90 &*self.0.as_ptr()
83 } 91 }
84} 92}
diff --git a/crates/libsyntax2/src/yellow/syntax.rs b/crates/libsyntax2/src/yellow/syntax.rs
index 75b6cb7dc..ede9ad3c8 100644
--- a/crates/libsyntax2/src/yellow/syntax.rs
+++ b/crates/libsyntax2/src/yellow/syntax.rs
@@ -6,7 +6,7 @@ use std::{
6use smol_str::SmolStr; 6use smol_str::SmolStr;
7 7
8use { 8use {
9 yellow::{GreenNode, RedNode, TreeRoot, SyntaxRoot, RedPtr, RefRoot, OwnedRoot}, 9 yellow::{GreenNode, RedNode, TreeRoot, SyntaxRoot, RedPtr, RefRoot, OwnedRoot, SyntaxText},
10 SyntaxKind::{self, *}, 10 SyntaxKind::{self, *},
11 TextRange, TextUnit, 11 TextRange, TextUnit,
12}; 12};
@@ -58,6 +58,13 @@ impl SyntaxNode<OwnedRoot> {
58 } 58 }
59} 59}
60 60
61impl<'a> SyntaxNode<RefRoot<'a>> {
62 pub(crate) fn leaf_text_ref(self) -> Option<&'a SmolStr> {
63 let red = unsafe { self.red.get(self.root.syntax_root()) };
64 red.green().leaf_text_ref()
65 }
66}
67
61impl<R: TreeRoot> SyntaxNode<R> { 68impl<R: TreeRoot> SyntaxNode<R> {
62 pub fn borrowed<'a>(&'a self) -> SyntaxNodeRef<'a> { 69 pub fn borrowed<'a>(&'a self) -> SyntaxNodeRef<'a> {
63 SyntaxNode { 70 SyntaxNode {
@@ -66,7 +73,7 @@ impl<R: TreeRoot> SyntaxNode<R> {
66 } 73 }
67 } 74 }
68 75
69 pub fn owned<'a>(&'a self) -> SyntaxNode { 76 pub fn owned(&self) -> SyntaxNode {
70 SyntaxNode { 77 SyntaxNode {
71 root: self.root.owned(), 78 root: self.root.owned(),
72 red: self.red, 79 red: self.red,
@@ -82,8 +89,8 @@ impl<R: TreeRoot> SyntaxNode<R> {
82 TextRange::offset_len(red.start_offset(), red.green().text_len()) 89 TextRange::offset_len(red.start_offset(), red.green().text_len())
83 } 90 }
84 91
85 pub fn text(&self) -> String { 92 pub fn text(&self) -> SyntaxText {
86 self.red().green().text() 93 SyntaxText::new(self.borrowed())
87 } 94 }
88 95
89 pub fn children(&self) -> impl Iterator<Item = SyntaxNode<R>> { 96 pub fn children(&self) -> impl Iterator<Item = SyntaxNode<R>> {
@@ -91,7 +98,7 @@ impl<R: TreeRoot> SyntaxNode<R> {
91 let n_children = self.red().n_children(); 98 let n_children = self.red().n_children();
92 let root = self.root.clone(); 99 let root = self.root.clone();
93 (0..n_children).map(move |i| { 100 (0..n_children).map(move |i| {
94 let red = unsafe { red.get(&root) }; 101 let red = unsafe { red.get(root.syntax_root()) };
95 SyntaxNode { 102 SyntaxNode {
96 root: root.clone(), 103 root: root.clone(),
97 red: red.get_child(i).unwrap(), 104 red: red.get_child(i).unwrap(),
@@ -171,7 +178,7 @@ impl<R: TreeRoot> SyntaxNode<R> {
171 } 178 }
172 179
173 fn red(&self) -> &RedNode { 180 fn red(&self) -> &RedNode {
174 unsafe { self.red.get(&self.root) } 181 unsafe { self.red.get(self.root.syntax_root()) }
175 } 182 }
176} 183}
177 184
diff --git a/crates/libsyntax2/src/yellow/syntax_text.rs b/crates/libsyntax2/src/yellow/syntax_text.rs
new file mode 100644
index 000000000..268547470
--- /dev/null
+++ b/crates/libsyntax2/src/yellow/syntax_text.rs
@@ -0,0 +1,101 @@
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 to_string(&self) -> String {
35 self.chunks().collect()
36 }
37 pub fn contains(&self, c: char) -> bool {
38 self.chunks().any(|it| it.contains(c))
39 }
40 pub fn find(&self, c: char) -> Option<TextUnit> {
41 let mut acc: TextUnit = 0.into();
42 for chunk in self.chunks() {
43 if let Some(pos) = chunk.find(c) {
44 let pos: TextUnit = (pos as u32).into();
45 return Some(acc + pos);
46 }
47 acc += TextUnit::of_str(chunk);
48 }
49 None
50 }
51 pub fn len(&self) -> TextUnit {
52 self.range.len()
53 }
54 pub fn slice(&self, range: impl SyntaxTextSlice) -> SyntaxText<'a> {
55 let range = range.restrict(self.range)
56 .unwrap_or_else(|| {
57 panic!("invalid slice, range: {:?}, slice: {:?}", self.range, range)
58 });
59 SyntaxText { node: self.node, range }
60 }
61}
62
63impl<'a> fmt::Debug for SyntaxText<'a> {
64 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
65 fmt::Debug::fmt(&self.to_string(), f)
66 }
67}
68
69impl<'a> fmt::Display for SyntaxText<'a> {
70 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
71 fmt::Display::fmt(&self.to_string(), f)
72 }
73}
74
75pub trait SyntaxTextSlice: fmt::Debug {
76 fn restrict(&self, range: TextRange) -> Option<TextRange>;
77}
78
79impl SyntaxTextSlice for TextRange {
80 fn restrict(&self, range: TextRange) -> Option<TextRange> {
81 intersect(*self, range)
82 }
83}
84
85impl SyntaxTextSlice for ops::RangeTo<TextUnit> {
86 fn restrict(&self, range: TextRange) -> Option<TextRange> {
87 if !contains_offset_nonstrict(range, self.end) {
88 return None;
89 }
90 Some(TextRange::from_to(range.start(), self.end))
91 }
92}
93
94impl SyntaxTextSlice for ops::RangeFrom<TextUnit> {
95 fn restrict(&self, range: TextRange) -> Option<TextRange> {
96 if !contains_offset_nonstrict(range, self.start) {
97 return None;
98 }
99 Some(TextRange::from_to(self.start, range.end()))
100 }
101}