https://github.com/dotvanilla/vanilla

vanilla编译器项目是我之前开发过的一个实验性质的项目。主要是为了解决在浏览器端的一些高性能计算的需求,例如数据加密和解密,基于WebGL的计算机图形项目,力学物理规律模拟,网络可视化布局计算等。

当然,上面的操作目前都存在有对应的JavaScript代码库来实现。但是JavaScript是一门动态类型的语言,在计算性能上,数据量增大了以后,无法满足实际的计算需求。所以就诞生了WebAssembly项目。WebAssembly项目主要是为了满足浏览器端或者基于nodejs后台的高性能计算的需求。vanilla编译器项目可以将一个完整的VisualBasic.NET项目以WASM为编译目标平台,编译出一个WebAssembly应用程序。

在这里我将介绍vanilla编译器项目是如何开发的。这些文章,将会帮助你可以深入的理解vanilla编译器项目。或者你可以通过以vanilla编译器项目为参考,开发出自己的编译器项目将其他的编程语言编译为WebAssembly应用程序。

在本博客中相关的教程文章:

VanillaBasic编译器项目

在这个编译器项目之中,主要由三大部分模块组成:

  • 将VB.NET代码转换为WAST中间代码
  • 将WAST中间代码编译为WebAssembly
  • 一个用于支撑VB.NET程序在浏览器中运行的TypeScript运行时环境

之所以称呼这个VisualBasic.NET语言的编译器项目为VanillaBasic,是因为你可以使用VB.NET的语法进行开发,但是没有办法使用.NET框架。你只能够从零开始编写一个应用程序,使用原生的VisualBasic语言从头开发,没有任何框架可以被依赖使用。

经过了很多年的发展,VisualBasic.NET语言的语法目前已经足够成熟和复杂了。我们如果从头开始编写VisualBasic语言的语法解析器,很明显是一件很不现实的事。好在微软开源了一个名称为Roslyn的编译器项目。我们可以借助这个编译器项目很轻松的就可以进行VisualBasic源代码文件的解析操作,得到相关的语法单元用于编译为WebAssembly程序。

关于Roslyn编译器进行VisualBasic源代码解析的操作,可以阅读《Roslyn编译器开发》这篇文章。

VB.NET编译器

使用Vanilla编译器进行VisualBasic源代码的WASM平台编译是非常的简单的,你只需要简单的调用几个相关的函数即可。在这里带你简单的了解一下是如何使用Vanilla编译器将一个VisualBasic源代码文件编译为WebAssembly程序:

  • 首先我们会需要创建一个Vanilla的编译器对象
  • 接着就可以通过VisualStudio工具得到一个VisualBasic项目中的源代码文件,传递进入编译器对象进行源代码文件的解析操作
  • 之后可以将解析完成的源代码项目转换为WAST源代码文件
  • 最后将WAST源代码文件送入WebAssembly编译器工具中即可完成整个编译过程了。

例如通过下面的一段代码可以进行VisualBasic项目的源代码解析:

Imports Microsoft.VisualBasic.ApplicationServices.Development.VisualStudio
Imports Microsoft.VisualBasic.ApplicationServices.Development.VisualStudio.vbproj
Imports VanillaBasic.Roslyn
Imports VanillaBasic.WebAssembly.Compiler

Dim vb As Project = Project.Load("/path/to/target.vbproj")
Dim wasm As New Scanner(vb)

For Each file As String In vb.EnumerateSourceFiles(skipAssmInfo:=True, fullName:=True)
    wasm.AddModules(file)
Next

Call wasm.Workspace _
    .ToSExpression _
    .SaveTo("/path/to/webassembly.wat")

将解析得到的VisualBasic源代码项目编译为WebAssembly程序集,可以通过VanillaBuild编译器来完成,例如下面的一个例子就是将解析得到VisualBasic项目通过Compile方法进行WebAssembly目标编译:

<Extension>
Private Sub CreateWasm(VisualBasic As Workspace, debug As Boolean, output$)
    Dim config As New Wat2wasm With {.output = output}

    If debug Then
        config.debugNames = True
        config.debugParser = True
        config.verbose = True
    End If

    Call VanillaBuild.WastDump(VisualBasic, output.ChangeSuffix("*.wast"))
    Call VanillaBuild.HexDump(VisualBasic, output.ChangeSuffix("*.dmp"), verbose:=True)
    Call VanillaBuild.Compile(VisualBasic, config)
End Sub

TypeScript运行时环境

在WebAssembly之中,由于其是专门针对于数学计算的需求而开发的。所以很多的在JavaScript之中的API,例如DOM操作,ajax网络请求等API都是缺失掉的。所以我们会需要一个对应的JavaScript胶水代码库来帮助WebAssembly应用程序来调用这些数值计算以外的功能API函数。

另外,WebAssembly一般无法直接通过类似于javascript一样的,可以直接在HTML页面之中通过script标签加载。所以我们会需要通过对应的JavaScript代码加载WebAssembly程序文件。在Vanilla编译器项目之中,建立了一个TypeScript胶水代码项目用来支持所编译出来的VisualBasic程序在浏览器上的运行。

下面,我们来学习如何通过这个JavaScript运行时环境来执行你所编译出来的VisualBasic程序把:

// WebAssembly Demo
vanilla.Wasm.showDebugMessage(false);
vanilla.Wasm.RunAssembly("../vbscripts/base64.wasm", {
  run: encoder => {
    let base64 = encoder.base64Encoder;
    let handleInput = function () {
      displayBase64.innerText = base64.encode(textInput.value);
      textOutput.innerText = base64.decode(displayBase64.innerText);
    }

    console.log("WebAssembly structure is keeps the same as your VB.NET source file:");
    console.log(encoder);
    console.log("Here is the application info get from AssemblyInfo.vb file:");
    console.log(encoder.AssemblyInfo);

    textInput.onkeypress = handleInput;
    textInput.oninput = handleInput;
    textInput.oninput();
  },
  api: { console: true, text: true, array: true }
});

下面我们来逐行解读上面的TypeScript运行时环境代码。

首先,vanilla.Wasm.showDebugMessage这一句是用于控制WebAssembly程序的调试模式的函数。我们只需要通过这个函数设置一个逻辑值,就可以打开或者关闭调试模式了。
在VanillaBasic环境之中运行一个编译为WebAssembly程序的VB.NET应用,其实只需要调用vanilla.Wasm.RunAssembly这个函数就可以了。这个函数接受两个参数:第一个参数就是目标WebAssembly文件的网络位置;第二个参数就是用来描述怎样执行这个WebAssembly文件的配置对象了。在这里我们主要是着重来讲解这个运行时配置对象的使用。

在这个运行时配置对象中,最终的一个接口就是run属性,其是运行你的WebAssembly程序是必须的。这个run属性只需要接收一个函数集合对象就可以了。例如:

{
    run: function(webassembly) {
        webassembly.method1();
    }
}

没错,这个run函数的参数就是你的WebAssembly程序。WebAssembly环境会通过这个运行时配置对象,将加载好的webAssembly程序传递到这个run函数之中,然后你就可以通过这个参数来得到对应的WebAssembly程序,调用相应的函数了。

Latest posts by xie guigang (see all)

Attachments

No responses yet

发表评论

您的电子邮箱地址不会被公开。 必填项已用*标注