TypeScript背后的主干也是围绕着AST的操作。
常规的AST操作有三个阶段:
- parse阶段:将code转换为AST节点集合
- 词法分析:将code转换为tokens集合;
- 语法分析:根据tokens集合的排列顺序,构建AST节点,继而构建AST节点集合;
- transform阶段;
- Generate阶段;
TypeScript在此基础上做了扩展,分析mini-typescript就可以看到:
- parse阶段:以一个语句为工作单元,基于词法片段生成AST;
- 准备工作,预置的tokens类型、Node类型和keywords;
- 设计了词法分析工具
lex
,按照行为单位,将code拆解为一个一个tokens,根据tokens的排列顺序组织为AST的Node节点,特别注意的是,在这个阶段收集了变量的类型typename
;
- bind阶段;
- 这里的bind阶段非常简单,仅仅是检查了变量有没有重定义;
- check阶段:检查一个语句单位内,基本语法、类型准确性;
- 做了基本的类型校检,比如
var a:string = 'hello'
,其中 string 的类型标注,在之前收集的Node节点的typename
属性;'hello'本身是一个表达式,表达式是一个独立的Node的节点,根据节点的类型可以去获取表达式的类型。最后两者做比较;
- 做了基本的类型校检,比如
- transform阶段:
- 如果存在类型标注,移除一下。操作非常方便,还记得之前收集的类型是
typename
,这里之前将Node上的这个信息给去掉了就行;
- 如果存在类型标注,移除一下。操作非常方便,还记得之前收集的类型是
- emit/generator阶段:
- 生成js代码。因为在AST Node构建之初,有
text
属性记录原始文本,所以再搬回来就是了。如果涉及变量标注,就得手动拼接以移除;
- 生成js代码。因为在AST Node构建之初,有
这里要补充的是,真实的bind阶段,是TypeScript Infer起作用的节点,它的算法根据上下文判断,给没有类型标注的变量补上类型标注。