aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_mbe/src/mbe_parser.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_mbe/src/mbe_parser.rs')
-rw-r--r--crates/ra_mbe/src/mbe_parser.rs187
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 @@
1use 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.
5use crate::ParseError;
6
7pub(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
22fn 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
31fn 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
41fn 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
73fn 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
99fn 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
113fn 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)]
135mod 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(&macro_definition.token_tree().unwrap()).unwrap();
184 parse(&definition_tt)
185 }
186
187}