如何将JavaScript转化成Swift?(一)

最近遇到了一个诡异的需求:node

将一个弱类型语言JavaScript转化成强类型语言Swiftswift

方案一:

强转,将JavaScript的语法和Swift的语法一一对应bash

在Js中 一个方法的关键词是 function 在Swift中是 func,咱们遍历一下Js代码,将全部的 function 转化成 func网络

嗯。。。 感受太傻了。。。没有一点做为一个程序猿的追求post

方案二:

将Js转化成AST,将Js的AST转化成Swift的AST,而后再转回Swiftui

嗯。。。这个貌似牛逼哄哄,可是遇到了几个难点:this

一、Js的AST和Swift的AST很难找到对应关系

JavaScript中定义一个a变量:spa

var a = 1翻译

Swift中定义一个a变量:code

var a = 1

他们的AST分别以下:

JavaScript的AST

Swift的AST

二者的语法描述如出一辙,可是AST却相差不少,很难找到差别性

二、JavaScript中经过 escodegen 这个库 将AST从新生成为源码,可是在Swift和Java中并未找到相应的官方库或者第三方库来进行转化

三、JavaScript中有ES五、ES6,咱们能够编写ES6的语法而后经过Bebal将ES6翻译成ES5,用到就是 JavaScript 和 AST 之间的相互转换,可是Swift并中没有相似的需求,因此相应的资料代码极少

方案三:

将Js的AST转化成Swift

既然不能将Swift的AST转化成Swift,可不能够将Js的AST转化成Swift呢?

如何操做?:

这里借鉴了JS Parser的三板斧

1.经过 esprima 把源码转化为AST

2.经过 estraverse 遍历并更新AST

3.经过 escodegen 将AST从新生成源码

简单说一下原理:

  • 首先经过 esprima 将js 源码翻译成 AST,
  • 经过 estraverse 遍历AST 补充一些特征(好比类型)
  • 修改 escodegen 源码,生成Swift源码

修改 escodegen 源码

新建一个Js的项目,安装 esprima、escodegen依赖,

新建 test.js 须要解析的js代码:

function testFunc() {
    var a = 1
    var b = "1"
    var c  = false
    if (a<20) {
      b = "Good day";
    }
    console.log(b)
    var car = {type:"Fiat", model:500, color:"white"};
    console.log(car.type)
}
  
复制代码

新建 swift.js 用来读取 test.js 代码,生成 test.swift 文件:

const esprima = require('esprima');
const escodegen = require("escodegen");
var fs = require("fs")

// 读取test.js代码
var data = fs.readFileSync('test.js');
let code =  data.toString()

// 解析js的语法
let tree = esprima.parseScript(code);

// 解析ast
let transformCode = escodegen.generate(tree);

// 生成swift文件
fs.writeFile('test.swift', transformCode,  function(err) {
   if (err) {
       return console.error(err);
   }
});
复制代码

进行编译。。。

node swift.js

下面开始修改 escodegen 里面的 escodegen.js 文件

将 function 替换成 func

FunctionDeclaration: function (stmt, flags) {
             return [
                 generateAsyncPrefix(stmt, true),
                 'function',
                 generateStarSuffix(stmt) || noEmptySpace(),
                 stmt.id ? generateIdentifier(stmt.id) : '',
                 this.generateFunctionBody(stmt)
             ];
        },
复制代码

这段代码是用来处理 function 节点,咱们只须要将 function 修改为 func 便可,很简单!

Js是弱类型,如何判断类型?

VariableDeclarator: function (stmt, flags) {
            var itemFlags = (flags & F_ALLOW_IN) ? E_TTT : E_FTT;
            console.log("+++++++++++++++++ 执行 VariableDeclarator+++++++++++++++++")
            // 增长数据类型
            // console.log(stmt.mold.name)
            if (stmt.init) {
                 if (stmt.mold.name) {
                     return [
                         this.generateExpression(stmt.id, Precedence.Assignment, itemFlags),
                         space,
                         '=',
                         space,
                         this.generateExpression(stmt.init, Precedence.Assignment, itemFlags)
                     ];
                 }
                ];
            }
复制代码

这是处理变量的一个方法, 这段代码的返回结果是:a = 1 , 咱们只须要在 a 前面加上 类型便可,这里用 Js的 typeof 方法进行判断,而后将 number、string、boolean 和swift 的Int、String、Bool进行映射

如何将 console.log 修改为 print

// 进行字符串替换 
for (let i = 0; i < result.length; i++) {
    const element = result[i];
    if (element.indexOf("console.log")!=-1) {
        result[i] = element.replace(/console.log/, "print")
    }
}
复制代码

比较简单粗暴。。。

如何将Js的对应翻译成 Swift的对象?

这个稍微复杂,由于Js弱类型的特性,他不须要额外去写一个类定一个对象,可是Swift须要,因此这里咱们须要读取Js的对象,而后生成一个类

在 Js 中 描述一个对象

var car = {type:"Fiat", model:500, color:"white"}
复制代码

在Swift中描述一个对象

class Car: NSObject {
    var type: String = ""
    var model: Int = 0
    var color: String = ""
    init(type: String, model: Int, color: Int) {
        self.type = type
        self.model = model
        self.color = color
    }
}

let car = Car(type: "Fiat", model: 500, color: "white")
复制代码

在 ObjectExpression 方法中 能够经过

if (expr.properties) {
    let properties  = expr.properties
    for (let i = 0; i < properties.length; i++) {
        const element = properties[i];
        // 生成对应的文件
        console.log(element.key.name)
    }
}
复制代码

将 var car = {type:"Fiat", model:500, color:"white"} 中的type、model、color读取到,而后生成对应的Swift文件

剩下的就是将

var car = {type:"Fiat", model:500, color:"white"}
复制代码

替换成

let car = Car(type: "Fiat", model: 500, color: "white")
复制代码

只须要生成对象的时候记录一下类名,将 ‘{’ 替换成 ‘Car(’ ,将 ‘)’ 替换成 ‘}’便可

生成对象的代码:

// 生成类名
            let className =  getClassName(expr) 
            var swiftObject = 'class ' + className + ': NSObject { \n'

            if (expr.properties) {
                let properties  = expr.properties
                for (let i = 0; i < properties.length; i++) {
                    const element = properties[i];
                    // 生成对应的文件
                    swiftObject += space + space + "var " + element.key.name + ': ' + typeOfSwift(element.value.value) + '\n'
                }
            }

            swiftObject += '}'

            fs.writeFile('./Swift_Code/Model/' + className + '.swift', swiftObject,  function(err) {
                console.log(err)
                if (err) {
                    return console.error(err);
                }
             });

复制代码

成果

完成了上述的翻译就能够完美的将 test.js 代码翻译成 test.swift 啦

func testFunc() {
    var a:Int = 1;
    var b:String = '1';
    var c:Bool = false;
    if (a < 20) {
        b = 'Good day';
    }
    print(b);
    var car = Car(
        type: 'Fiat',
        model: 500,
        color: 'white'
    );
    print(car.type);
}
复制代码

for循环如何翻译?Js的网络请求如何翻译成Swift

如何将JavaScript转化成Swift?(二)

未完待续。。。。

相关文章
相关标签/搜索