猫·仁波切

会研发的PM才是好OP.

Rust Syntax Extensions

All rust ASTs are in syntax::ast. And extensions are in syntax::ext.

1
2
3
4
5
6
7
8
9
10
#![feature(macro_registrar, managed_boxes)];

extern crate syntax;

use syntax::ast;
use syntax::ast::Name;
use syntax::ext::base::SyntaxExtension;

#[macro_registrar]
pub fn macro_registrar(register: |Name, SyntaxExtension|);

Managed boxes, the @-pointer is still used in rust compiler, so it is essential to enable this feature.

where the doc says:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
/// A name is a part of an identifier, representing a string or
gensym. It's the result of interning.
/// created by token::intern()
type Name = u32;

/// An enum representing the different kinds of syntax extensions.
pub enum SyntaxExtension {
    /// A syntax extension that is attached to an item and creates new items
    /// based upon it.
    ///
    /// `#[deriving(...)]` is an `ItemDecorator`.
    ItemDecorator(ItemDecorator),

    /// A syntax extension that is attached to an item and modifies it
    /// in-place.
    ItemModifier(ItemModifier),

    /// A normal, function-like syntax extension.
    ///
    /// `bytes!` is a `NormalTT`.
    NormalTT(~MacroExpander:'static, Option<Span>),

    /// A function-like syntax extension that has an extra ident before
    /// the block.
    ///
    /// `macro_rules!` is an `IdentTT`.
    IdentTT(~IdentMacroExpander:'static, Option<Span>),
}

type ItemDecorator = fn(&mut ExtCtxt, Span, @MetaItem, @Item, |@Item|);
type ItemModifier = fn(&mut ExtCtxt, Span, @MetaItem, @Item) -> @Item;

pub trait MacroExpander {
    fn expand(&self, ecx: &mut ExtCtxt, span: Span, token_tree: &[TokenTree]) -> ~MacResult;
}

pub trait IdentMacroExpander {
    fn expand(&self, cx: &mut ExtCtxt, sp: Span, ident: Ident, token_tree: Vec<TokenTree>) -> ~MacResult;
}

/// The result of a macro expansion. The return values of the various
/// methods are spliced into the AST at the callsite of the macro (or
/// just into the compiler's internal macro table, for `make_def`).
pub trait MacResult {
    /// Define a new macro.
    fn make_def(&self) -> Option<MacroDef> {
        None
    }
    /// Create an expression.
    fn make_expr(&self) -> Option<@ast::Expr> {
        None
    }
    /// Create zero or more items.
    fn make_items(&self) -> Option<SmallVector<@ast::Item>> {
        None
    }

    /// Create a statement.
    ///
    /// By default this attempts to create an expression statement,
    /// returning None if that fails.
    fn make_stmt(&self) -> Option<@ast::Stmt> {
        self.make_expr()
            .map(|e| @codemap::respan(e.span, ast::StmtExpr(e, ast::DUMMY_NODE_ID)))
    }
}

How to call

1
2
3
4
5
6
use syntax::parse::token;

#[macro_registrar]
pub fn registrar(register: |Name, SyntaxExtension|) {
    register(token::intern("your_ext_name"), your_extension);
}

Note: registrar is not register.

How to create each part:

Name is generated from syntax::parse::token::intern().

For different SyntaxExtension Enum, write the function, and wrap in Enum constructor.

ItemDecorator

src/libsyntax/ext/deriving/mod.rs. The #[deriving(...).

To make items from an existing item.

ItemModifier

src/test/auxiliary/macro_crate_test.rs

Modify existing item.

NormalTT

Builtin sample in: src/libsyntax/ext/base.rs and sub dirs. Normal macro_name!(...) call.

IdentTT

Builtin sample in: src/libsyntax/ext/tt/macro_rules.rs, pub fn add_new_extension.

1
2
3
macro_name! ident(
    whatever here...
)

Aux

The quote feature.

1
#![feature(quote, phase)]

This enables quote_expr!(ExtCtxt, [Code]), quote_tokens!, quote_item!, quote_pat!, quote_stmt!, quote_ty! macros, and generates corresponding ast type.

Erlang 的一些好玩 Tips

可以模拟OO, 模块级别的继承.

-extends(parent).

反编译 beam, 对加密过或者 hipe 的似乎无效.

1
2
{ok,{_,[{abstract_code,{_,AC}}]}} = beam_lib:chunks(Beam,[abstract_code]).
io:fwrite("~s~n", [erl_prettypr:format(erl_syntax:form_list(AC))]).

语句块, 比较少用到.

1
2
3
begin
   ...
end

Parameterised Modules 参数化模块, 也是模拟 OO 的. 很多 web 框架都这么用, 不过这货在 R16 被去掉了, 也是… 其实挺恶心.

-module(xxx, [Arg1, Arg2]).

Stateful Modules, 用于替换 Parameterised Modules. 将模块和对应状态保存在 tuple 里, 看起来像是调用某一对象的方法一样.

1
2
3
4
X = {Mod, P1, P2, ..., Pn},
X:Func(A1, A2, ..., An).
%% 等价于
Mod:Func(A1, A2, ..., An, X).

所以 web 框架就转为使用这个特性了, 看起来很无害而且不反 FP.