ITADN
README.md
以下内容由 AI 翻译,如有问题请点此提交 issue 反馈

Zena 编程语言

Zena 是一种静态类型编程语言,从底层设计起即可编译为紧凑、高性能的 WebAssembly GC 二进制文件,并配备快速、集成的工具链。它将熟悉的、类似 TypeScript 的语法与现代语言的最佳特性——Swift、Dart、Scala、Go 和 Kotlin——以及健全、注重正确性的类型系统相结合。

let x = 42; // Immutable variable, inferred type
var y: String = "hello"; // mutable variable

interface Animal {
  sayHi(): String;
}

distinct type CatId = String; // Nominal type alias

class Cat implements Animal {
  #greeting = 'Hi'; // Private field
  name = 'Bob'; // Mutable public field
  let id: CatId; // Immutable field
  var(#mood) mood: 'aloof' | 'grumpy'; // Public field, private setter

  // Constructor with initializer list
  new(id: CatId) : id = id {}

  sayHi() {
    return `${this.greeting}, I'm ${this.name}`;
  }
}

// A function that uses pattern matching
export let getChildren = (n: Node) => match (n) {
  case {left, right}: [left, right] // array literal
  case {children}: children
  case _: []
}

// Pipelines
let formatTitle = (title: String) => title
  |> trim($)
  |> titleCase($)
  |> truncate($, 80);

[!WARNING] Zena 非常新,语法可能会发生很大变化!特别是,我们不确定 构造函数的 new(),以及作为类字段修饰符的 letvar……

为什么选择 Zena?

Wasm GC 的甜蜜点

虽然像 Rust 这样的语言在针对 Wasm 线性内存方面表现出色,但 Zena 是专门为 WebAssembly 的托管对象模型(Wasm GC)而设计的。这消除了随 Zena 模块一起分发分配器或垃圾回收器的需求。这种直接映射塑造了 Zena 的设计:

  • 仅限 Wasm 的原语: 基本类型直接映射到 Wasm 原语,实现零转换开销。
  • 原生数组: Zena 数组直接编译为原生 Wasm GC 数组,无需包装器或装箱。
  • 零装箱泛型 直接单态化为具体的 Wasm 类型。
  • 结构化记录与元组 直接编译为原生 Wasm GC 结构体和多值栈返回。
  • Wasm GC 异常 驱动零开销的错误处理。
  • 字符串编码透明性: 字符串隐藏其编码,与宿主特定的字符串编码透明地协同工作(对于多样化的 Wasm 宿主至关重要)。
  • 名义枚举 映射为高效的包装类型。

可预测且一致的语义

Zena 提供简单、符合预期的行为,没有魔法般的意外或隐式强制转换:

  • 一致的作用域: 变量声明默认具有块级作用域且不可变(let),并支持显式的可变性 var
  • 严格的原始类型: 采用不同的原始数值类型(i32i64u32u64f32f64),而非单一的运行时表示。
  • 无隐式类型转换: 在编译时防止意外的类型转换。
  • 清晰的分离: 明确区分结构体记录(用于纯数据)和类(用于具有行为的名义类型)。
  • 更安全的语义: 对可迭代对象和迭代器进行清晰、一致的 for-in 循环迭代。

优先考虑正确性

Zena 高度重视可靠性和类型安全:

  • 健全的类型系统: 静态检查且无逃生机制,确保 Zena 程序不会出现运行时类型错误。
  • 默认安全: 默认不可变、模式匹配的穷尽性检查、受检的类型转换以及不同的类型。
  • 契约: 未来支持前置/后置条件契约和数值单位类型,以便在编译时验证物理量。

现代人体工程学

受 Swift、Dart、Scala、Go 和 Kotlin 启发的开发者生产力特性:

  • 代数数据类型: 通过密封类层次结构、联合类型和记录原生支持。
  • 表达式导向: 诸如 iftrythrow 等控制流构造是求值为值的表达式。
  • 模式匹配: 带有解构的穷尽 match 表达式。
  • 管道: 用于清晰、可读的函数链式调用的 |> 管道运算符。
  • 丰富的对象模型: Dart 风格的构造函数、混入和扩展类。
  • 小巧且快速的二进制文件: 激进的死代码消除会移除未使用的函数、类和类型,生成极小的二进制文件(对于小型程序,小至 37 字节)。

集成工具链

直接内置于单一 CLI 工具中的统一开发体验:

