Skip to content

Commit 8f22dda

Browse files
author
Max Brunsfeld
authored
Merge pull request #3 from tree-sitter/macro-rules
Support for 'macro_rules!' expr
2 parents ffbef27 + 9687765 commit 8f22dda

File tree

5 files changed

+108325
-51754
lines changed

5 files changed

+108325
-51754
lines changed

.eslintrc.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@
1111
"seq": true,
1212
"optional": true,
1313
"choice": true,
14+
"alias": true,
1415
"repeat": true,
1516
"repeat1": true
1617
},

corpus/source_files.txt

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -45,3 +45,50 @@ vec![0; 100];
4545
(number_literal) (number_literal) (number_literal)))
4646
(macro_invocation (macro_name) (macro_arguments
4747
(number_literal) (number_literal))))
48+
49+
============================================
50+
Macro definition
51+
============================================
52+
53+
macro_rules! say_hello {
54+
() => (
55+
println!("Hello!");
56+
)
57+
}
58+
59+
macro_rules! four {
60+
() => {1 + 3};
61+
}
62+
63+
macro_rules! foo {
64+
(x => $e:expr) => (println!("mode X: {}", $e));
65+
(y => $e:expr) => (println!("mode Y: {}", $e))
66+
}
67+
68+
macro_rules! o_O {
69+
(
70+
$($x:expr; [ $( $y:expr ),* ]);*
71+
) => {
72+
$($($x + $e),*),*
73+
}
74+
}
75+
76+
----
77+
78+
(source_file
79+
(expr_macro_rules (identifier) (macro_rule
80+
(matcher)
81+
(transcriber (non_special_token) (non_special_token) (non_special_token))))
82+
(expr_macro_rules (identifier) (macro_rule
83+
(matcher)
84+
(transcriber (non_special_token))))
85+
(expr_macro_rules (identifier)
86+
(macro_rule
87+
(matcher (non_special_token) (metavariable) (fragment_specifier))
88+
(transcriber (non_special_token) (non_special_token) (non_special_token) (metavariable)))
89+
(macro_rule
90+
(matcher (non_special_token) (metavariable) (fragment_specifier))
91+
(transcriber (non_special_token) (non_special_token) (non_special_token) (metavariable))))
92+
(expr_macro_rules (identifier) (macro_rule
93+
(matcher (non_special_token) (metavariable) (fragment_specifier) (non_special_token) (non_special_token) (non_special_token) (metavariable) (fragment_specifier) (non_special_token) (non_special_token) (non_special_token))
94+
(transcriber (non_special_token) (metavariable) (non_special_token) (metavariable) (non_special_token)))))

grammar.js

Lines changed: 69 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,71 @@ module.exports = grammar({
3131
$._declaration_statement,
3232
$._expression_statement,
3333
$._control_flow_statement,
34+
$.expr_macro_rules,
3435
$.macro_invocation,
3536
$.empty_statement
3637
),
3738

39+
expr_macro_rules: $ => {
40+
const rules = seq(
41+
repeat(seq($.macro_rule, ';')),
42+
optional($.macro_rule)
43+
)
44+
45+
return seq(
46+
'macro_rules!',
47+
$.identifier,
48+
choice(
49+
seq('(', rules, ')', ';'),
50+
seq('{', rules, '}')
51+
)
52+
)
53+
},
54+
55+
macro_rule: $ => seq(
56+
$.matcher,
57+
'=>',
58+
$.transcriber
59+
),
60+
61+
matcher: $ => choice(
62+
seq('(', repeat($._matcher), ')'),
63+
seq('[', repeat($._matcher), ']'),
64+
seq('{', repeat($._matcher), '}')
65+
),
66+
67+
_matcher: $ => choice(
68+
seq('(', repeat($._matcher), ')'),
69+
seq('[', repeat($._matcher), ']'),
70+
seq('{', repeat($._matcher), '}'),
71+
seq($.metavariable, ':', $.fragment_specifier),
72+
seq('$', '(', repeat($._matcher), ')', optional(/[^+*]+/), choice('+', '*')),
73+
$.non_special_token
74+
),
75+
76+
fragment_specifier: $ => choice(
77+
'ident', 'path', 'expr', 'ty', 'pat', 'stmt', 'block', 'item', 'meta', 'tt'
78+
),
79+
80+
transcriber: $ => choice(
81+
seq('(', repeat($._transcriber), ')'),
82+
seq('[', repeat($._transcriber), ']'),
83+
seq('{', repeat($._transcriber), '}')
84+
),
85+
86+
_transcriber: $ => prec.left(-1, choice(
87+
seq('(', repeat($._transcriber), ')'),
88+
seq('[', repeat($._transcriber), ']'),
89+
seq('{', repeat($._transcriber), '}'),
90+
seq('$', '(', repeat($._transcriber), ')', optional(/[^+*]+/), choice('+', '*')),
91+
$._statement,
92+
$._expression,
93+
seq($._expression, $.non_special_token, $._expression),
94+
$.non_special_token
95+
)),
96+
97+
non_special_token: $ => /[^\(\)\[\]{}$]+/,
98+
3899
macro_invocation: $ => prec.right(seq(
39100
$.macro_name,
40101
$.macro_arguments,
@@ -81,7 +142,7 @@ module.exports = grammar({
81142
$.struct_item,
82143
$.type_item,
83144
$.function_item,
84-
$.impl_item,
145+
$.impl_item
85146
),
86147

87148
attribute_item: $ => seq(
@@ -313,10 +374,10 @@ module.exports = grammar({
313374

314375
mutable_specifier: $ => 'mut',
315376

316-
_expression_statement: $ => seq(
377+
_expression_statement: $ => prec.right(seq(
317378
$._expression,
318379
';'
319-
),
380+
)),
320381

321382
_expression: $ => choice(
322383
$._no_struct_literal_expr,
@@ -345,6 +406,7 @@ module.exports = grammar({
345406
$.break_expression,
346407
$.continue_expression,
347408
$._index_expression,
409+
$.metavariable,
348410
seq('(', $._expression, ')')
349411
)),
350412

@@ -503,9 +565,9 @@ module.exports = grammar({
503565

504566
loop_label: $ => seq('\'', $.identifier),
505567

506-
break_expression: $ => seq('break', optional($.loop_label)),
568+
break_expression: $ => prec.left(seq('break', optional($.loop_label))),
507569

508-
continue_expression: $ => seq('continue', optional($.loop_label)),
570+
continue_expression: $ => prec.left(seq('continue', optional($.loop_label))),
509571

510572
_index_expression: $ => seq($._expression, '[', $._expression, ']'),
511573

@@ -636,6 +698,8 @@ module.exports = grammar({
636698

637699
super: $ => 'super',
638700

701+
metavariable: $ => /\$[a-zA-Z_]\w*/,
702+
639703
empty_statement: $ => ';'
640704
}
641705
})

0 commit comments

Comments
 (0)