Skip to content

Commit 934bc6e

Browse files
committed
Attributes on expressions
Added 'rustc-tests' for attributes on expressions and, along the way, added support for inner attributes in a bunch of places. Also bumped support of 'rustc' to the latest (stable) version. Will need to switch to nightly or beta soon though...
1 parent 58dcba3 commit 934bc6e

File tree

8 files changed

+186
-38
lines changed

8 files changed

+186
-38
lines changed

sample-sources/attributes.rs

Lines changed: 119 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,119 @@
1+
fn main () {
2+
match x {
3+
#[arm_outer]
4+
0 => true,
5+
}
6+
}
7+
8+
fn expressions() {
9+
#[box_outer]
10+
box 1;
11+
12+
// #[inplace_outer]
13+
// x <- 1;
14+
15+
#[vec_outer]
16+
[ #![vec_inner] 1, 2, 3];
17+
18+
#[call_outer]
19+
foo(1, 2, 3);
20+
21+
#[methodcall_outer]
22+
x.foo(1, 2, 3);
23+
24+
#[tuple_outer]
25+
( #![tuple_inner] 1, 2, 3);
26+
#[tuple_outer]
27+
( #![tuple_inner] 1, );
28+
#[tuple_outer]
29+
( #![tuple_inner] );
30+
31+
// #[binary_outer]
32+
// 1 + 2;
33+
34+
#[unary_outer]
35+
-1;
36+
37+
#[lit_outer]
38+
1;
39+
40+
// #[cast_outer]
41+
// 1 as f64;
42+
43+
// #[typeascription_outer]
44+
// 1: f32;
45+
46+
// #[if_outer]
47+
// if (true) {
48+
// 1;
49+
// }
50+
51+
// #[iflet_outer]
52+
// if let x = true {
53+
// 1;
54+
// }
55+
56+
#[while_outer]
57+
while (true) {
58+
#![while_inner]
59+
1;
60+
}
61+
62+
#[whilelet_outer]
63+
while let x = true {
64+
#![whilelet_inner]
65+
1;
66+
}
67+
68+
#[for_outer]
69+
for i in 1..3 {
70+
#![for_inner]
71+
1;
72+
}
73+
74+
#[loop_outer]
75+
loop {
76+
#![loop_inner]
77+
1;
78+
}
79+
80+
#[match_outer]
81+
match x {
82+
#![match_inner]
83+
_ => 1
84+
}
85+
86+
#[closure_outer]
87+
move |x| { 1 + 2 };
88+
89+
#[blockexpr_outer]
90+
{ #![blockexpr_inner] 1; 2 }
91+
#[blockexpr_outer]
92+
unsafe { #![blockexpr_inner] 1; 2 }
93+
94+
// #[catch_outer] UPDATE RUSTC
95+
// do catch { #![catch_inner] 1 }
96+
97+
// #[assign_outer]
98+
// x = 1;
99+
100+
// #[assignop_outer]
101+
// x += 1;
102+
103+
#[fieldaccess_outer]
104+
x.foo;
105+
106+
#[tupfield_outer]
107+
x.0;
108+
109+
#[index_outer]
110+
x[0];
111+
112+
// #[range_outer]
113+
// 1..2;
114+
115+
#[pathexpr_outer]
116+
math::PI;
117+
118+
}
119+

sample-sources/precedences.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,25 +37,29 @@ fn range_expressions() {
3737
// general expression
3838
let _ = ..Point { x: 1 };
3939
let _ = ..{};
40+
let _ = |x| { 1 };
4041

4142
// non-block expression
4243
..Point { x: 1 };
4344
..{};
4445
- { 1 };
4546
return |x: i32| x + 1;
4647
box 1 + 2;
48+
|x| { 1 };
4749

4850
// no struct expression
4951
for x in 1.. { }
5052
for x in ..1 { }
5153
for x in ..Point{} { }
5254
for x in .. { }
5355
for x in {}.. { }
56+
for x in |x| { 1 } { }
5457

5558
// no struct/block expression (to the right of '..')
5659
for x in ..1 { }
5760
for x in ..1 + 1 { }
5861
for x in ..1 + { 2 } { }
62+
for x in ..|x| { 1 } { }
5963

6064
// precedences of ranges in general
6165
fn general_ranges() {

src/Language/Rust/Parser/Internal.y

Lines changed: 55 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,7 @@ gen_expression(lhs,rhs,rhs2) :: { Expr Span }
864864
: ntExpr { $1 }
865865
| lit_expr { $1 }
866866
| '[' sep_byT(expr,',') ']' { Vec [] $2 ($1 # $>) }
867+
| '[' inner_attrs sep_byT(expr,',') ']' { Vec (toList $2) $3 ($1 # $>) }
867868
| '[' expr ';' expr ']' { Repeat [] $2 $4 ($1 # $>) }
868869
| expr_mac { MacExpr [] $1 (spanOf $1) }
869870
| expr_path %prec PATH { PathExpr [] Nothing $1 (spanOf $1) }
@@ -1000,24 +1001,26 @@ lit_expr :: { Expr Span }
10001001
-- one to omit the separating ';' after 'if', 'match', 'loop', 'for', 'while'"
10011002
block_expr :: { Expr Span }
10021003
: block_like_expr { $1 }
1003-
| block { BlockExpr [] $1 (spanOf $1) }
1004+
| inner_attrs_block { let (as,b) = $1 in BlockExpr as b (spanOf b) }
10041005

10051006
-- Any expression ending in a '{ ... }' block except a block itself.
10061007
block_like_expr :: { Expr Span }
10071008
: if_expr { $1 }
1008-
| loop block { Loop [] $2 Nothing ($1 # $>) }
1009-
| lifetime ':' loop block { Loop [] $4 (Just $1) ($1 # $>) }
1010-
| for pat in nostruct_expr block { ForLoop [] $2 $4 $5 Nothing ($1 # $>) }
1011-
| lifetime ':' for pat in nostruct_expr block { ForLoop [] $4 $6 $7 (Just $1) ($1 # $>) }
1012-
| while nostruct_expr block { While [] $2 $3 Nothing ($1 # $>) }
1013-
| lifetime ':' while nostruct_expr block { While [] $4 $5 (Just $1) ($1 # $>) }
1014-
| while let pat '=' nostruct_expr block { WhileLet [] $3 $5 $6 Nothing ($1 # $>) }
1015-
| lifetime ':' while let pat '=' nostruct_expr block { WhileLet [] $5 $7 $8 (Just $1) ($1 # $>) }
1016-
| match nostruct_expr '{' '}' { Match [] $2 [] ($1 # $>) }
1017-
| match nostruct_expr '{' arms '}' { Match [] $2 $4 ($1 # $>) }
1009+
| loop inner_attrs_block { let (as,b) = $> in Loop as b Nothing ($1 # b) }
1010+
| lifetime ':' loop inner_attrs_block { let (as,b) = $> in Loop as b (Just $1) ($1 # b) }
1011+
| for pat in nostruct_expr inner_attrs_block { let (as,b) = $> in ForLoop as $2 $4 b Nothing ($1 # b) }
1012+
| lifetime ':' for pat in nostruct_expr inner_attrs_block { let (as,b) = $> in ForLoop as $4 $6 b (Just $1) ($1 # b) }
1013+
| while nostruct_expr inner_attrs_block { let (as,b) = $> in While as $2 b Nothing ($1 # b) }
1014+
| lifetime ':' while nostruct_expr inner_attrs_block { let (as,b) = $> in While as $4 b (Just $1) ($1 # b) }
1015+
| while let pat '=' nostruct_expr inner_attrs_block { let (as,b) = $> in WhileLet as $3 $5 b Nothing ($1 # b) }
1016+
| lifetime ':' while let pat '=' nostruct_expr inner_attrs_block { let (as,b) = $> in WhileLet as $5 $7 b (Just $1) ($1 # b) }
1017+
| match nostruct_expr '{' '}' { Match [] $2 [] ($1 # $>) }
1018+
| match nostruct_expr '{' inner_attrs '}' { Match (toList $4) $2 [] ($1 # $>) }
1019+
| match nostruct_expr '{' arms '}' { Match [] $2 $4 ($1 # $>) }
1020+
| match nostruct_expr '{' inner_attrs arms '}' { Match (toList $4) $2 $5 ($1 # $>) }
10181021
| expr_path '!' '{' many(token_tree) '}' { MacExpr [] (Mac $1 $4 ($1 # $>)) ($1 # $>) }
1019-
| unsafe block { BlockExpr [] $2{ rules = Unsafe } ($1 # $>) }
1020-
| do catch block { Catch [] $3 ($1 # $>) }
1022+
| unsafe inner_attrs_block { let (as,b) = $> in BlockExpr as b{ rules = Unsafe } ($1 # b) }
1023+
| do catch inner_attrs_block { let (as,b) = $> in Catch as b ($1 # b) }
10211024

10221025
-- 'if' expressions are a bit special since they can have an arbitrary number of 'else if' chains.
10231026
if_expr :: { Expr Span }
@@ -1053,18 +1056,21 @@ expr_arms :: { (Expr Span, [Arm Span]) }
10531056
| paren_expr comma_arms { ($1, $2) }
10541057
| struct_expr comma_arms { ($1, $2) }
10551058
| block_like_expr comma_arms { ($1, $2) }
1056-
| block comma_arms { (BlockExpr [] $1 (spanOf $1), $2) }
1057-
| block arms { (BlockExpr [] $1 (spanOf $1), $2) }
1059+
| inner_attrs_block comma_arms { let (as,b) = $1 in (BlockExpr as b (spanOf b), $2) }
1060+
| inner_attrs_block arms { let (as,b) = $1 in (BlockExpr as b (spanOf b), $2) }
10581061

10591062

10601063
-- As per https://github.com/rust-lang/rust/issues/15701 (as of March 10 2017), the only way to have
10611064
-- attributes on expressions should be with inner attributes on a paren expression.
10621065
paren_expr :: { Expr Span }
1063-
: '(' ')' { TupExpr [] [] ($1 # $2) }
1064-
| '(' expr ')' { ParenExpr [] $2 ($1 # $3) }
1065-
| '(' inner_attrs expr ')' { ParenExpr (toList $2) $3 ($1 # $4) }
1066-
| '(' expr ',' ')' { TupExpr [] [$2] ($1 # $4) }
1067-
| '(' expr ',' sep_by1T(expr,',') ')' { TupExpr [] ($2 : toList $4) ($1 # $5) }
1066+
: '(' ')' { TupExpr [] [] ($1 # $>) }
1067+
| '(' inner_attrs ')' { TupExpr (toList $2) [] ($1 # $>) }
1068+
| '(' expr ')' { ParenExpr [] $2 ($1 # $>) }
1069+
| '(' inner_attrs expr ')' { ParenExpr (toList $2) $3 ($1 # $>) }
1070+
| '(' expr ',' ')' { TupExpr [] [$2] ($1 # $>) }
1071+
| '(' inner_attrs expr ',' ')' { TupExpr (toList $2) [$3] ($1 # $>) }
1072+
| '(' expr ',' sep_by1T(expr,',') ')' { TupExpr [] ($2 : toList $4) ($1 # $>) }
1073+
| '(' inner_attrs expr ',' sep_by1T(expr,',') ')' { TupExpr (toList $2) ($3 : toList $5) ($1 # $>) }
10681074

10691075

10701076
-- Closure ending in blocks
@@ -1087,9 +1093,12 @@ arg :: { Arg Span }
10871093

10881094
-- Struct expression literal
10891095
struct_expr :: { Expr Span }
1090-
: expr_path '{' '..' expr '}' { Struct [] $1 [] (Just $4) ($1 # $>) }
1091-
| expr_path '{' sep_by1(field,',') ',' '..' expr '}' { Struct [] $1 (toList $3) (Just $6) ($1 # $>) }
1092-
| expr_path '{' sep_byT(field,',') '}' { Struct [] $1 $3 Nothing ($1 # $>) }
1096+
: expr_path '{' '..' expr '}' { Struct [] $1 [] (Just $4) ($1 # $>) }
1097+
| expr_path '{' inner_attrs '..' expr '}' { Struct (toList $3) $1 [] (Just $5) ($1 # $>) }
1098+
| expr_path '{' sep_by1(field,',') ',' '..' expr '}' { Struct [] $1 (toList $3) (Just $6) ($1 # $>) }
1099+
| expr_path '{' inner_attrs sep_by1(field,',') ',' '..' expr '}' { Struct (toList $3) $1 (toList $4) (Just $7) ($1 # $>) }
1100+
| expr_path '{' sep_byT(field,',') '}' { Struct [] $1 $3 Nothing ($1 # $>) }
1101+
| expr_path '{' inner_attrs sep_byT(field,',') '}' { Struct (toList $3) $1 $4 Nothing ($1 # $>) }
10931102
10941103
field :: { Field Span }
10951104
: ident ':' expr { Field (unspan $1) (Just $3) ($1 # $3) }
@@ -1126,14 +1135,14 @@ initializer :: { Maybe (Expr Span) }
11261135
11271136
11281137
block :: { Block Span }
1129-
: ntBlock { $1 }
1130-
| '{' '}' { Block [] Normal ($1 # $>) }
1131-
| '{' stmts_possibly_no_semi '}' { Block [ s | Just s <- $2 ] Normal ($1 # $>) }
1138+
: ntBlock { $1 }
1139+
| '{' '}' { Block [] Normal ($1 # $>) }
1140+
| '{' stmts_possibly_no_semi '}' { Block [ s | Just s <- $2 ] Normal ($1 # $>) }
11321141
11331142
inner_attrs_block :: { ([Attribute Span], Block Span) }
1134-
: block { ([], $1) }
1135-
| '{' inner_attrs '}' { (toList $2, Block [] Normal ($1 # $>)) }
1136-
| '{' inner_attrs stmts_possibly_no_semi '}' { (toList $2, Block [ s | Just s <- $3 ] Normal ($1 # $>)) }
1143+
: block { ([], $1) }
1144+
| '{' inner_attrs '}' { (toList $2, Block [] Normal ($1 # $>)) }
1145+
| '{' inner_attrs stmts_possibly_no_semi '}' { (toList $2, Block [ s | Just s <- $3 ] Normal ($1 # $>)) }
11371146
11381147
11391148
-----------
@@ -1143,12 +1152,20 @@ inner_attrs_block :: { ([Attribute Span], Block Span) }
11431152
item :: { Item Span }
11441153
: ntItem { $1 }
11451154
| stmt_item { $1 }
1146-
| expr_path '!' ident '[' many(token_tree) ']' ';' { Item (unspan $3) [] (MacItem (Mac $1 $5 ($1 # $>))) InheritedV ($1 # $>) }
1155+
| expr_path '!' ident '[' many(token_tree) ']' ';' { macroItem (unspan $3) (Mac $1 $5 ($1 # $>)) ($1 # $>) }
1156+
| expr_path '!' '[' many(token_tree) ']' ';' { macroItem "" (Mac $1 $4 ($1 # $>)) ($1 # $>) }
1157+
| expr_path '!' ident '(' many(token_tree) ')' ';' { macroItem (unspan $3) (Mac $1 $5 ($1 # $>)) ($1 # $>) }
1158+
| expr_path '!' '(' many(token_tree) ')' ';' { macroItem "" (Mac $1 $4 ($1 # $>)) ($1 # $>) }
1159+
| expr_path '!' ident '{' many(token_tree) '}' { macroItem (unspan $3) (Mac $1 $5 ($1 # $>)) ($1 # $>) }
1160+
| expr_path '!' '{' many(token_tree) '}' { macroItem "" (Mac $1 $4 ($1 # $>)) ($1 # $>) }
1161+
1162+
{- | expr_path '!' ident '[' many(token_tree) ']' ';' { Item (unspan $3) [] (MacItem (Mac $1 $5 ($1 # $>))) InheritedV ($1 # $>) }
11471163
| expr_path '!' '[' many(token_tree) ']' ';' { Item "" [] (MacItem (Mac $1 $4 ($1 # $>))) InheritedV ($1 # $>) }
11481164
| expr_path '!' ident '(' many(token_tree) ')' ';' { Item (unspan $3) [] (MacItem (Mac $1 $5 ($1 # $>))) InheritedV ($1 # $>) }
11491165
| expr_path '!' '(' many(token_tree) ')' ';' { Item "" [] (MacItem (Mac $1 $4 ($1 # $>))) InheritedV ($1 # $>) }
11501166
| expr_path '!' ident '{' many(token_tree) '}' { Item (unspan $3) [] (MacItem (Mac $1 $5 ($1 # $>))) InheritedV ($1 # $>) }
11511167
| expr_path '!' '{' many(token_tree) '}' { Item "" [] (MacItem (Mac $1 $4 ($1 # $>))) InheritedV ($1 # $>) }
1168+
-}
11521169
11531170
mod_item :: { Item Span }
11541171
: many(outer_attribute) vis item { let Item i a n _ _ = $3 in Item i ($1 ++ a) n (unspan $2) ($1 # $2 # $3) }
@@ -1487,6 +1504,7 @@ token :: { Spanned Token }
14871504
-- Weak keywords, have special meaning only in specific contexts.
14881505
| default { $1 }
14891506
| union { $1 }
1507+
| catch { $1 }
14901508
-- Comments
14911509
| outerDoc { $1 }
14921510
| innerDoc { $1 }
@@ -1543,6 +1561,11 @@ toStmt (MacExpr a m s) hasSemi isBlock | hasSemi = MacStmt m SemicolonMac a
15431561
| isBlock = MacStmt m BracesMac a
15441562
toStmt e hasSemi _ = (if hasSemi then Semi else NoSemi) e
15451563
1564+
-- | Make a macro item, which may be a 'MacroDef'
1565+
macroItem :: Ident -> Mac Span -> Span -> Item Span
1566+
macroItem i (Mac (Path False (("macro_rules", NoParameters _) :| []) _) tts _) x = Item i [] (MacroDef tts) InheritedV x
1567+
macroItem i mac x = Item i [] (MacItem mac) InheritedV x
1568+
15461569
-- | Add attributes to an expression
15471570
addAttrs :: [Attribute Span] -> Expr Span -> Expr Span
15481571
addAttrs as (Box as' e s) = Box (as ++ as') e s
@@ -1565,6 +1588,7 @@ addAttrs as (Loop as' b l s) = Loop (as ++ as') b l s
15651588
addAttrs as (Match as' e a s) = Match (as ++ as') e a s
15661589
addAttrs as (Closure as' c f e s) = Closure (as ++ as') c f e s
15671590
addAttrs as (BlockExpr as' b s) = BlockExpr (as ++ as') b s
1591+
addAttrs as (Catch as' b s) = Catch (as ++ as') b s
15681592
addAttrs as (Assign as' e1 e2 s) = Assign (as ++ as') e1 e2 s
15691593
addAttrs as (AssignOp as' b e1 e2 s) = AssignOp (as ++ as') b e1 e2 s
15701594
addAttrs as (FieldAccess as' e i s) = FieldAccess (as ++ as') e i s
@@ -1573,7 +1597,7 @@ addAttrs as (Index as' e1 e2 s) = Index (as ++ as') e1 e2 s
15731597
addAttrs as (Range as' e1 e2 r s) = Range (as ++ as') e1 e2 r s
15741598
addAttrs as (PathExpr as' q p s) = PathExpr (as ++ as') q p s
15751599
addAttrs as (AddrOf as' m e s) = AddrOf (as ++ as') m e s
1576-
addAttrs as (Break as' l e s) = Break (as ++ as') l e s
1600+
addAttrs as (Break as' l e s) = Break (as ++ as') l e s
15771601
addAttrs as (Continue as' l s) = Continue (as ++ as') l s
15781602
addAttrs as (Ret as' e s) = Ret (as ++ as') e s
15791603
addAttrs as (InlineAsmExpr as' a s) = InlineAsmExpr (as ++ as') a s

src/Language/Rust/Pretty/Internal.hs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -751,7 +751,7 @@ printItem (Item ident attrs node vis x) = annotate x $ align $ printOuterAttrs a
751751
WL.Empty -> leading <+> lagging
752752
_ -> leading <#> wc <#> lagging
753753
MacItem m -> printMac m Paren <> ";"
754-
754+
MacroDef tts -> "macro_rules" <> "!" <+> printIdent ident <+> block Brace True mempty mempty [ printTts tts ]
755755

756756
-- | Print a trait item (@print_trait_item@)
757757
printTraitItem :: TraitItem a -> Doc a

src/Language/Rust/Pretty/Resolve.hs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -955,6 +955,7 @@ resolveItemKind (Impl u p g mt t is) = do
955955
resolveItemKind (DefaultImpl u t) = DefaultImpl u <$> resolveTraitRef t
956956
resolveItemKind (Trait u g bds is) = Trait u <$> resolveGenerics g <*> sequence (resolveTyParamBound NoneBound <$> bds) <*> sequence (resolveTraitItem <$> is)
957957
resolveItemKind (MacItem m) = MacItem <$> resolveMac ExprPath m
958+
resolveItemKind (MacroDef tt) = MacroDef <$> sequence (resolveTt <$> tt)
958959
resolveItemKind (Use v) = Use <$> resolveViewPath v
959960

960961
instance Monoid a => Resolve (ItemKind a) where resolve = resolveItemKind

src/Language/Rust/Syntax/AST.hs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -583,8 +583,11 @@ data ItemKind a
583583
-- Example: @impl\<A\> Foo\<A\> { .. }@ or @impl\<A\> Trait for Foo\<A\> { .. }@
584584
| Impl Unsafety ImplPolarity (Generics a) (Maybe (TraitRef a)) (Ty a) [ImplItem a]
585585
-- | generated from a call to a macro
586-
-- Example: @macro_rules! foo { .. }@ or @foo!(..)@
586+
-- Example: @foo!{ .. }@
587587
| MacItem (Mac a)
588+
-- | definition of a macro via @macro_rules@
589+
-- Example: @macro_rules! foo { .. }@
590+
| MacroDef [TokenTree]
588591
deriving (Eq, Functor, Show, Typeable, Data, Generic)
589592

590593
-- | A Kleene-style repetition operator for token sequences (@syntax::ast::KleeneOp@). This refers
@@ -709,9 +712,6 @@ data IntRep = Bin | Oct | Dec | Hex deriving (Eq, Show, Enum, Bounded, Typeable,
709712

710713
-- | Represents a macro invocation (@syntax::ast::Mac@). The 'Path' indicates which macro is being
711714
-- invoked, and the 'TokenTree's contains the source of the macro invocation.
712-
--
713-
-- Quoted from the source "NB: the additional ident for a macro_rules-style macro is actually
714-
-- stored in the enclosing item. Oog."
715715
data Mac a = Mac (Path a) [TokenTree] a deriving (Eq, Functor, Show, Typeable, Data, Generic)
716716

717717
instance Located a => Located (Mac a) where spanOf (Mac _ _ s) = spanOf s

tests/rustc-tests/Diff.hs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,8 @@ instance Show a => Diffable (Item a) where
8383
is === (n' ! "fields" ! 5)
8484
("Mac", MacItem m) ->
8585
m === (n' ! "fields" ! 0)
86+
("MacroDef", MacroDef tt) ->
87+
tt === (n' ! "fields" ! 0)
8688
_ -> diff "different items" item val
8789

8890
instance Diffable ImplPolarity where

tests/unit-tests/LexerTest.hs

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11,8 +11,6 @@ import Language.Rust.Syntax
1111
import Language.Rust.Data.Position
1212
import Language.Rust.Data.InputStream
1313

14-
import Control.Monad
15-
1614
lexerSuite :: Test
1715
lexerSuite = testGroup "lexer suite" [ commonCode, literals ]
1816

0 commit comments

Comments
 (0)