diff options
Diffstat (limited to 'crates/ra_mbe/src/mbe_parser.rs')
-rw-r--r-- | crates/ra_mbe/src/mbe_parser.rs | 187 |
1 files changed, 0 insertions, 187 deletions
diff --git a/crates/ra_mbe/src/mbe_parser.rs b/crates/ra_mbe/src/mbe_parser.rs deleted file mode 100644 index 954b84d9d..000000000 --- a/crates/ra_mbe/src/mbe_parser.rs +++ /dev/null | |||
@@ -1,187 +0,0 @@ | |||
1 | use crate::tt_cursor::TtCursor; | ||
2 | /// This module parses a raw `tt::TokenStream` into macro-by-example token | ||
3 | /// stream. This is a *mostly* identify function, expect for handling of | ||
4 | /// `$var:tt_kind` and `$(repeat),*` constructs. | ||
5 | use crate::ParseError; | ||
6 | |||
7 | pub(crate) fn parse(tt: &tt::Subtree) -> Result<crate::MacroRules, ParseError> { | ||
8 | let mut parser = TtCursor::new(tt); | ||
9 | let mut rules = Vec::new(); | ||
10 | while !parser.is_eof() { | ||
11 | rules.push(parse_rule(&mut parser)?); | ||
12 | if let Err(e) = parser.expect_char(';') { | ||
13 | if !parser.is_eof() { | ||
14 | return Err(e); | ||
15 | } | ||
16 | break; | ||
17 | } | ||
18 | } | ||
19 | Ok(crate::MacroRules { rules }) | ||
20 | } | ||
21 | |||
22 | fn parse_rule(p: &mut TtCursor) -> Result<crate::Rule, ParseError> { | ||
23 | let lhs = parse_subtree(p.eat_subtree()?, false)?; | ||
24 | p.expect_char('=')?; | ||
25 | p.expect_char('>')?; | ||
26 | let mut rhs = parse_subtree(p.eat_subtree()?, true)?; | ||
27 | rhs.delimiter = crate::Delimiter::None; | ||
28 | Ok(crate::Rule { lhs, rhs }) | ||
29 | } | ||
30 | |||
31 | fn is_boolean_literal(lit: Option<&tt::TokenTree>) -> bool { | ||
32 | if let Some(tt::TokenTree::Leaf(tt::Leaf::Literal(lit))) = lit { | ||
33 | if lit.text == "true" || lit.text == "false" { | ||
34 | return true; | ||
35 | } | ||
36 | } | ||
37 | |||
38 | false | ||
39 | } | ||
40 | |||
41 | fn parse_subtree(tt: &tt::Subtree, transcriber: bool) -> Result<crate::Subtree, ParseError> { | ||
42 | let mut token_trees = Vec::new(); | ||
43 | let mut p = TtCursor::new(tt); | ||
44 | while let Some(tt) = p.eat() { | ||
45 | let child: crate::TokenTree = match tt { | ||
46 | tt::TokenTree::Leaf(leaf) => match leaf { | ||
47 | tt::Leaf::Punct(tt::Punct { char: '$', spacing }) => { | ||
48 | // mbe var can be an ident or keyword, including `true` and `false` | ||
49 | if p.at_ident().is_some() || is_boolean_literal(p.current()) { | ||
50 | crate::Leaf::from(parse_var(&mut p, transcriber)?).into() | ||
51 | } else if let Some(tt::TokenTree::Subtree(_)) = p.current() { | ||
52 | parse_repeat(&mut p, transcriber)?.into() | ||
53 | } else { | ||
54 | // Treat it as normal punct | ||
55 | crate::Leaf::from(tt::Punct { char: '$', spacing: *spacing }).into() | ||
56 | } | ||
57 | } | ||
58 | tt::Leaf::Punct(punct) => crate::Leaf::from(*punct).into(), | ||
59 | tt::Leaf::Ident(tt::Ident { text, .. }) => { | ||
60 | crate::Leaf::from(crate::Ident { text: text.clone() }).into() | ||
61 | } | ||
62 | tt::Leaf::Literal(tt::Literal { text }) => { | ||
63 | crate::Leaf::from(crate::Literal { text: text.clone() }).into() | ||
64 | } | ||
65 | }, | ||
66 | tt::TokenTree::Subtree(subtree) => parse_subtree(&subtree, transcriber)?.into(), | ||
67 | }; | ||
68 | token_trees.push(child); | ||
69 | } | ||
70 | Ok(crate::Subtree { token_trees, delimiter: tt.delimiter }) | ||
71 | } | ||
72 | |||
73 | fn parse_var(p: &mut TtCursor, transcriber: bool) -> Result<crate::Var, ParseError> { | ||
74 | let text = { | ||
75 | if is_boolean_literal(p.current()) { | ||
76 | let lit = p.eat_literal().unwrap(); | ||
77 | lit.text.clone() | ||
78 | } else { | ||
79 | let ident = p.eat_ident().unwrap(); | ||
80 | ident.text.clone() | ||
81 | } | ||
82 | }; | ||
83 | |||
84 | let kind = if !transcriber && p.at_char(':') { | ||
85 | p.bump(); | ||
86 | if let Some(ident) = p.eat_ident() { | ||
87 | Some(ident.text.clone()) | ||
88 | } else { | ||
89 | p.rev_bump(); | ||
90 | None | ||
91 | } | ||
92 | } else { | ||
93 | None | ||
94 | }; | ||
95 | |||
96 | Ok(crate::Var { text, kind }) | ||
97 | } | ||
98 | |||
99 | fn mk_repeat( | ||
100 | rep: char, | ||
101 | subtree: crate::Subtree, | ||
102 | separator: Option<crate::Separator>, | ||
103 | ) -> Result<crate::Repeat, ParseError> { | ||
104 | let kind = match rep { | ||
105 | '*' => crate::RepeatKind::ZeroOrMore, | ||
106 | '+' => crate::RepeatKind::OneOrMore, | ||
107 | '?' => crate::RepeatKind::ZeroOrOne, | ||
108 | _ => return Err(ParseError::Expected(String::from("repeat"))), | ||
109 | }; | ||
110 | Ok(crate::Repeat { subtree, kind, separator }) | ||
111 | } | ||
112 | |||
113 | fn parse_repeat(p: &mut TtCursor, transcriber: bool) -> Result<crate::Repeat, ParseError> { | ||
114 | let subtree = p.eat_subtree()?; | ||
115 | let mut subtree = parse_subtree(subtree, transcriber)?; | ||
116 | subtree.delimiter = crate::Delimiter::None; | ||
117 | |||
118 | if let Some(rep) = p.at_punct() { | ||
119 | match rep.char { | ||
120 | '*' | '+' | '?' => { | ||
121 | p.bump(); | ||
122 | return mk_repeat(rep.char, subtree, None); | ||
123 | } | ||
124 | _ => {} | ||
125 | } | ||
126 | } | ||
127 | |||
128 | let sep = p.eat_seperator().ok_or_else(|| ParseError::Expected(String::from("separator")))?; | ||
129 | let rep = p.eat_punct().ok_or_else(|| ParseError::Expected(String::from("repeat")))?; | ||
130 | |||
131 | mk_repeat(rep.char, subtree, Some(sep)) | ||
132 | } | ||
133 | |||
134 | #[cfg(test)] | ||
135 | mod tests { | ||
136 | use ra_syntax::{ast, AstNode}; | ||
137 | |||
138 | use super::*; | ||
139 | use crate::ast_to_token_tree; | ||
140 | |||
141 | #[test] | ||
142 | fn test_invalid_parse() { | ||
143 | expect_err("invalid", "subtree"); | ||
144 | |||
145 | is_valid("($i:ident) => ()"); | ||
146 | is_valid("($($i:ident)*) => ($_)"); | ||
147 | is_valid("($($true:ident)*) => ($true)"); | ||
148 | is_valid("($($false:ident)*) => ($false)"); | ||
149 | |||
150 | expect_err("$i:ident => ()", "subtree"); | ||
151 | expect_err("($i:ident) ()", "`=`"); | ||
152 | expect_err("($($i:ident)_) => ()", "repeat"); | ||
153 | } | ||
154 | |||
155 | fn expect_err(macro_body: &str, expected: &str) { | ||
156 | assert_eq!( | ||
157 | create_rules(&format_macro(macro_body)), | ||
158 | Err(ParseError::Expected(String::from(expected))) | ||
159 | ); | ||
160 | } | ||
161 | |||
162 | fn is_valid(macro_body: &str) { | ||
163 | assert!(create_rules(&format_macro(macro_body)).is_ok()); | ||
164 | } | ||
165 | |||
166 | fn format_macro(macro_body: &str) -> String { | ||
167 | format!( | ||
168 | " | ||
169 | macro_rules! foo {{ | ||
170 | {} | ||
171 | }} | ||
172 | ", | ||
173 | macro_body | ||
174 | ) | ||
175 | } | ||
176 | |||
177 | fn create_rules(macro_definition: &str) -> Result<crate::MacroRules, ParseError> { | ||
178 | let source_file = ast::SourceFile::parse(macro_definition).ok().unwrap(); | ||
179 | let macro_definition = | ||
180 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
181 | |||
182 | let (definition_tt, _) = | ||
183 | ast_to_token_tree(¯o_definition.token_tree().unwrap()).unwrap(); | ||
184 | parse(&definition_tt) | ||
185 | } | ||
186 | |||
187 | } | ||