ARTICLE · INTELLIGENCE

战地情报 · 详情页

来自尧图项目组的一线实战观察与深度解析

Kip WASM Playground:把整套Haskell编译器搬进浏览器的完整方案

Kip WASM Playground:把整套Haskell编译器搬进浏览器的完整方案

【免费下载链接】kip

A programming language in Turkish where grammatical case and mood are part of the type system.

项目地址:https://gitcode.com/gh_mirrors/kip2/kip
点击查看免费下载

Kip WASM Playground 是一个把 Kip 语言(一门把土耳其语语法格纳入类型系统的实验性编程语言)的完整编译器打包成 WebAssembly,让你直接在浏览器里编写、运行 Kip 程序的在线试验场(Playground)。无需安装任何工具链,打开网页点一下 Run 按钮,整套基于 Haskell 实现的解析器、类型检查器、解释器以及 Foma 形态分析库都会在浏览器里完成一次真实的编译执行。

为什么值得了解这个方案

Kip 是一种以语言学研究为目标的实验性编程语言:函数签名的"格"(nominative、accusative 等)是类型的一部分,当参数格不同时,参数顺序可以自由调换。语言本身用 Haskell 编写,核心模块位于 src/Kip/ 目录(如 Parser.hs、TypeCheck.hs)。

而 WASM Playground 的意义在于:

  • 🌐零安装体验:编译产物kip-playground.wasm由浏览器原生 WebAssembly 引擎执行,用户不需要装 GHC、Foma 或 Stack
  • 🧩完整语义:不是阉割版解释器,而是同一套kip-playground运行器的 WASM 构建,连 JS 代码生成(--codegen js)都能在页面上用
  • ⚡秒级复用:采用 WASI Reactor 模式,一次加载、多次运行,配合.iz字节码缓存,二次运行非常快

整体构建与部署流程记录在 playground/README.md。

整体架构:一个 WASM 实例如何承载整套编译器

整个浏览器端方案由三部分组成,对应仓库中三个关键文件:

组件文件职责
Reactor 入口app/PlaygroundReactor.hs以 WASI reactor 模式导出kip_run函数,供浏览器反复调用
前端编排playground/kip-worker.js在 Web Worker 中构建内存版 WASI 文件系统,加载并运行 WASM
页面 UIplayground/playground.js 与 playground/index.html源码编辑器、输出终端、示例选择、JS 生成面板

几个关键设计点值得新手学习:

  1. Reactor 而非 Command 模式:常规 WASM 程序像命令行进程一样"跑完即退出",而 app/PlaygroundReactor.hs 导出的kip_run让同一个 WASM 实例可以被调用多次。Worker 会检测导出表里是否有kip_run来自动区分两种运行模式(见 kip-worker.js)。
  2. 内存版虚拟文件系统:playground/build-assets.sh 会把标准库 lib/ 和形态分析资源vendor/trmorph.fst复制到dist/assets/,运行时挂载为 WASI 根目录下的/lib与/vendor,用户代码则固定放在/main.kip。
  3. C 语言 Foma 依赖也要编译到 WASM:Kip 通过 FFI 调用 C 库 Foma 做土耳其语形态分析(src/Language/Foma.hs),所以 Playground 还需要用 WASI-SDK 把libfoma.a交叉编译成 WASM 版本,构建脚本为 playground/build-foma-wasm.sh。

一键构建步骤:从源码到浏览器可用的 Playground

构建需要三样前置工具:GHC WASM 工具链(wasm32-wasi-ghc)、WASI-SDK、以及 Foma 的 WASM 构建。macOS 上最快的方式是官方ghc-wasm-meta安装脚本(详见 playground/README.md)。

配置好环境变量后,一条命令完成全部构建:

source playground/.ghc-wasm/env export WASI_SDK_PATH=.../playground/.ghc-wasm/wasi-sdk export FOMA_WASM_PREFIX=.../playground/foma-wasm ./playground/build-wasm.sh

