Skip to content
体验新版
项目
组织
正在加载...
登录
切换导航
打开侧边栏
int
Rust
提交
2fcbb48c
R
Rust
项目概览
int
/
Rust
接近 1 年 前同步成功
通知
1
Star
0
Fork
0
代码
文件
提交
分支
Tags
贡献者
分支图
Diff
Issue
0
列表
看板
标记
里程碑
合并请求
0
DevOps
流水线
流水线任务
计划
Wiki
0
Wiki
分析
仓库
DevOps
项目成员
Pages
R
Rust
项目概览
项目概览
详情
发布
仓库
仓库
文件
提交
分支
标签
贡献者
分支图
比较
Issue
0
Issue
0
列表
看板
标记
里程碑
合并请求
0
合并请求
0
Pages
DevOps
DevOps
流水线
流水线任务
计划
分析
分析
仓库分析
DevOps
Wiki
0
Wiki
成员
成员
收起侧边栏
关闭侧边栏
动态
分支图
创建新Issue
流水线任务
提交
Issue看板
体验新版 GitCode,发现更多精彩内容 >>
提交
2fcbb48c
编写于
2月 27, 2017
作者:
A
Austin Bonander
浏览文件
操作
浏览文件
下载
电子邮件补丁
差异文件
Implement function-like procedural macros ( `#[proc_macro]`)
上级
4be034e6
变更
10
隐藏空白更改
内联
并排
Showing
10 changed file
with
213 addition
and
10 deletion
+213
-10
src/libproc_macro/lib.rs
src/libproc_macro/lib.rs
+4
-0
src/librustc_metadata/creader.rs
src/librustc_metadata/creader.rs
+10
-1
src/libsyntax/feature_gate.rs
src/libsyntax/feature_gate.rs
+5
-0
src/libsyntax_ext/proc_macro_impl.rs
src/libsyntax_ext/proc_macro_impl.rs
+35
-0
src/libsyntax_ext/proc_macro_registrar.rs
src/libsyntax_ext/proc_macro_registrar.rs
+57
-9
src/test/compile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs
...ile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs
+23
-0
src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs
src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs
+21
-0
src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
+12
-0
src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs
...test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs
+26
-0
src/test/run-pass-fulldeps/proc-macro/bang-macro.rs
src/test/run-pass-fulldeps/proc-macro/bang-macro.rs
+20
-0
未找到文件。
src/libproc_macro/lib.rs
浏览文件 @
2fcbb48c
...
...
@@ -125,6 +125,10 @@ fn register_custom_derive(&mut self,
fn
register_attr_proc_macro
(
&
mut
self
,
name
:
&
str
,
expand
:
fn
(
TokenStream
,
TokenStream
)
->
TokenStream
);
fn
register_bang_proc_macro
(
&
mut
self
,
name
:
&
str
,
expand
:
fn
(
TokenStream
)
->
TokenStream
);
}
// Emulate scoped_thread_local!() here essentially
...
...
src/librustc_metadata/creader.rs
浏览文件 @
2fcbb48c
...
...
@@ -586,7 +586,7 @@ fn load_derive_macros(&mut self, root: &CrateRoot, dylib: Option<PathBuf>, span:
use
proc_macro
::
__
internal
::
Registry
;
use
rustc_back
::
dynamic_lib
::
DynamicLibrary
;
use
syntax_ext
::
deriving
::
custom
::
ProcMacroDerive
;
use
syntax_ext
::
proc_macro_impl
::
AttrProcMacro
;
use
syntax_ext
::
proc_macro_impl
::
{
AttrProcMacro
,
BangProcMacro
}
;
let
path
=
match
dylib
{
Some
(
dylib
)
=>
dylib
,
...
...
@@ -630,6 +630,15 @@ fn register_attr_proc_macro(&mut self,
);
self
.0
.push
((
Symbol
::
intern
(
name
),
Rc
::
new
(
expand
)));
}
fn
register_bang_proc_macro
(
&
mut
self
,
name
:
&
str
,
expand
:
fn
(
TokenStream
)
->
TokenStream
)
{
let
expand
=
SyntaxExtension
::
ProcMacro
(
Box
::
new
(
BangProcMacro
{
inner
:
expand
})
);
self
.0
.push
((
Symbol
::
intern
(
name
),
Rc
::
new
(
expand
)));
}
}
let
mut
my_registrar
=
MyRegistrar
(
Vec
::
new
());
...
...
src/libsyntax/feature_gate.rs
浏览文件 @
2fcbb48c
...
...
@@ -763,6 +763,11 @@ pub fn is_builtin_attr(attr: &ast::Attribute) -> bool {
"attribute proc macros are currently unstable"
,
cfg_fn!
(
proc_macro
))),
(
"proc_macro"
,
Normal
,
Gated
(
Stability
::
Unstable
,
"proc_macro"
,
"function-like proc macros are currently unstable"
,
cfg_fn!
(
proc_macro
))),
(
"rustc_derive_registrar"
,
Normal
,
Gated
(
Stability
::
Unstable
,
"rustc_derive_registrar"
,
"used internally by rustc"
,
...
...
src/libsyntax_ext/proc_macro_impl.rs
浏览文件 @
2fcbb48c
...
...
@@ -56,3 +56,38 @@ fn expand<'cx>(&self,
}
}
}
pub
struct
BangProcMacro
{
pub
inner
:
fn
(
TsShim
)
->
TsShim
,
}
impl
base
::
ProcMacro
for
BangProcMacro
{
fn
expand
<
'cx
>
(
&
self
,
ecx
:
&
'cx
mut
ExtCtxt
,
span
:
Span
,
input
:
TokenStream
)
->
TokenStream
{
let
input
=
__
internal
::
token_stream_wrap
(
input
);
let
res
=
__
internal
::
set_parse_sess
(
&
ecx
.parse_sess
,
||
{
panic
::
catch_unwind
(
panic
::
AssertUnwindSafe
(||
(
self
.inner
)(
input
)))
});
match
res
{
Ok
(
stream
)
=>
__
internal
::
token_stream_inner
(
stream
),
Err
(
e
)
=>
{
let
msg
=
"proc macro panicked"
;
let
mut
err
=
ecx
.struct_span_fatal
(
span
,
msg
);
if
let
Some
(
s
)
=
e
.downcast_ref
::
<
String
>
()
{
err
.help
(
&
format!
(
"message: {}"
,
s
));
}
if
let
Some
(
s
)
=
e
.downcast_ref
::
<&
'static
str
>
()
{
err
.help
(
&
format!
(
"message: {}"
,
s
));
}
err
.emit
();
panic!
(
FatalError
);
}
}
}
}
src/libsyntax_ext/proc_macro_registrar.rs
浏览文件 @
2fcbb48c
...
...
@@ -27,6 +27,9 @@
use
deriving
;
const
PROC_MACRO_KINDS
:
[
&
'static
str
;
3
]
=
[
"proc_macro_derive"
,
"proc_macro_attribute"
,
"proc_macro"
];
struct
ProcMacroDerive
{
trait_name
:
ast
::
Name
,
function_name
:
Ident
,
...
...
@@ -34,14 +37,15 @@ struct ProcMacroDerive {
attrs
:
Vec
<
ast
::
Name
>
,
}
struct
AttrProcMacro
{
struct
ProcMacroDef
{
function_name
:
Ident
,
span
:
Span
,
}
struct
CollectProcMacros
<
'a
>
{
derives
:
Vec
<
ProcMacroDerive
>
,
attr_macros
:
Vec
<
AttrProcMacro
>
,
attr_macros
:
Vec
<
ProcMacroDef
>
,
bang_macros
:
Vec
<
ProcMacroDef
>
,
in_root
:
bool
,
handler
:
&
'a
errors
::
Handler
,
is_proc_macro_crate
:
bool
,
...
...
@@ -58,17 +62,18 @@ pub fn modify(sess: &ParseSess,
let
ecfg
=
ExpansionConfig
::
default
(
"proc_macro"
.to_string
());
let
mut
cx
=
ExtCtxt
::
new
(
sess
,
ecfg
,
resolver
);
let
(
derives
,
attr_macros
)
=
{
let
(
derives
,
attr_macros
,
bang_macros
)
=
{
let
mut
collect
=
CollectProcMacros
{
derives
:
Vec
::
new
(),
attr_macros
:
Vec
::
new
(),
bang_macros
:
Vec
::
new
(),
in_root
:
true
,
handler
:
handler
,
is_proc_macro_crate
:
is_proc_macro_crate
,
is_test_crate
:
is_test_crate
,
};
visit
::
walk_crate
(
&
mut
collect
,
&
krate
);
(
collect
.derives
,
collect
.attr_macros
)
(
collect
.derives
,
collect
.attr_macros
,
collect
.bang_macros
)
};
if
!
is_proc_macro_crate
{
...
...
@@ -83,7 +88,7 @@ pub fn modify(sess: &ParseSess,
return
krate
;
}
krate
.module.items
.push
(
mk_registrar
(
&
mut
cx
,
&
derives
,
&
attr_macros
));
krate
.module.items
.push
(
mk_registrar
(
&
mut
cx
,
&
derives
,
&
attr_macros
,
&
bang_macros
));
if
krate
.exported_macros
.len
()
>
0
{
handler
.err
(
"cannot export macro_rules! macros from a `proc-macro`
\
...
...
@@ -93,6 +98,10 @@ pub fn modify(sess: &ParseSess,
return
krate
}
fn
is_proc_macro_attr
(
attr
:
&
ast
::
Attribute
)
->
bool
{
PROC_MACRO_KINDS
.iter
()
.any
(|
kind
|
attr
.check_name
(
kind
))
}
impl
<
'a
>
CollectProcMacros
<
'a
>
{
fn
check_not_pub_in_root
(
&
self
,
vis
:
&
ast
::
Visibility
,
sp
:
Span
)
{
if
self
.is_proc_macro_crate
&&
...
...
@@ -196,12 +205,12 @@ fn collect_custom_derive(&mut self, item: &'a ast::Item, attr: &'a ast::Attribut
fn
collect_attr_proc_macro
(
&
mut
self
,
item
:
&
'a
ast
::
Item
,
attr
:
&
'a
ast
::
Attribute
)
{
if
let
Some
(
_
)
=
attr
.meta_item_list
()
{
self
.handler
.span_err
(
attr
.span
,
"`#[proc_macro_attribute]` attribute
cannot contain any meta item
s"
);
does not take any argument
s"
);
return
;
}
if
self
.in_root
&&
item
.vis
==
ast
::
Visibility
::
Public
{
self
.attr_macros
.push
(
AttrProcMacro
{
self
.attr_macros
.push
(
ProcMacroDef
{
span
:
item
.span
,
function_name
:
item
.ident
,
});
...
...
@@ -215,6 +224,29 @@ fn collect_attr_proc_macro(&mut self, item: &'a ast::Item, attr: &'a ast::Attrib
self
.handler
.span_err
(
item
.span
,
msg
);
}
}
fn
collect_bang_proc_macro
(
&
mut
self
,
item
:
&
'a
ast
::
Item
,
attr
:
&
'a
ast
::
Attribute
)
{
if
let
Some
(
_
)
=
attr
.meta_item_list
()
{
self
.handler
.span_err
(
attr
.span
,
"`#[proc_macro]` attribute
does not take any arguments"
);
return
;
}
if
self
.in_root
&&
item
.vis
==
ast
::
Visibility
::
Public
{
self
.bang_macros
.push
(
ProcMacroDef
{
span
:
item
.span
,
function_name
:
item
.ident
,
});
}
else
{
let
msg
=
if
!
self
.in_root
{
"functions tagged with `#[proc_macro]` must
\
currently reside in the root of the crate"
}
else
{
"functions tagged with `#[proc_macro]` must be `pub`"
};
self
.handler
.span_err
(
item
.span
,
msg
);
}
}
}
impl
<
'a
>
Visitor
<
'a
>
for
CollectProcMacros
<
'a
>
{
...
...
@@ -232,7 +264,7 @@ fn visit_item(&mut self, item: &'a ast::Item) {
let
mut
found_attr
:
Option
<&
'a
ast
::
Attribute
>
=
None
;
for
attr
in
&
item
.attrs
{
if
attr
.check_name
(
"proc_macro_derive"
)
||
attr
.check_name
(
"proc_macro_attribute"
)
{
if
is_proc_macro_attr
(
&
attr
)
{
if
let
Some
(
prev_attr
)
=
found_attr
{
let
msg
=
if
attr
.name
()
==
prev_attr
.name
()
{
format!
(
"Only one `#[{}]` attribute is allowed on any given function"
,
...
...
@@ -285,6 +317,8 @@ fn visit_item(&mut self, item: &'a ast::Item) {
self
.collect_custom_derive
(
item
,
attr
);
}
else
if
attr
.check_name
(
"proc_macro_attribute"
)
{
self
.collect_attr_proc_macro
(
item
,
attr
);
}
else
if
attr
.check_name
(
"proc_macro"
)
{
self
.collect_bang_proc_macro
(
item
,
attr
);
};
visit
::
walk_item
(
self
,
item
);
...
...
@@ -320,7 +354,8 @@ fn visit_mac(&mut self, mac: &ast::Mac) {
// }
fn
mk_registrar
(
cx
:
&
mut
ExtCtxt
,
custom_derives
:
&
[
ProcMacroDerive
],
custom_attrs
:
&
[
AttrProcMacro
])
->
P
<
ast
::
Item
>
{
custom_attrs
:
&
[
ProcMacroDef
],
custom_macros
:
&
[
ProcMacroDef
])
->
P
<
ast
::
Item
>
{
let
eid
=
cx
.codemap
()
.record_expansion
(
ExpnInfo
{
call_site
:
DUMMY_SP
,
callee
:
NameAndSpan
{
...
...
@@ -342,6 +377,7 @@ fn mk_registrar(cx: &mut ExtCtxt,
let
registrar
=
Ident
::
from_str
(
"registrar"
);
let
register_custom_derive
=
Ident
::
from_str
(
"register_custom_derive"
);
let
register_attr_proc_macro
=
Ident
::
from_str
(
"register_attr_proc_macro"
);
let
register_bang_proc_macro
=
Ident
::
from_str
(
"register_bang_proc_macro"
);
let
mut
stmts
=
custom_derives
.iter
()
.map
(|
cd
|
{
let
path
=
cx
.path_global
(
cd
.span
,
vec!
[
cd
.function_name
]);
...
...
@@ -371,6 +407,18 @@ fn mk_registrar(cx: &mut ExtCtxt,
vec!
[
registrar
,
name
,
cx
.expr_path
(
path
)]))
}));
stmts
.extend
(
custom_macros
.iter
()
.map
(|
cm
|
{
let
name
=
cx
.expr_str
(
cm
.span
,
cm
.function_name.name
);
let
path
=
cx
.path_global
(
cm
.span
,
vec!
[
cm
.function_name
]);
let
registrar
=
cx
.expr_ident
(
cm
.span
,
registrar
);
let
ufcs_path
=
cx
.path
(
span
,
vec!
[
proc_macro
,
__
internal
,
registry
,
register_bang_proc_macro
]);
cx
.stmt_expr
(
cx
.expr_call
(
span
,
cx
.expr_path
(
ufcs_path
),
vec!
[
registrar
,
name
,
cx
.expr_path
(
path
)]))
}));
let
path
=
cx
.path
(
span
,
vec!
[
proc_macro
,
__
internal
,
registry
]);
let
registrar_path
=
cx
.ty_path
(
path
);
let
arg_ty
=
cx
.ty_rptr
(
span
,
registrar_path
,
None
,
ast
::
Mutability
::
Mutable
);
...
...
src/test/compile-fail-fulldeps/proc-macro/auxiliary/bang_proc_macro.rs
0 → 100644
浏览文件 @
2fcbb48c
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// force-host
// no-prefer-dynamic
#![feature(proc_macro)]
#![crate_type
=
"proc-macro"
]
extern
crate
proc_macro
;
use
proc_macro
::
TokenStream
;
#[proc_macro]
pub
fn
bang_proc_macro
(
input
:
TokenStream
)
->
TokenStream
{
input
}
src/test/compile-fail-fulldeps/proc-macro/macro-use-bang.rs
0 → 100644
浏览文件 @
2fcbb48c
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:bang_proc_macro.rs
#![feature(proc_macro)]
#[macro_use]
extern
crate
bang_proc_macro
;
fn
main
()
{
bang_proc_macro!
(
println!
(
"Hello, world!"
));
//~^ ERROR: procedural macros cannot be imported with `#[macro_use]`
}
src/test/compile-fail-fulldeps/proc-macro/resolve-error.rs
浏览文件 @
2fcbb48c
...
...
@@ -11,6 +11,7 @@
// aux-build:derive-foo.rs
// aux-build:derive-clona.rs
// aux-build:attr_proc_macro.rs
// aux-build:bang_proc_macro.rs
#![feature(proc_macro)]
...
...
@@ -19,13 +20,19 @@
#[macro_use]
extern
crate
derive_clona
;
extern
crate
attr_proc_macro
;
extern
crate
bang_proc_macro
;
use
attr_proc_macro
::
attr_proc_macro
;
use
bang_proc_macro
::
bang_proc_macro
;
macro_rules!
FooWithLongNam
{
()
=>
{}
}
macro_rules!
attr_proc_mac
{
()
=>
{}
}
#[derive(FooWithLongNan)]
//~^ ERROR cannot find derive macro `FooWithLongNan` in this scope
//~^^ HELP did you mean `FooWithLongName`?
...
...
@@ -61,7 +68,12 @@ fn main() {
attr_proc_macra!
();
//~^ ERROR cannot find macro `attr_proc_macra!` in this scope
//~^^ HELP did you mean `attr_proc_mac!`?
Dlona!
();
//~^ ERROR cannot find macro `Dlona!` in this scope
bang_proc_macrp!
();
//~^ ERROR cannot find macro `bang_proc_macrp!` in this scope
//~^^ HELP did you mean `bang_proc_macro!`?
}
src/test/run-pass-fulldeps/proc-macro/auxiliary/bang-macro.rs
0 → 100644
浏览文件 @
2fcbb48c
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// no-prefer-dynamic
#![feature(proc_macro)]
#![crate_type
=
"proc-macro"
]
extern
crate
proc_macro
;
use
proc_macro
::
TokenStream
;
#[proc_macro]
pub
fn
rewrite
(
input
:
TokenStream
)
->
TokenStream
{
let
input
=
input
.to_string
();
assert_eq!
(
input
,
r#""Hello, world!""#
);
r#""NOT Hello, world!""#
.parse
()
.unwrap
()
}
src/test/run-pass-fulldeps/proc-macro/bang-macro.rs
0 → 100644
浏览文件 @
2fcbb48c
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.
// aux-build:bang-macro.rs
#![feature(proc_macro)]
extern
crate
bang_macro
;
use
bang_macro
::
rewrite
;
fn
main
()
{
assert_eq!
(
rewrite!
(
"Hello, world!"
),
"NOT Hello, world!"
);
}
编辑
预览
Markdown
is supported
0%
请重试
或
添加新附件
.
添加附件
取消
You are about to add
0
people
to the discussion. Proceed with caution.
先完成此消息的编辑!
取消
想要评论请
注册
或
登录