编译器、解释器

相信计算机的同学对这两个词一定不陌生,从学计算机开始,我们就知道了计算机是二进制的世界,而我们用高级语言编写的代码计算机是无法理解的,编译器就是将我们编写的代码编译成计算机可以执行的二进制文件,然后计算机直接执行编译后的文件。

【低代码】手写低代码中的编译器/翻译器_html


如果将我们低代码也视为一种语言,这种语言就是低代码设计的产品模型。在之前曾提到过,像设计编程语言那样设计低代码平台

就像计算机无法直接运行我们的用高级语言编写的代码,它也更不可能具有运行我们低代码平台设计的模型。所以同理,我们可以像编译器那样将代码编译成计算机可以运行的形式。当然,低代码平台并非将模型编译成二进制指令集,而是翻译成目标平台可以运行的语言,这个过程是类似的。

【低代码】手写低代码中的编译器/翻译器_手写低代码平台_02

设计翻译器

有了上述的概念后我们大致清楚了要做一件什么样的事情,那就是将低代码平台设计的模型转换(翻译)成我们目标平台的语言,而目前最常见且流行的就是移动端的使用,所以我们本次所做的事情就是将低代码模型翻译成浏览器可以执行的语言也就是html

设计模型

设计模型前需要去了解目标平台语言是什么样的,尽可能选择简便且精巧的方式来设计模型。基本的html语言格式大致长这样,当然这是最简单的形式,实际我们网站或者移动端看到的网页远远比这个复杂,不过通过这样一个简单的页面,我们已经基本能了解html语言的雏形。

html由一个又一个的标签组成,最顶层的标签是,内部一层又一层的嵌套,我们不难得出,又html语言编写出来的页面是呈树状结构的。

<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>【低代码】手写低代码中的编译器/翻译器</title>
</head>
<body>
    <h1>我的低代码中编译器</h1>
</body>
</html>

这一段简单的逻辑可以组织成如下图所示这样的一个树形结构,不过图中省略了标签中值的关系,只包含标签与标签之间的逻辑。

【低代码】手写低代码中的编译器/翻译器_翻译器_03


这样的展现形式我们可以很自然的想到可以通过JSON(JavaScript Object Notation, JS 对象简谱) 一种轻量级的数据交换格式来描述这样的关系,且json本身就是一个树形结构的表述,可以完全覆盖并且很直观浅显的去描述我们低代码平台生成的模型。

模型

用Java来描述下我们的模型,如Java的基础是Object类,我们模型最基础的是标签,最底层的标签是html,它永远在最外层,然后内部嵌套一个又一个的标签,所以可以我们的模型也定义一个基础,这个基础的标签名称为,所有的标签都继承于这个基础并且拥有自己唯一的标签名称。






基础标签<html>

tag1 如<h1>

tag1 如<p>

tag1 如<input>

......


  • 基础标签html
package finish.model;

import java.util.List;
import java.util.Map;

/**
 * Copyright(c)lbhbinhao@163.com
 * @author liubinhao
 * @date 2022/1/25
 */
public class Base {

    private List<Base> subNode;

    public List<Base> getSubNode() {
        return subNode;
    }

    public void setSubNode(List<Base> subNode) {
        this.subNode = subNode;
    }

    public Map<String,String> attribute;

    public Map<String, String> getAttribute() {
        return attribute;
    }

    public void setAttribute(Map<String, String> attribute) {
        this.attribute = attribute;
    }

    public String getTag() {
        return "html";
    }
}
  • 子标签(以input标签为例)
package finish.model;

/**
 * Copyright(c)lbhbinhao@163.com
 * @author liubinhao
 * @date 2022/1/25
 * ++++ ______                           ______             ______
 * +++/     /|                         /     /|           /     /|
 * +/_____/  |                       /_____/  |         /_____/  |
 * |     |   |                      |     |   |        |     |   |
 * |     |   |                      |     |   |________|     |   |
 * |     |   |                      |     |  /         |     |   |
 * |     |   |                      |     |/___________|     |   |
 * |     |   |___________________   |     |____________|     |   |
 * |     |  /                  / |  |     |   |        |     |   |
 * |     |/ _________________/  /   |     |  /         |     |  /
 * |_________________________|/b    |_____|/           |_____|/
 */
public class InputButton extends Base{

    @Override
    public String getTag() {
        return "input";
    }

}

翻译器实现

我们的翻译器就是将有一个Base并且包含一个又一个的子节点这样的一个树状结构的模型翻译成浏览器这个目标平台可以读懂的html语言,要实现一个翻译器/编译器是一件非常复杂的事,此处以最简单的案例来展示,此处省略一万字,Talk is cheap. Show me the code.1

package model.translator;

import com.alibaba.fastjson.JSONObject;
import model.Base;
import model.InputButton;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

/**
 * Copyright(c)lbhbinhao@163.com
 *
 * @author liubinhao
 * @date 2022/1/25
 * ++++ ______                           ______             ______
 * +++/     /|                         /     /|           /     /|
 * +/_____/  |                       /_____/  |         /_____/  |
 * |     |   |                      |     |   |        |     |   |
 * |     |   |                      |     |   |________|     |   |
 * |     |   |                      |     |  /         |     |   |
 * |     |   |                      |     |/___________|     |   |
 * |     |   |___________________   |     |____________|     |   |
 * |     |  /                  / |  |     |   |        |     |   |
 * |     |/ _________________/  /   |     |  /         |     |  /
 * |_________________________|/b    |_____|/           |_____|/
 */

public class Translator {

    public static void translate(Base base, StringBuilder builder){
        String tag = base.getTag();
        builder.append("<").append(tag);
        if (base.getAttribute()!=null) {
            base.getAttribute().forEach((k, v) -> {
                builder.append(" ");
                builder.append(k).append("=").append("\"").append(v).append("\"");
            });
        }
        builder.append(">");
        if (base.getSubNode()!=null) {
            for (Base b : base.getSubNode()) {
                translate(b, builder);
            }
        }
        builder.append("</").append(base.getTag()).append(">");
    }

    public static void main(String[] args) {

        Base base = new Base();
        List<Base> sub = new ArrayList<>();
        InputButton button = new InputButton();
        HashMap<String, String> map = new HashMap<>();
        map.put("type","text");
        button.setAttribute(map);
        sub.add(button);
        base.setSubNode(sub);
        String model = JSONObject.toJSONString(base);
        System.out.println("model:\n"+model);

        StringBuilder builder = new StringBuilder();
        translate(base,builder);
        System.err.println("translation:\n"+builder.toString());
    }
}

上述案例中定义了一个最简单模型

  • 用图表示
  • 用JSON表示
{"subNode":[{"attribute":{"type":"text"},"tag":"input"}],"tag":"html"}
  • 用html呈现
<html><input type="text"></input></html>

【低代码】手写低代码中的编译器/翻译器_手写低代码平台_04

上诉代码就是将用JSON描述的模型翻译成了html标签语言描述的形式,是不是很简单呢,只通过很简单的几十行代码,就完成了一个最基础版本的翻译器!


  1. Linus Torvalds ↩︎