承影生成器

# 承影生成器 ## (一)、项目背景 - 承影生成器,是承影低代码工具中最基础、最底层的模块,主要负责代码的“编译”与“反编译”工作。 - 承影生成器是承影低代码四大底层能力之首,为四大前台模块“设计器”、“编排器”、“数据源”、“工作台”提供代码的生成与解析能力。 - 承影生成器原名“编译器”,后因与“反编译器”整合,故更名为“生成器” ## (二)、实现方向 - 代码生成主要由3个步骤实现: (1)前端完成程序的可视化设计(如流程图),并通过中间语言(Json格式)将设计传递给后端; (2)后端解析中间语言,并提需求分析中间语言的语义。 (3)根据分析的语义结果,调用相应的语法模板,生成出最终的可运行代码。 ## (三)、数据流向图 ![image.png](https://cos.easydoc.net/92634618/files/kp3g69tc.png) ## (四)、主要部件 - #### 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>) %> ``` ## (五)、生成器开发三大原则 - 保证生成代码的正确性与运行性能 - 保证项目的功能可扩展性。 - 保证项目的代码可维护性。 ## (六)、未来展望 - 通过异步编译来加速代码生成。 - 对算法进行优化,减少空间占用。 - 支持更多的编译目标。 - 支持更复杂的业务代码生成。