aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--src/lexer/mod.rs11
-rw-r--r--src/lib.rs4
-rw-r--r--src/parser/mod.rs5
-rw-r--r--src/text.rs59
-rw-r--r--src/tree.rs74
-rw-r--r--tests/lexer.rs14
6 files changed, 150 insertions, 17 deletions
diff --git a/src/lexer/mod.rs b/src/lexer/mod.rs
index f46746bee..7c4259763 100644
--- a/src/lexer/mod.rs
+++ b/src/lexer/mod.rs
@@ -16,6 +16,17 @@ use self::strings::{is_string_literal_start, scan_char, scan_byte_char_or_string
16mod comments; 16mod comments;
17use self::comments::{scan_shebang, scan_comment}; 17use self::comments::{scan_shebang, scan_comment};
18 18
19pub fn tokenize(text: &str) -> Vec<Token> {
20 let mut text = text;
21 let mut acc = Vec::new();
22 while !text.is_empty() {
23 let token = next_token(text);
24 acc.push(token);
25 let len: u32 = token.len.into();
26 text = &text[len as usize..];
27 }
28 acc
29}
19pub fn next_token(text: &str) -> Token { 30pub fn next_token(text: &str) -> Token {
20 assert!(!text.is_empty()); 31 assert!(!text.is_empty());
21 let mut ptr = Ptr::new(text); 32 let mut ptr = Ptr::new(text);
diff --git a/src/lib.rs b/src/lib.rs
index 3b9dbc8f7..82213e2b3 100644
--- a/src/lib.rs
+++ b/src/lib.rs
@@ -5,6 +5,6 @@ mod tree;
5mod lexer; 5mod lexer;
6 6
7pub mod syntax_kinds; 7pub mod syntax_kinds;
8pub use text::TextUnit; 8pub use text::{TextUnit, TextRange};
9pub use tree::{SyntaxKind, Token}; 9pub use tree::{SyntaxKind, Token};
10pub use lexer::next_token; 10pub use lexer::{next_token, tokenize};
diff --git a/src/parser/mod.rs b/src/parser/mod.rs
new file mode 100644
index 000000000..da902e2b7
--- /dev/null
+++ b/src/parser/mod.rs
@@ -0,0 +1,5 @@
1use {Token, File};
2
3pub fn parse(tokens: &[Token]) -> File {
4 unimplemented!()
5} \ No newline at end of file
diff --git a/src/text.rs b/src/text.rs
index c3ef1ac8e..ee0dc8398 100644
--- a/src/text.rs
+++ b/src/text.rs
@@ -56,4 +56,63 @@ impl ops::SubAssign<TextUnit> for TextUnit {
56 fn sub_assign(&mut self, rhs: TextUnit) { 56 fn sub_assign(&mut self, rhs: TextUnit) {
57 self.0 -= rhs.0 57 self.0 -= rhs.0
58 } 58 }
59}
60
61
62#[derive(Clone, Copy, PartialEq, Eq)]
63pub struct TextRange {
64 start: TextUnit,
65 end: TextUnit,
66}
67
68impl fmt::Debug for TextRange {
69 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
70 <Self as fmt::Display>::fmt(self, f)
71 }
72}
73
74impl fmt::Display for TextRange {
75 fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
76 write!(f, "[{}; {})", self.start(), self.end())
77 }
78}
79
80
81impl TextRange {
82 pub fn empty() -> TextRange {
83 TextRange::from_to(TextUnit::new(0), TextUnit::new(0))
84 }
85
86 pub fn from_to(from: TextUnit, to: TextUnit) -> TextRange {
87 assert!(from <= to, "Invalid text range [{}; {})", from, to);
88 TextRange { start: from, end: to }
89 }
90
91 pub fn from_len(from: TextUnit, len: TextUnit) -> TextRange {
92 TextRange::from_to(from, from + len)
93 }
94
95 pub fn start(&self) -> TextUnit {
96 self.start
97 }
98
99 pub fn end(&self) -> TextUnit {
100 self.end
101 }
102
103 pub fn len(&self) -> TextUnit {
104 self.end - self.start
105 }
106
107 pub fn is_empty(&self) -> bool {
108 self.start() == self.end()
109 }
110}
111
112impl ops::Index<TextRange> for str {
113 type Output = str;
114
115 fn index(&self, index: TextRange) -> &str {
116 &self[index.start().0 as usize..index.end().0 as usize]
117 }
59} \ No newline at end of file 118} \ No newline at end of file
diff --git a/src/tree.rs b/src/tree.rs
index 0924f38d0..2ac25e795 100644
--- a/src/tree.rs
+++ b/src/tree.rs
@@ -1,4 +1,4 @@
1use text::{TextUnit}; 1use text::{TextUnit, TextRange};
2use syntax_kinds::syntax_info; 2use syntax_kinds::syntax_info;
3 3
4use std::fmt; 4use std::fmt;
@@ -28,4 +28,74 @@ pub(crate) struct SyntaxInfo {
28pub struct Token { 28pub struct Token {
29 pub kind: SyntaxKind, 29 pub kind: SyntaxKind,
30 pub len: TextUnit, 30 pub len: TextUnit,
31} \ No newline at end of file 31}
32
33pub struct File {
34 text: String,
35 nodes: Vec<NodeData>,
36}
37
38impl File {
39 pub fn root<'f>(&'f self) -> Node<'f> {
40 assert!(!self.nodes.is_empty());
41 Node { file: self, idx: NodeIdx(0) }
42 }
43}
44
45#[derive(Clone, Copy)]
46pub struct Node<'f> {
47 file: &'f File,
48 idx: NodeIdx,
49}
50
51impl<'f> Node<'f> {
52 pub fn kind(&self) -> SyntaxKind {
53 self.data().kind
54 }
55
56 pub fn text(&self) -> &'f str {
57 let range = self.data().range;
58 &self.file.text.as_str()[range]
59 }
60
61 pub fn parent(&self) -> Option<Node<'f>> {
62 self.as_node(self.data().parent)
63 }
64
65 pub fn children(&self) -> Children<'f> {
66 Children { next: self.as_node(self.data().first_child) }
67 }
68
69 fn data(&self) -> &'f NodeData {
70 &self.file.nodes[self.idx.0 as usize]
71 }
72
73 fn as_node(&self, idx: Option<NodeIdx>) -> Option<Node<'f>> {
74 idx.map(|idx| Node { file: self.file, idx })
75 }
76}
77
78pub struct Children<'f> {
79 next: Option<Node<'f>>,
80}
81
82impl<'f> Iterator for Children<'f> {
83 type Item = Node<'f>;
84
85 fn next(&mut self) -> Option<Node<'f>> {
86 let next = self.next;
87 self.next = next.and_then(|node| node.as_node(node.data().next_sibling));
88 next
89 }
90}
91
92#[derive(Clone, Copy)]
93struct NodeIdx(u32);
94
95struct NodeData {
96 kind: SyntaxKind,
97 range: TextRange,
98 parent: Option<NodeIdx>,
99 first_child: Option<NodeIdx>,
100 next_sibling: Option<NodeIdx>,
101}
diff --git a/tests/lexer.rs b/tests/lexer.rs
index 6a9bab66b..beca19c24 100644
--- a/tests/lexer.rs
+++ b/tests/lexer.rs
@@ -7,7 +7,7 @@ use std::path::{PathBuf, Path};
7use std::fs::read_dir; 7use std::fs::read_dir;
8use std::fmt::Write; 8use std::fmt::Write;
9 9
10use libsyntax2::{Token, next_token}; 10use libsyntax2::{Token, tokenize};
11 11
12#[test] 12#[test]
13fn lexer_tests() { 13fn lexer_tests() {
@@ -53,18 +53,6 @@ fn lexer_test_case(path: &Path) {
53 assert_diff!(expected, actual, "\n", 0) 53 assert_diff!(expected, actual, "\n", 0)
54} 54}
55 55
56fn tokenize(text: &str) -> Vec<Token> {
57 let mut text = text;
58 let mut acc = Vec::new();
59 while !text.is_empty() {
60 let token = next_token(text);
61 acc.push(token);
62 let len: u32 = token.len.into();
63 text = &text[len as usize..];
64 }
65 acc
66}
67
68fn dump_tokens(tokens: &[Token], text: &str) -> String { 56fn dump_tokens(tokens: &[Token], text: &str) -> String {
69 let mut acc = String::new(); 57 let mut acc = String::new();
70 let mut offset = 0; 58 let mut offset = 0;