#language #description #format #serialization #compiler #verilization #version

verilization-compiler-cli-core

verilization 序列化描述语言编译器。这个版本包含 CLI,没有语言,以便添加额外语言。

1 个不稳定版本

0.1.0 2021年5月5日

#7#verilization


用于 verilization-compiler-cli

GPL-3.0-only

105KB
2.5K SLoC

Verilization

Verilization 是一种用于定义二进制文件格式的序列化描述语言。与其他序列化工具(如 Protocol Buffers)不同,序列化的 Verilization 数据不具有向前或向后兼容性。相反,从旧版本格式转换变得容易,允许数据更加紧凑,并且可以更好地控制数据的底层形状。

目标

Verilization 具有以下主要目标。

  • 给用户最大的文件格式控制权
  • 以语言无关的方式定义格式
  • 支持从旧版本格式轻松转换

其他较低层次的目标。

  • 支持大整型类型
  • 可以在其他语言中嵌入而不使用本地二进制文件

类型

以下类型受支持。

类型 编码
struct 类型 按顺序编码每个字段
enum 类型 一个标签(按与 nat 相同的格式编码)后跟由该标签表示的字段的编码
extern 类型 由目标语言编写的代码定义

结构体

使用多个 版本 定义 struct 类型。每个版本定义一个字段列表。

struct Rectangle {
    version 1 {
        width: u32;
        height: u32;
    }
}

枚举

使用多个 版本 定义 enum 类型。每个版本定义一个用作情况的字段列表。枚举值由这些字段中的 exactly one 个组成。

struct StringOrInt {
    version 1 {
        str: string;
        num: int;
    }
}

外部类型

在用户代码中定义 extern 类型。类型定义、转换和编解码器必须在目标语言中实现。

extern 类型可以声明可用于该类型的文字。

extern MyString {
    literal {
        string;
    }
}

支持以下文字规范。

名称 示例 语法 注意
整数 integer [0, 256) 'integer'open_bracket integer_literal? ','integer_literal?close_bracket
其中 `open_bracket : '['
'('andclose_bracket : ']'
字符串 string 'string' 字符串的内容不能被限制。
序列 序列T '序列'类型表达式 定义指定类型的序列。
情况 情况 正数() '情况'标识符'(' [类型表达式{ ','类型表达式} ] ')' 定义一个情况。如果名称不同,可以指定多个情况字面量。
记录 记录{a:A;b:B; } '记录' '{' {标识符':'类型表达式';' } '}' 定义一个记录。

运行时库类型

运行时库提供了一些extern类型。

类型 字面量 编码
{i,u}{8,16,32,64} 类型范围内的整数 小端顺序的字节固定宽序列
int 整数 一个可变长格式
nat 非负整数 int类似,但没有符号位
string 字符串 长度为nat,后跟一个指定长度的UTF-8字节序列
list T 类型为T的序列 长度为nat,后跟一个类型为T的序列
option T 两种情况some(x)none() 一个字节b。如果b非零,则其后跟一个T

intnat的编码定义了一个小端顺序的位序列。每个字节的最高位如果该数字有更多字节则被设置。

此编码是一个字节序列[B0, ..., Bn],其中当i < n时,Bi,7 = 1,并且Bn,7 = 0。这个字节序列等同于一个位序列[B0,0, ... B0,6, ..., Bn-1,0, ..., Bn-1,6] = [b0, ..., bm-1],其中m = 6n。本质上,位序列移除了用于确定序列何时结束的标志位,并将每个字节中的剩余位从最低到最高排序。位序列映射如下

  • 对于int类型,如果bm-1 = 0,则k = b0 * 20 + ... + bm - 2 * 2m-2
  • 对于int类型,如果bm-1 = 1,则k = -(b0 * 20 + ... + bm - 2 * 2m-2) - 1
  • 对于nat类型,k = b0 * 20 + ... + bm - 1 * 2m-1

版本控制

在下面的示例中,用户有一个用户名和出生日期。

struct Person {
    version 1 {
        name: Name;
        dob: Date;
    }
}

struct Name {
    version 1 {
        firstName: string;
        middleName: option string;
        lastName: string;
    }
}

但是,并非每个人都有2个或3个名字。为了适应这种情况,我们可以创建一个新的版本,允许任意数量的名字。

struct Name {
    version 1 {
        ...
    }
    version 2 {
        names: list string;
    }
}

Name的这种改变意味着在格式的版本2中,Personname字段现在将使用Name的版本2。然而,由于没有对Person的直接更改,版本2是自动创建的。在生成的代码中,预期用户将提供代码以将Name从版本1升级到版本2。但是,没有必要为升级Person提供此类代码。Person可以通过其字段的升级代码自动升级。

最终

可以通过将版本化类型声明为final来表示不会添加该类型的任何新版本。这限制了类型到最后显式声明的版本,防止自动生成新版本。最终类型只能包含最终或非版本化类型的字段。

final struct FormatVersion {
    version 1 {
        major: nat;
    }
}

泛型

泛型类型允许类型参数化。

final struct Pair(A, B) {
    version 1 {
        left: A;
        right: B;
    }
}

常量

常量允许定义在生成语言之间共享的值。

字面量 示例 用法
整数 88 extern 类型与 integer 字面量
字符串 "Hello World" extern 类型与 string 字面量
序列 [a,b,c] extern 类型与 sequence 字面量
记录 {x= 1;y= 2; } struct 类型与 extern 类型与 record 字面量
情况 名称(a) enum 类型与 extern 类型与 case Name 字面量

命令行

Verilization 具有命令行界面。以下选项受到支持。

语言生成器

以下语言受到支持。

编译器绑定

Verilization 编译器是用 Rust 编写的。它可以编译成 WebAssembly 以在其他语言中使用。这具有优势,即工具可以分发(例如,作为 NPM 软件包、独立 JAR 等),而不需要任何本地二进制文件。这些绑定公开了可以直接从运行时使用的界面,以及仅依赖于相关运行时的命令行界面。

目前,以下运行时存在绑定。

  • Node

依赖

~2.5MB
~56K SLoC