承影生成器
# 承影生成器
## (一)、项目背景
- 承影生成器,是承影低代码工具中最基础、最底层的模块,主要负责代码的“编译”与“反编译”工作。
- 承影生成器是承影低代码四大底层能力之首,为四大前台模块“设计器”、“编排器”、“数据源”、“工作台”提供代码的生成与解析能力。
- 承影生成器原名“编译器”,后因与“反编译器”整合,故更名为“生成器”
## (二)、实现方向
- 代码生成主要由3个步骤实现:
(1)前端完成程序的可视化设计(如流程图),并通过中间语言(Json格式)将设计传递给后端;
(2)后端解析中间语言,并提需求分析中间语言的语义。
(3)根据分析的语义结果,调用相应的语法模板,生成出最终的可运行代码。
## (三)、数据流向图

## (四)、主要部件
- #### 1. 解析器(parser)
解析器从前端接收中间语言数据(JSON格式),解析为流程图实体类Graph(包含结点的集合nodes,与边的集合edges),或者是一个表达式Expression。解析的过程中,解析器可能会对流程图做简单的数据校验,比如:
(1)流程图是否有且仅有一个入口、出口。;
(2)在返回、报错节点后,程序应该马上进入出口;
(3)是否为DAG(有向无环图):流程图内没有“环”,因此程序不会进入死循环。
- #### 2. 遍历器(walker)
遍历器仅考虑每个代码块的生成顺序,而不考虑代码具体如何生成。它主要的职责是对流程图实体类Graph进行遍历,将一个树形的多层数据结构,转换为一个由代码生成指令组成的序列(Series)。
在遍历器的研发中,我们遇到并解决了如下问题:
(1)当程序有多个分支,且需要回溯,如何保证结点访问顺序是正确的;
(2)当程序有多个分支,每个分支的上下文,与作用域,以及出入参的依赖问题怎么处理;
(3)如何基于图论,自动找出最优的异步运行方案。
算法复杂度的分析:
如果对一个节点访问的次数不等于1,则该段代码的生成会出错。
经过了我们大量测试,生成器生成的代码没有出现明显问题。
因此,可以知道生成器对于每个节点的访问次数有且仅有1次。
所以,生成器没多余的节点访问动作,算法在时间复杂度上达到了最优。
遍历器拿到流程图的访问顺序后,会按照顺序请求访问器,从访问器中获得具体的代码块。
- #### 3. 访问器(visitor)
访问器就像是一个很大的switch,它在代码生成的环节中,对整体并不知情。它不考虑具体的访问顺序,只考虑每个代码原子块该如何单独生成。
访问器知道如何生成代码块后,会将数据交给渲染器。渲染器会渲染出具体的代码。
- #### 4. 渲染器(renderer)
渲染器根据不同的“编译目标”要求,找到相应的模板文件的位置,并将数据注入模板。
通过配置不同的“编译目标”,可以调用不同的模板,从而实现跨语言的代码生成。
- #### 5. 生成器(exporter)
接受来自遍历器的代码块,生成器的职责是将这些代码块依次存储下来,并同时记录代码块“需要引入的依赖”、和“需要定义的方法”,最终将整体代码注入到main方法的模板中,并导出所有代码。
- #### 6. 语法模板(Template)
基于StringTemplate的模板引擎库,通过严格的MVC分层,支持更加灵活的代码生成
```python
### 语法模板的部分代码块示例
sorted(obj, lambda) ::= <%
sorted(<obj><if(lambda)>, key = <lambda><endif>)
%>
count(obj, args) ::= <%
<obj>.count(<args>)
%>
copy_imports() ::= "from copy import deepcopy"
copy(obj) ::= <%
deepcopy(<obj>)
%>
ceil_imports() ::= "from math import ceil"
ceil(obj) ::= <%
ceil(<obj>)
%>
floor_imports() ::= "from math import floor"
floor(obj) ::= <%
floor(<obj>)
%>
```
## (五)、生成器开发三大原则
- 保证生成代码的正确性与运行性能
- 保证项目的功能可扩展性。
- 保证项目的代码可维护性。
## (六)、未来展望
- 通过异步编译来加速代码生成。
- 对算法进行优化,减少空间占用。
- 支持更多的编译目标。
- 支持更复杂的业务代码生成。