  • 一体化: 包含编译器、测试运行器、LSP 语言服务器、格式化器以及未来的 linting/MCP 工具。
  • 自包含: 整个工具链由 Zena 本身编写并编译为在 Wasm 上原生运行。

WASI 与 WIT 集成(进行中)

对 WebAssembly 组件模型的一等支持:

  • 直接导入/导出: 无需中间 "bindgen" 包装工具,直接导入和导出 WASI 组件。
  • 原生 WIT 解析: Zena 的编译器原生理解 WebAssembly 接口类型(.wit)文件以生成类型安全的绑定。

丰富的标准库(进行中)

基于 WASI 构建的受 Python 启发的“开箱即用”标准库:

  • 核心模块: 包含对单元测试、命令行参数解析、文件系统访问、HTTP 网络、正则表达式以及 JSON 解析的内置支持。

状态

Zena 尚不可用!

Zena 处于非常早期的开发阶段,许多内容可能正在发生变化,包括 语法,以及不可变性等默认设置。许多功能仅部分 实现,且已实现的功能中很可能存在大量隐藏 bug。

目前,功能正在快速添加,标准库正在构建 中,并且正在添加 WASI P2 支持,其直接目标是将 编译器移植到 Zena 并实现自托管。

功能亮点

类、接口和混入

interface Printable {
  toString(): String;
}

mixin Named {
  name: String;
}

class User with Named implements Printable {
  age: i32;

  new(name: String, age: i32) {
    this.name = name;
    this.age = age;
  }