playground/build-wasm.sh 内部做了这些事:

  • 用wasm32-wasi-cabal以-O2优化级别编译kip-playground-reactor可执行文件
  • 用wasm-opt -O3做后链接优化,进一步压缩 WASM 体积
  • 调用 build-assets.sh 拷贝标准库、trmorph.fst和 tests/succeed/ 下全部成功示例到dist/
  • 调用 build-iz-wasm.sh 用 wasmtime预编译.iz字节码缓存——这是提速的关键一步

构建产物输出到playground/dist/:kip-playground.wasm、index.html、playground.js、assets/lib/等。

本地快速部署:最快配置方法

构建完成后,用任意静态服务器托管playground/dist即可:

node playground/serve.js # 或最简方式(但不支持交互式 stdin) python3 -m http.server --directory playground/dist 8001

打开http://localhost:8001就能写代码、选示例、点 Run。

如何开启交互式输入(stdin)支持

如果程序需要读取标准输入(比如 Kip 的oku原语),浏览器要求页面启用跨源隔离,即响应头:

  • Cross-Origin-Opener-Policy: same-origin
  • Cross-Origin-Embedder-Policy: require-corp

这正是 playground/serve.js 比python3 -m http.server多做的事。Worker 端用Atomics.wait阻塞等待主线程把键盘输入送进内存缓冲区,实现真正的交互式终端(kip-worker.js)。

部署到无法自定义响应头的静态托管时,页面会回退使用 playground/coi-serviceworker.js 通过 Service Worker 注入这两个头部(需 HTTPS)。

Playground 界面能做什么

打开页面后,核心功能都集中在 playground/index.html 的 Playground 区块:

  • 📝写代码:左侧源码面板带 Kip 语法高亮(高亮规则在 playground/kip-syntax.js)
  • 🚀运行 / 停止:一次点击完成"写入/main.kip→ 调用 WASM → 收集 stdout"全流程
  • 📚内置示例:下拉框里是 tests/succeed/ 的 100+ 个官方示例,如selamlamak.kip、fibonacci.kip
  • ⚙️Generate JavaScript:同一份 Kip 代码可现场生成 JavaScript 输出到独立面板,方便在浏览器外继续实验
  • 🌍中英双语:UI 与诊断信息支持 en/tr 一键切换
  • 🎮附加彩蛋:还附带一个 playground/quiz/index.html 的编程小测验页面

性能优化清单:让浏览器里跑编译器不卡顿

这套方案里有几个值得借鉴的优化技巧:

  1. .iz字节码缓存:Kip 把类型检查过的模块缓存为.iz文件(机制在 src/Kip/Cache.hs)。Playground 构建时用 wasmtime 预生成标准库的.iz并随静态资源分发,浏览器里再加载时跳过重复的类型检查
  2. WASM 模块只编译一次:Worker 用WebAssembly.compileStreaming在页面加载阶段预热编译(kip-worker.js),后续每次运行只做廉价的实例化
  3. 标准库文件带负缓存:.kip/.iz/trmorph.fst首次 fetch 后缓存在 Worker 内存中,缺失文件也会记住,避免重复 404
  4. Reactors 复用 + 无缓冲 stdio:长生命周期的 WASM 实例避免了每次运行重新初始化 Haskell RTS;输出流设为无缓冲防止大段代码生成结果被截断(app/PlaygroundReactor.hs)
  5. 每次运行状态隔离:kip_run内部通过runPlaygroundRequest保证全新运行时状态(见 src/Kip/Playground.hs),用户上一次的自定义定义不会泄漏到下一次运行

延伸阅读

  • 语言特性与本地安装:README.md
  • WASM Playground 完整构建指南:playground/README.md
  • 构建脚本:playground/build-wasm.sh、playground/build-foma-wasm.sh
  • 编译器入口实现:app/Playground.hs、app/PlaygroundReactor.hs
  • 浏览器 Worker 实现:playground/kip-worker.js

这套方案证明:只要编译器用 Haskell 这类可移植语言写成、C 依赖能交叉编译到 WASI,"把整门语言装进浏览器"完全可行——而且连交互式终端都能做出来。

【免费下载链接】kip

A programming language in Turkish where grammatical case and mood are part of the type system.

项目地址:https://gitcode.com/gh_mirrors/kip2/kip
点击查看免费下载

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

RELATED READING

延伸阅读

更多一线实战笔记与深度复盘,助您持续精进