Rust编译器将源码进行Tokenization,转换成一个个token tree,这些token tree可以是不符合Rust语法规则的。这些token有不同的类型。

需要注意的是self,即是Identifiers,也是Kerwords,大多数情况下是Keywords Macro是Rust的语法扩展

Tokenization后,接下来就是将token stream转换成AST(Abstract Syntax Tree),这一步被称之为**Paprsing,**而宏的处理就是在AST之后开始了。

Toekn trees

所有的Token自己就是一个Token Tree,具体点来说他自己就是一个只有一个叶子节点的Token Tree。被**{}、[]、()**包裹的一系列token组成了一个有多个叶子的Token Tree。例如下面这行代码。

a + b + (c + d[0]) + e

转换成Token Tree后如下:

«a» «+» «b» «+» «(   )» «+» «e»
          ╭────────┴──────────╮
           «c» «+» «d» «[   ]»
                        ╭─┴─╮
                         «0»

最终转换出来的是一个具有多个根的token tree,相互嵌套,接着Token tree会被转换成AST,如下:

Untitled

Token tree中不应该存在不成对的{}、[]、()

Rust的宏,其处理就是在AST构建之后,才开始进行处理,因此调用宏的语法必须是符合Rust语法规则的,属于Rust的语法扩展,下面是宏相关的语法扩展。

  1. # [ $arg ]e.g. #[derive(Clone)]#[no_mangle], …
  2. # ! [ $arg ]e.g. #![allow(dead_code)]#![crate_name="blang"], …