  toString(): String {
    return `${this.name} (${this.age})`;
  }
}

类支持继承、抽象成员、final 密封、私有 # 字段、访问器、运算符重载以及泛型类型参数。接口 使用带有 vtable 的胖指针以实现高效的动态分发。

泛型

泛型是完全单态化的。Array<i32> 存储原始整数,零 装箱开销:

let identity = <T>(x: T): T => x;

identity(42); // monomorphized for i32
identity('hello'); // monomorphized for String

类型参数支持约束(T extends Comparable)和默认值 (T = i32)。F 有界多态(T extends Comparable<T>)即将推出。

运算符重载

Zena 允许类重载 ==[][]=+,更多功能即将推出。

运算符重载应有助于使 Zena 在科学计算 和集合操作中更加易用。由于 final 类成员是静态解析的, 运算符重载不会对内置数组的数组索引造成任何性能影响。

记录与元组

Zena 支持不可变记录和元组。记录是命名 值的集合。元组是固定长度的值列表。

let point = {x: 1.0, y: 2.0};
let items = (1, 'two', 3);

数组

[...] 字面量创建一个 FixedArray<T> —— 一种零开销的固定大小 WASM GC 数组。对于可增长数组,请使用 Array.from()new Array<T>()。 可增长数组的字面量语法正在计划中。

let nums = [1, 2, 3]; // FixedArray<i32>
let grow = Array.from([1, 2, 3]); // Array<i32> (growable)

类型定义

Zena 拥有一组不断扩展的类型表达式,包括基本类型、字面量、 记录、元组、函数和联合类型。

type Pet = Cat | Dog;

Distinct 类型在其他类型之上创建名义类型或“品牌”类型。

distinct type UserId = i32;
distinct type PostId = i32;

let x: UserId = 1 as PostId;  // ❌ Error: type mismatch

Type 类型系统存在限制,以帮助保持类型健全性,并使 WASM 输出 小巧且快速。

例如,联合类型的成员必须可区分,并且能够存储在一个 WASM 值类型中。你不能混合原始类型和引用,因为不存在 允许这样做的 WASM 类型。你必须对原始类型进行装箱:

type NullableId = i32 | null; // ❌ Error
type Nullable<T> = T | null; // ❌ Error: T could be a primitive

type NullableId = Box<i32> | null; // ✅ OK
type Nullable<T extends anyref> = T | null; // ✅ OK

type NullableId = Option<i32>; // ✅ Also OK

枚举

无标签枚举映射为 i32 或 String 作为不同的类型。带有案例类的密封类充当带标签枚举(带有关联数据的枚举)的角色。

enum Direction {
  Up = 'UP',
  Down = 'DOWN',
  Left = 'LEFT',
  Right = 'RIGHT',
}

面向表达式的控制流

ifmatch 是返回值的表达式:

let abs = if (x >= 0) x else -x;

let label = match (level) {
  case 1: "low"
  case 2: "medium"
  case _: "high"
};

模式匹配

模式匹配与 match() 表达式配合使用,该表达式用于检查 完备性:

class Circle { radius: f32; new(radius: f32) { this.radius = radius; } }
class Rect { w: f32; h: f32; new(w: f32, h: f32) { this.w = w; this.h = h; } }

let area = (shape: Circle | Rect): f32 => {
  match (shape) {
    case Circle {radius}: 3.14159 * radius * radius
    case Rect {w, h}: w * h
  }
};

而 while/let 和 if/let 语句:

if ((let(value, true) = map.get(key))) {
  // key was found in the map, value is valid
}

while ((let(value, true) = iterator.next())) {
  // The iterator had another value
}

模式支持字面量、记录、类、守卫、as 绑定以及逻辑 | / & 组合子。穷尽性在编译时进行检查。

多值返回

函数可以返回作为内联元组的多个值,这些值编译为 WASM 的 多值返回,无需堆分配或包装对象:

let divmod = (a: i32, b: i32): (i32, i32) => {
  return (a / b, a % b);
};

let (quot, rem) = divmod(17, 5); // quot = 3, rem = 2

这实现了零分配迭代器:

interface Iterator<T> {
  next(): (T, true) | (never, false);
}

解构

解构是一种始终匹配的模式匹配形式。如果匹配无法保证,则会导致编译错误。

你可以解构对象、记录、元组和内联元组(多值返回):

let {x, y} = point; // Object desctructuring
let (_, _, z) = vec; // Tuples
let (value, found) = map.get(key); // Inline tuples - no heap allocation
let {x, y, z = 0} = point; // Defaults: point can be 2D or 3D
let {r as red, b as blue} = color; // Renaming

Pipeline Operator

|> 运算符将嵌套调用转换为可读的从左到右的流程。$ 占位符标记了管道值的位置:

let result = data |> parse($) |> transform($) |> validate($);

// Equivalent to: validate(transform(parse(data)))

路线图与状态

Zena 目前正处于积极开发阶段。大多数核心语言特性(类、接口、泛型、模式匹配、记录与元组、异常以及代数数据类型)均已完全实现并经过优化(包括死代码消除和零装箱泛型)。

当前重点:自托管编译器

自托管编译器(packages/zena-compiler)使用 Zena 语言本身编写,并且已经通过了所有语法、语言和执行测试。我们目前正在构建一个新的基于 IR 的后端,以解锁高级优化。一旦开发完全迁移到自托管编译器,TypeScript 引导编译器将被弃用。

即将推出的平台特性

  • WASI 组件模型与 WIT:与 WebAssembly 组件模型直接集成,原生导入 .wit 文件。
  • 异步函数与协作式多线程:原生支持异步执行,针对即将推出的 WASM P3 特性,采用协作式多线程。
  • 工具链与开发体验:包管理器、在线游乐场以及增强的 VS Code 集成。

引导后路线图

在弃用引导编译器后,我们计划实现使 Zena 区别于 TypeScript 的标志性特性:

  • 数值单位类型:静态验证的物理单位和度量单位(例如,在编译时防止将米与英尺相加)。
  • SIMD:原生 WebAssembly 向量指令支持,用于高性能计算。
  • 装饰器和宏:用于编译时代码生成和扩展的元编程能力。
  • 契约requiresensures 前置/后置条件,支持运行时断言检查以及未来使用 SMT 求解器进行静态验证。

WASM & WASI

Zena 原生支持 WASM-GC,但也支持更广泛的 WASM 生态系统:

# Compile for a JS host environment
zena build main.zena -o main.wasm --target host

# Compile for WASI
zena build main.zena -o main.wasm --target wasi

# Run with wasmtime
wasmtime run -W gc,function-references,exceptions --invoke main main.wasm

线性内存。 zena:memory 标准库模块提供了用于处理线性内存的工具,当您需要直接的字节级访问时(例如用于二进制格式或与非 GC WASM 模块的互操作),可以使用这些工具。

组件模型。 我们正在努力让 Zena 模块能够直接导入 WIT 文件,无需代码生成步骤,即可生成 WASI 组件和 WIT 接口,且无需任何额外工具。

展望未来。 目前,WASI 组件需要将 GC 类型降级为线性内存。我们期待未来的 WASI 提案能够原生支持 GC 类型,这将使 Zena 组件完全避免降级开销。

正确性

Zena 旨在降低错误发生的概率,无论代码是由人类编写还是由 AI 生成。

健全的类型系统。 变量或参数不应有任何方式谎报其类型。如果一个变量的类型是 String,那么它在运行时确实是一个 String。目前没有已知的破坏健全性的逃生通道。健全性得益于以下几项额外特性:

  • 具体化的泛型 Array<i32>Array<f64> 是不同的类型,即使在运行时也是如此,因此像 x is Array<i32> 这样的运行时类型检查是有效的。
  • 受检的强制转换。 所有 as 强制转换要么在编译时被消除,要么在运行时被验证。
  • 类初始化列表。 构造函数使用初始化列表,保证在对象变得可见之前,所有不可变和非空字段都已设置。不可能泄露一个部分初始化的对象。

某些类型,例如 i32u32boolean,或基于同一底层类型的类型别名,具有相同的底层表示,并且可以在彼此之间进行强制转换,但这不应影响程序类型的整体健全性。

未来的正确性项目 Zena 将继续添加更多有助于确保正确性的功能。

  • 独立类型和度量单位。 独立类型已经允许您以零成本创建类型安全的包装器,因此即使 UserIdPostId 底层都是 i32,它们也不会被意外互换。计划中的数值度量单位将通过更流畅的语法和单位分析进一步扩展此功能,在编译时捕获诸如将米加到英尺之类的错误。
  • 纯粹性。 @pure 注解将函数标记为无副作用。目前,这是被信任的,而非经过验证的,但它记录了意图并支持未来的优化。未来,我们将尝试验证纯粹性注解或自动推断它们。
  • 契约和验证。 我们计划添加 requiresensures 契约,以指定函数期望和保证的内容。运行时契约可以尽早捕获违规。静态验证(通过 SMT 求解器)可以证明契约对所有输入都成立。结合 AI 生成的代码,这创造了一个强大的工作流:AI 编写实现,验证器证明其符合规范。

Zena 与生成式 AI

Zena 主要借助生成式 AI 实现,没有它就不会存在。Zena 始于一次随意的实验:当最新的 AI 模块在处理复杂代码库方面展现出巨大改进时,我们让 Gemini 从零开始创建一种新的编程语言,它做到了!我们有经验去仔细审查的代码看起来不错,因此我们继续要求修改和新功能,Zena 现在正成长为更实质性的东西。

你可以称 Zena 为一种“氛围编码”语言,但这个过程更少“氛围”,更多“指导”。在数百次更改中,有数千个提示。并非所有代码都经过仔细审查,但很多都经过了。与智能体的设计“讨论”帮助塑造了语言和编译器,权衡了 Zena 试图做出的取舍,有时还涉及来自人类和智能体的反对意见。

Zena 仍然是一个实验,只是现在更严肃了。我们试图用 Zena 回答的一些问题包括:

  • 编码智能体能否让一个人或一个极小的团队构建出一门完整的、 生产级质量的编程语言,并包含现代语言所期望的所有工具链和生态系统 组件?
  • 一门新语言能否突破 LLM 训练集的壁垒?许多人 担心如今启动一门新语言已不可能,因为存在于 LLM 训练集中的流行 语言拥有不可逾越的优势。另一方面,LLM 的通用翻译能力可能使得 其生成何种语言变得不那么重要。Zena 正试图做到足够熟悉,以便 通过上下文轻松教会 LLM 如何生成它。
  • 一个项目能否从“氛围编码”标准过渡到正规的工程实践, 同时保持编码智能体带来的巨大加速?
  • 一门编程语言能否帮助改善生成式编码的工作流和 成果?

文档

快速开始

Zena 尚未发布。要从源码构建:

git clone https://github.com/elematic/zena.git
cd zena
npm install
npm run build
npm test

前提条件

  • Node.js v25+
  • npm
  • wasmtime(用于运行 WASI 程序)

许可证

MIT