diff options
Diffstat (limited to 'crates/mbe/src')
-rw-r--r-- | crates/mbe/src/lib.rs | 72 | ||||
-rw-r--r-- | crates/mbe/src/mbe_expander.rs | 9 | ||||
-rw-r--r-- | crates/mbe/src/tests.rs | 233 |
3 files changed, 227 insertions, 87 deletions
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs index 19543d777..35cde5f10 100644 --- a/crates/mbe/src/lib.rs +++ b/crates/mbe/src/lib.rs | |||
@@ -14,6 +14,7 @@ mod tests; | |||
14 | 14 | ||
15 | use std::fmt; | 15 | use std::fmt; |
16 | 16 | ||
17 | use test_utils::mark; | ||
17 | pub use tt::{Delimiter, DelimiterKind, Punct}; | 18 | pub use tt::{Delimiter, DelimiterKind, Punct}; |
18 | 19 | ||
19 | use crate::{ | 20 | use crate::{ |
@@ -76,6 +77,14 @@ pub struct MacroRules { | |||
76 | shift: Shift, | 77 | shift: Shift, |
77 | } | 78 | } |
78 | 79 | ||
80 | /// For Macro 2.0 | ||
81 | #[derive(Clone, Debug, PartialEq, Eq)] | ||
82 | pub struct MacroDef { | ||
83 | rules: Vec<Rule>, | ||
84 | /// Highest id of the token we have in TokenMap | ||
85 | shift: Shift, | ||
86 | } | ||
87 | |||
79 | #[derive(Clone, Debug, PartialEq, Eq)] | 88 | #[derive(Clone, Debug, PartialEq, Eq)] |
80 | struct Rule { | 89 | struct Rule { |
81 | lhs: MetaTemplate, | 90 | lhs: MetaTemplate, |
@@ -179,7 +188,7 @@ impl MacroRules { | |||
179 | let mut src = TtIter::new(tt); | 188 | let mut src = TtIter::new(tt); |
180 | let mut rules = Vec::new(); | 189 | let mut rules = Vec::new(); |
181 | while src.len() > 0 { | 190 | while src.len() > 0 { |
182 | let rule = Rule::parse(&mut src)?; | 191 | let rule = Rule::parse(&mut src, true)?; |
183 | rules.push(rule); | 192 | rules.push(rule); |
184 | if let Err(()) = src.expect_char(';') { | 193 | if let Err(()) = src.expect_char(';') { |
185 | if src.len() > 0 { | 194 | if src.len() > 0 { |
@@ -200,7 +209,58 @@ impl MacroRules { | |||
200 | // apply shift | 209 | // apply shift |
201 | let mut tt = tt.clone(); | 210 | let mut tt = tt.clone(); |
202 | self.shift.shift_all(&mut tt); | 211 | self.shift.shift_all(&mut tt); |
203 | mbe_expander::expand(self, &tt) | 212 | mbe_expander::expand_rules(&self.rules, &tt) |
213 | } | ||
214 | |||
215 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { | ||
216 | self.shift.shift(id) | ||
217 | } | ||
218 | |||
219 | pub fn map_id_up(&self, id: tt::TokenId) -> (tt::TokenId, Origin) { | ||
220 | match self.shift.unshift(id) { | ||
221 | Some(id) => (id, Origin::Call), | ||
222 | None => (id, Origin::Def), | ||
223 | } | ||
224 | } | ||
225 | } | ||
226 | |||
227 | impl MacroDef { | ||
228 | pub fn parse(tt: &tt::Subtree) -> Result<MacroDef, ParseError> { | ||
229 | let mut src = TtIter::new(tt); | ||
230 | let mut rules = Vec::new(); | ||
231 | |||
232 | if Some(tt::DelimiterKind::Brace) == tt.delimiter_kind() { | ||
233 | mark::hit!(parse_macro_def_rules); | ||
234 | while src.len() > 0 { | ||
235 | let rule = Rule::parse(&mut src, true)?; | ||
236 | rules.push(rule); | ||
237 | if let Err(()) = src.expect_char(';') { | ||
238 | if src.len() > 0 { | ||
239 | return Err(ParseError::Expected("expected `;`".to_string())); | ||
240 | } | ||
241 | break; | ||
242 | } | ||
243 | } | ||
244 | } else { | ||
245 | mark::hit!(parse_macro_def_simple); | ||
246 | let rule = Rule::parse(&mut src, false)?; | ||
247 | if src.len() != 0 { | ||
248 | return Err(ParseError::Expected("remain tokens in macro def".to_string())); | ||
249 | } | ||
250 | rules.push(rule); | ||
251 | } | ||
252 | for rule in rules.iter() { | ||
253 | validate(&rule.lhs)?; | ||
254 | } | ||
255 | |||
256 | Ok(MacroDef { rules, shift: Shift::new(tt) }) | ||
257 | } | ||
258 | |||
259 | pub fn expand(&self, tt: &tt::Subtree) -> ExpandResult<tt::Subtree> { | ||
260 | // apply shift | ||
261 | let mut tt = tt.clone(); | ||
262 | self.shift.shift_all(&mut tt); | ||
263 | mbe_expander::expand_rules(&self.rules, &tt) | ||
204 | } | 264 | } |
205 | 265 | ||
206 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { | 266 | pub fn map_id_down(&self, id: tt::TokenId) -> tt::TokenId { |
@@ -216,12 +276,14 @@ impl MacroRules { | |||
216 | } | 276 | } |
217 | 277 | ||
218 | impl Rule { | 278 | impl Rule { |
219 | fn parse(src: &mut TtIter) -> Result<Rule, ParseError> { | 279 | fn parse(src: &mut TtIter, expect_arrow: bool) -> Result<Rule, ParseError> { |
220 | let lhs = src | 280 | let lhs = src |
221 | .expect_subtree() | 281 | .expect_subtree() |
222 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; | 282 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; |
223 | src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; | 283 | if expect_arrow { |
224 | src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; | 284 | src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?; |
285 | src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?; | ||
286 | } | ||
225 | let rhs = src | 287 | let rhs = src |
226 | .expect_subtree() | 288 | .expect_subtree() |
227 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; | 289 | .map_err(|()| ParseError::Expected("expected subtree".to_string()))?; |
diff --git a/crates/mbe/src/mbe_expander.rs b/crates/mbe/src/mbe_expander.rs index a80b73db4..802c8fb0f 100644 --- a/crates/mbe/src/mbe_expander.rs +++ b/crates/mbe/src/mbe_expander.rs | |||
@@ -10,11 +10,10 @@ use syntax::SmolStr; | |||
10 | 10 | ||
11 | use crate::{ExpandError, ExpandResult}; | 11 | use crate::{ExpandError, ExpandResult}; |
12 | 12 | ||
13 | pub(crate) fn expand(rules: &crate::MacroRules, input: &tt::Subtree) -> ExpandResult<tt::Subtree> { | 13 | pub(crate) fn expand_rules( |
14 | expand_rules(&rules.rules, input) | 14 | rules: &[crate::Rule], |
15 | } | 15 | input: &tt::Subtree, |
16 | 16 | ) -> ExpandResult<tt::Subtree> { | |
17 | fn expand_rules(rules: &[crate::Rule], input: &tt::Subtree) -> ExpandResult<tt::Subtree> { | ||
18 | let mut match_: Option<(matcher::Match, &crate::Rule)> = None; | 17 | let mut match_: Option<(matcher::Match, &crate::Rule)> = None; |
19 | for rule in rules { | 18 | for rule in rules { |
20 | let new_match = match matcher::match_(&rule.lhs, input) { | 19 | let new_match = match matcher::match_(&rule.lhs, input) { |
diff --git a/crates/mbe/src/tests.rs b/crates/mbe/src/tests.rs index bd2977ebd..8d978163d 100644 --- a/crates/mbe/src/tests.rs +++ b/crates/mbe/src/tests.rs | |||
@@ -6,7 +6,7 @@ use syntax::{ | |||
6 | SyntaxKind::{ERROR, IDENT}, | 6 | SyntaxKind::{ERROR, IDENT}, |
7 | SyntaxNode, WalkEvent, T, | 7 | SyntaxNode, WalkEvent, T, |
8 | }; | 8 | }; |
9 | use test_utils::assert_eq_text; | 9 | use test_utils::{assert_eq_text, mark}; |
10 | 10 | ||
11 | use super::*; | 11 | use super::*; |
12 | 12 | ||
@@ -675,6 +675,36 @@ fn test_match_literal() { | |||
675 | .assert_expand_items("foo! ['('];", "fn foo () {}"); | 675 | .assert_expand_items("foo! ['('];", "fn foo () {}"); |
676 | } | 676 | } |
677 | 677 | ||
678 | #[test] | ||
679 | fn test_parse_macro_def_simple() { | ||
680 | mark::check!(parse_macro_def_simple); | ||
681 | |||
682 | parse_macro2( | ||
683 | r#" | ||
684 | macro foo($id:ident) { | ||
685 | fn $id() {} | ||
686 | } | ||
687 | "#, | ||
688 | ) | ||
689 | .assert_expand_items("foo!(bar);", "fn bar () {}"); | ||
690 | } | ||
691 | |||
692 | #[test] | ||
693 | fn test_parse_macro_def_rules() { | ||
694 | mark::check!(parse_macro_def_rules); | ||
695 | |||
696 | parse_macro2( | ||
697 | r#" | ||
698 | macro foo { | ||
699 | ($id:ident) => { | ||
700 | fn $id() {} | ||
701 | } | ||
702 | } | ||
703 | "#, | ||
704 | ) | ||
705 | .assert_expand_items("foo!(bar);", "fn bar () {}"); | ||
706 | } | ||
707 | |||
678 | // The following tests are port from intellij-rust directly | 708 | // The following tests are port from intellij-rust directly |
679 | // https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt | 709 | // https://github.com/intellij-rust/intellij-rust/blob/c4e9feee4ad46e7953b1948c112533360b6087bb/src/test/kotlin/org/rust/lang/core/macros/RsMacroExpansionTest.kt |
680 | 710 | ||
@@ -1699,95 +1729,122 @@ pub(crate) struct MacroFixture { | |||
1699 | rules: MacroRules, | 1729 | rules: MacroRules, |
1700 | } | 1730 | } |
1701 | 1731 | ||
1702 | impl MacroFixture { | 1732 | pub(crate) struct MacroFixture2 { |
1703 | pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree { | 1733 | rules: MacroDef, |
1704 | self.try_expand_tt(invocation).unwrap() | 1734 | } |
1705 | } | ||
1706 | |||
1707 | fn try_expand_tt(&self, invocation: &str) -> Result<tt::Subtree, ExpandError> { | ||
1708 | let source_file = ast::SourceFile::parse(invocation).tree(); | ||
1709 | let macro_invocation = | ||
1710 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
1711 | |||
1712 | let (invocation_tt, _) = ast_to_token_tree(¯o_invocation.token_tree().unwrap()) | ||
1713 | .ok_or_else(|| ExpandError::ConversionError)?; | ||
1714 | 1735 | ||
1715 | self.rules.expand(&invocation_tt).result() | 1736 | macro_rules! impl_fixture { |
1716 | } | 1737 | ($name:ident) => { |
1738 | impl $name { | ||
1739 | pub(crate) fn expand_tt(&self, invocation: &str) -> tt::Subtree { | ||
1740 | self.try_expand_tt(invocation).unwrap() | ||
1741 | } | ||
1717 | 1742 | ||
1718 | fn assert_expand_err(&self, invocation: &str, err: &ExpandError) { | 1743 | fn try_expand_tt(&self, invocation: &str) -> Result<tt::Subtree, ExpandError> { |
1719 | assert_eq!(self.try_expand_tt(invocation).as_ref(), Err(err)); | 1744 | let source_file = ast::SourceFile::parse(invocation).tree(); |
1720 | } | 1745 | let macro_invocation = |
1746 | source_file.syntax().descendants().find_map(ast::MacroCall::cast).unwrap(); | ||
1721 | 1747 | ||
1722 | fn expand_items(&self, invocation: &str) -> SyntaxNode { | 1748 | let (invocation_tt, _) = ast_to_token_tree(¯o_invocation.token_tree().unwrap()) |
1723 | let expanded = self.expand_tt(invocation); | 1749 | .ok_or_else(|| ExpandError::ConversionError)?; |
1724 | token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node() | ||
1725 | } | ||
1726 | 1750 | ||
1727 | fn expand_statements(&self, invocation: &str) -> SyntaxNode { | 1751 | self.rules.expand(&invocation_tt).result() |
1728 | let expanded = self.expand_tt(invocation); | 1752 | } |
1729 | token_tree_to_syntax_node(&expanded, FragmentKind::Statements).unwrap().0.syntax_node() | ||
1730 | } | ||
1731 | 1753 | ||
1732 | fn expand_expr(&self, invocation: &str) -> SyntaxNode { | 1754 | #[allow(unused)] |
1733 | let expanded = self.expand_tt(invocation); | 1755 | fn assert_expand_err(&self, invocation: &str, err: &ExpandError) { |
1734 | token_tree_to_syntax_node(&expanded, FragmentKind::Expr).unwrap().0.syntax_node() | 1756 | assert_eq!(self.try_expand_tt(invocation).as_ref(), Err(err)); |
1735 | } | 1757 | } |
1736 | 1758 | ||
1737 | fn assert_expand_tt(&self, invocation: &str, expected: &str) { | 1759 | #[allow(unused)] |
1738 | let expansion = self.expand_tt(invocation); | 1760 | fn expand_items(&self, invocation: &str) -> SyntaxNode { |
1739 | assert_eq!(expansion.to_string(), expected); | 1761 | let expanded = self.expand_tt(invocation); |
1740 | } | 1762 | token_tree_to_syntax_node(&expanded, FragmentKind::Items).unwrap().0.syntax_node() |
1763 | } | ||
1741 | 1764 | ||
1742 | fn assert_expand(&self, invocation: &str, expected: &str) { | 1765 | #[allow(unused)] |
1743 | let expansion = self.expand_tt(invocation); | 1766 | fn expand_statements(&self, invocation: &str) -> SyntaxNode { |
1744 | let actual = format!("{:?}", expansion); | 1767 | let expanded = self.expand_tt(invocation); |
1745 | test_utils::assert_eq_text!(&expected.trim(), &actual.trim()); | 1768 | token_tree_to_syntax_node(&expanded, FragmentKind::Statements) |
1746 | } | 1769 | .unwrap() |
1770 | .0 | ||
1771 | .syntax_node() | ||
1772 | } | ||
1747 | 1773 | ||
1748 | fn assert_expand_items(&self, invocation: &str, expected: &str) -> &MacroFixture { | 1774 | #[allow(unused)] |
1749 | self.assert_expansion(FragmentKind::Items, invocation, expected); | 1775 | fn expand_expr(&self, invocation: &str) -> SyntaxNode { |
1750 | self | 1776 | let expanded = self.expand_tt(invocation); |
1751 | } | 1777 | token_tree_to_syntax_node(&expanded, FragmentKind::Expr).unwrap().0.syntax_node() |
1778 | } | ||
1752 | 1779 | ||
1753 | fn assert_expand_statements(&self, invocation: &str, expected: &str) -> &MacroFixture { | 1780 | #[allow(unused)] |
1754 | self.assert_expansion(FragmentKind::Statements, invocation, expected); | 1781 | fn assert_expand_tt(&self, invocation: &str, expected: &str) { |
1755 | self | 1782 | let expansion = self.expand_tt(invocation); |
1756 | } | 1783 | assert_eq!(expansion.to_string(), expected); |
1784 | } | ||
1757 | 1785 | ||
1758 | fn assert_expansion(&self, kind: FragmentKind, invocation: &str, expected: &str) { | 1786 | #[allow(unused)] |
1759 | let expanded = self.expand_tt(invocation); | 1787 | fn assert_expand(&self, invocation: &str, expected: &str) { |
1760 | assert_eq!(expanded.to_string(), expected); | 1788 | let expansion = self.expand_tt(invocation); |
1761 | 1789 | let actual = format!("{:?}", expansion); | |
1762 | let expected = expected.replace("$crate", "C_C__C"); | 1790 | test_utils::assert_eq_text!(&expected.trim(), &actual.trim()); |
1763 | 1791 | } | |
1764 | // wrap the given text to a macro call | ||
1765 | let expected = { | ||
1766 | let wrapped = format!("wrap_macro!( {} )", expected); | ||
1767 | let wrapped = ast::SourceFile::parse(&wrapped); | ||
1768 | let wrapped = | ||
1769 | wrapped.tree().syntax().descendants().find_map(ast::TokenTree::cast).unwrap(); | ||
1770 | let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0; | ||
1771 | wrapped.delimiter = None; | ||
1772 | wrapped | ||
1773 | }; | ||
1774 | 1792 | ||
1775 | let expanded_tree = token_tree_to_syntax_node(&expanded, kind).unwrap().0.syntax_node(); | 1793 | fn assert_expand_items(&self, invocation: &str, expected: &str) -> &$name { |
1776 | let expanded_tree = debug_dump_ignore_spaces(&expanded_tree).trim().to_string(); | 1794 | self.assert_expansion(FragmentKind::Items, invocation, expected); |
1795 | self | ||
1796 | } | ||
1777 | 1797 | ||
1778 | let expected_tree = token_tree_to_syntax_node(&expected, kind).unwrap().0.syntax_node(); | 1798 | #[allow(unused)] |
1779 | let expected_tree = debug_dump_ignore_spaces(&expected_tree).trim().to_string(); | 1799 | fn assert_expand_statements(&self, invocation: &str, expected: &str) -> &$name { |
1800 | self.assert_expansion(FragmentKind::Statements, invocation, expected); | ||
1801 | self | ||
1802 | } | ||
1780 | 1803 | ||
1781 | let expected_tree = expected_tree.replace("C_C__C", "$crate"); | 1804 | fn assert_expansion(&self, kind: FragmentKind, invocation: &str, expected: &str) { |
1782 | assert_eq!( | 1805 | let expanded = self.expand_tt(invocation); |
1783 | expanded_tree, expected_tree, | 1806 | assert_eq!(expanded.to_string(), expected); |
1784 | "\nleft:\n{}\nright:\n{}", | 1807 | |
1785 | expanded_tree, expected_tree, | 1808 | let expected = expected.replace("$crate", "C_C__C"); |
1786 | ); | 1809 | |
1787 | } | 1810 | // wrap the given text to a macro call |
1811 | let expected = { | ||
1812 | let wrapped = format!("wrap_macro!( {} )", expected); | ||
1813 | let wrapped = ast::SourceFile::parse(&wrapped); | ||
1814 | let wrapped = wrapped | ||
1815 | .tree() | ||
1816 | .syntax() | ||
1817 | .descendants() | ||
1818 | .find_map(ast::TokenTree::cast) | ||
1819 | .unwrap(); | ||
1820 | let mut wrapped = ast_to_token_tree(&wrapped).unwrap().0; | ||
1821 | wrapped.delimiter = None; | ||
1822 | wrapped | ||
1823 | }; | ||
1824 | |||
1825 | let expanded_tree = | ||
1826 | token_tree_to_syntax_node(&expanded, kind).unwrap().0.syntax_node(); | ||
1827 | let expanded_tree = debug_dump_ignore_spaces(&expanded_tree).trim().to_string(); | ||
1828 | |||
1829 | let expected_tree = | ||
1830 | token_tree_to_syntax_node(&expected, kind).unwrap().0.syntax_node(); | ||
1831 | let expected_tree = debug_dump_ignore_spaces(&expected_tree).trim().to_string(); | ||
1832 | |||
1833 | let expected_tree = expected_tree.replace("C_C__C", "$crate"); | ||
1834 | assert_eq!( | ||
1835 | expanded_tree, expected_tree, | ||
1836 | "\nleft:\n{}\nright:\n{}", | ||
1837 | expanded_tree, expected_tree, | ||
1838 | ); | ||
1839 | } | ||
1840 | } | ||
1841 | }; | ||
1788 | } | 1842 | } |
1789 | 1843 | ||
1790 | fn parse_macro_to_tt(ra_fixture: &str) -> tt::Subtree { | 1844 | impl_fixture!(MacroFixture); |
1845 | impl_fixture!(MacroFixture2); | ||
1846 | |||
1847 | fn parse_macro_rules_to_tt(ra_fixture: &str) -> tt::Subtree { | ||
1791 | let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap(); | 1848 | let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap(); |
1792 | let macro_definition = | 1849 | let macro_definition = |
1793 | source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap(); | 1850 | source_file.syntax().descendants().find_map(ast::MacroRules::cast).unwrap(); |
@@ -1804,14 +1861,36 @@ fn parse_macro_to_tt(ra_fixture: &str) -> tt::Subtree { | |||
1804 | definition_tt | 1861 | definition_tt |
1805 | } | 1862 | } |
1806 | 1863 | ||
1864 | fn parse_macro_def_to_tt(ra_fixture: &str) -> tt::Subtree { | ||
1865 | let source_file = ast::SourceFile::parse(ra_fixture).ok().unwrap(); | ||
1866 | let macro_definition = | ||
1867 | source_file.syntax().descendants().find_map(ast::MacroDef::cast).unwrap(); | ||
1868 | |||
1869 | let (definition_tt, _) = ast_to_token_tree(¯o_definition.body().unwrap()).unwrap(); | ||
1870 | |||
1871 | let parsed = | ||
1872 | parse_to_token_tree(&ra_fixture[macro_definition.body().unwrap().syntax().text_range()]) | ||
1873 | .unwrap() | ||
1874 | .0; | ||
1875 | assert_eq!(definition_tt, parsed); | ||
1876 | |||
1877 | definition_tt | ||
1878 | } | ||
1879 | |||
1807 | pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture { | 1880 | pub(crate) fn parse_macro(ra_fixture: &str) -> MacroFixture { |
1808 | let definition_tt = parse_macro_to_tt(ra_fixture); | 1881 | let definition_tt = parse_macro_rules_to_tt(ra_fixture); |
1809 | let rules = MacroRules::parse(&definition_tt).unwrap(); | 1882 | let rules = MacroRules::parse(&definition_tt).unwrap(); |
1810 | MacroFixture { rules } | 1883 | MacroFixture { rules } |
1811 | } | 1884 | } |
1812 | 1885 | ||
1886 | pub(crate) fn parse_macro2(ra_fixture: &str) -> MacroFixture2 { | ||
1887 | let definition_tt = parse_macro_def_to_tt(ra_fixture); | ||
1888 | let rules = MacroDef::parse(&definition_tt).unwrap(); | ||
1889 | MacroFixture2 { rules } | ||
1890 | } | ||
1891 | |||
1813 | pub(crate) fn parse_macro_error(ra_fixture: &str) -> ParseError { | 1892 | pub(crate) fn parse_macro_error(ra_fixture: &str) -> ParseError { |
1814 | let definition_tt = parse_macro_to_tt(ra_fixture); | 1893 | let definition_tt = parse_macro_rules_to_tt(ra_fixture); |
1815 | 1894 | ||
1816 | match MacroRules::parse(&definition_tt) { | 1895 | match MacroRules::parse(&definition_tt) { |
1817 | Ok(_) => panic!("Expect error"), | 1896 | Ok(_) => panic!("Expect error"), |