diff options
author | Aleksey Kladov <[email protected]> | 2017-12-31 14:54:33 +0000 |
---|---|---|
committer | Aleksey Kladov <[email protected]> | 2017-12-31 14:54:33 +0000 |
commit | 9ce4db545efba697f20ab5cecbefc0589c7146ca (patch) | |
tree | ecda02126426b473bf2f70777a148e569c114c98 /src | |
parent | 98a58bf806ffda1b4d3352ed0f3e494fa25c8c74 (diff) |
Parser: groundwork
Diffstat (limited to 'src')
-rw-r--r-- | src/lexer/mod.rs | 11 | ||||
-rw-r--r-- | src/lib.rs | 4 | ||||
-rw-r--r-- | src/parser/mod.rs | 5 | ||||
-rw-r--r-- | src/text.rs | 59 | ||||
-rw-r--r-- | src/tree.rs | 74 |
5 files changed, 149 insertions, 4 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 | |||
16 | mod comments; | 16 | mod comments; |
17 | use self::comments::{scan_shebang, scan_comment}; | 17 | use self::comments::{scan_shebang, scan_comment}; |
18 | 18 | ||
19 | pub 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 | } | ||
19 | pub fn next_token(text: &str) -> Token { | 30 | pub 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; | |||
5 | mod lexer; | 5 | mod lexer; |
6 | 6 | ||
7 | pub mod syntax_kinds; | 7 | pub mod syntax_kinds; |
8 | pub use text::TextUnit; | 8 | pub use text::{TextUnit, TextRange}; |
9 | pub use tree::{SyntaxKind, Token}; | 9 | pub use tree::{SyntaxKind, Token}; |
10 | pub use lexer::next_token; | 10 | pub 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 @@ | |||
1 | use {Token, File}; | ||
2 | |||
3 | pub 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)] | ||
63 | pub struct TextRange { | ||
64 | start: TextUnit, | ||
65 | end: TextUnit, | ||
66 | } | ||
67 | |||
68 | impl 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 | |||
74 | impl 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 | |||
81 | impl 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 | |||
112 | impl 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 @@ | |||
1 | use text::{TextUnit}; | 1 | use text::{TextUnit, TextRange}; |
2 | use syntax_kinds::syntax_info; | 2 | use syntax_kinds::syntax_info; |
3 | 3 | ||
4 | use std::fmt; | 4 | use std::fmt; |
@@ -28,4 +28,74 @@ pub(crate) struct SyntaxInfo { | |||
28 | pub struct Token { | 28 | pub 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 | |||
33 | pub struct File { | ||
34 | text: String, | ||
35 | nodes: Vec<NodeData>, | ||
36 | } | ||
37 | |||
38 | impl 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)] | ||
46 | pub struct Node<'f> { | ||
47 | file: &'f File, | ||
48 | idx: NodeIdx, | ||
49 | } | ||
50 | |||
51 | impl<'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 | |||
78 | pub struct Children<'f> { | ||
79 | next: Option<Node<'f>>, | ||
80 | } | ||
81 | |||
82 | impl<'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)] | ||
93 | struct NodeIdx(u32); | ||
94 | |||
95 | struct NodeData { | ||
96 | kind: SyntaxKind, | ||
97 | range: TextRange, | ||
98 | parent: Option<NodeIdx>, | ||
99 | first_child: Option<NodeIdx>, | ||
100 | next_sibling: Option<NodeIdx>, | ||
101 | } | ||