66

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

 5 years ago
source link: https://www.tuicool.com/articles/QfuAV3Q
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

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

在Js中 一个方法的关键词是 function 在Swift中是 func,我们遍历一下Js代码,将所有的 function 转化成 func

嗯。。。 感觉太傻了。。。没有一点作为一个程序猿的追求

方案二:

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

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

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

JavaScript中定义一个a变量:

var a = 1

Swift中定义一个a变量:

var a = 1

他们的AST分别如下:

169c8309ff72b1f3169c83106e4f5325

两者的语法描述一模一样,但是AST却相差很多,很难找到差异性

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

3、JavaScript中有ES5、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  = falseif (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);

// 解析astlet 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 = typeself.model = model
        self.color = color
    }
}let car = Car(type: "Fiat", model: 500, color: "white")复制代码

在 ObjectExpression 方法中 可以通过

if (expr.properties) {let properties  = expr.propertiesfor (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.propertiesfor (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?(二)

未完待续。。。。


About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK