⚠️ 别在家尝试:今天为你的 JS 应用添加 Brainf**k 支持!

发布: (2026年1月18日 GMT+8 03:00)
8 min read
原文: Dev.to

Source: Dev.to

亲爱的 dev.to 管理员们,请耐心看完这篇。
这篇文章会出现一些脏话,正如标题所暗示的那样。不过这些脏话都是包名和实际的技术术语,并无冒犯之意。我会在合适的地方对大多数进行马赛克处理。

又来了。这些东西大概不该在生产环境中使用,因为它们要么完全毫无用处,要么会让维护它的人抓狂,或者让所有人都大喊“不要”“请别这么做”。


这次是关于深奥的编程语言

具体来说,是 Brainf**k,一种 Ook! 的方言,可惜它根本无法被猩猩理解。而且,不,我拒绝相信其实是相反的情况。

Brainf**k 因其难以阅读而臭名昭著。主要原因是它的指令都是单字符,能够将栈指针移动 1 位,或将指针指向的值增加或减少 1,并且只要指针当前指向的栈元素大于 0 就会循环。

我最近写了一篇关于 使用和创建 unplugins 的文章,在文中提到了加入 Brainf**k 支持,并自言自语地想到了:

Bilbo Baggins 提问的表情包

于是我们来了。如果你曾经想把一半的应用程序用一种繁琐、曲折、难以阅读的方式来构建,现在就是时机!而且你甚至可以把它开源,让其他人也这么做!

创建 Unplugin 模板

很直接。我们还需要另一个依赖叫 “hirnf**k”,它是一个把 Brainfk 代码转译为 JS 的库。对于不懂德语的朋友,这个包名的含义是 “brainfk”,就酱。

# Oops – typo!
$ px degit unplugin/unplugin-starter unplugin-bf
bash: px: command not found

哎呀,打错字了。是的,这已经开局不佳。

$ npx degit unplugin/unplugin-starter unplugin-bf
$ cd unplugin-bf/ && npm i -s hirnfick

好多了。

这会创建一个 unplugin 并安装我们的源到源编译器。我们将在 unplugin 的 src/index.ts 文件中实现编译。

查看 hirnf**k 的文档

它包含了一个可以稍作修改的 ESM 示例:

import hirnfick from "https://jspm.dev/hirnfick";

const helloWorldBF =
  "++++++++[>++++[>++>+++>+++>++>+>->>+[>.>---." +
  "+++++++..+++.>>.>+.>++.";

try {
  const helloJs = hirnfick.compileToJsWeb(helloWorldBF);
  const runHello = new Function(`${helloJs} return main().output.trim();`);
  console.log(runHello());
} catch (err) {
  console.error(`Error: ${err.message}`);
}

完美吧?它创建了一个可执行函数,甚至已经包含了一个 Brainf**k 的 “Hello World”。

实现全部功能

这出乎意料地简单。幸运的是,unplugin starter 已经为我们提供了大部分样板代码;我们只需要填补空白即可。

Starter 代码

import type { UnpluginFactory } from "unplugin";
import type { Options } from "./types";
import { createUnplugin } from "unplugin";

export const unpluginFactory: UnpluginFactory = (options) => ({
  name: "unplugin-starter",
  transformInclude(id) {
    return id.endsWith("main.ts");
  },
  transform(code) {
    return code.replace("__UNPLUGIN__", `Hello Unplugin! ${options}`);
  },
});

export const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory);

export default unplugin;

调整样板代码

  1. 更改文件过滤器 – 我们想要匹配 .bf 文件,而不是 main.ts
  2. 重命名 unplugin – 改为 unplugin-bf
  3. 移除未使用的选项
// ...
export const unpluginFactory: UnpluginFactory = () => ({
  name: "unplugin-bf",
  transformInclude(id) {
    return id.endsWith(".bf");
  },
  transform(code) {
    return code;
  },
});

添加实际的编译逻辑

现在我们把 hirnf**k 的示例复制粘贴到 transform 函数中,并稍作调整:

import type { UnpluginFactory } from "unplugin";
import type { Options } from "./types";
import hirnfick from "hirnfick";
import { createUnplugin } from "unplugin";

export const unpluginFactory: UnpluginFactory = () => ({
  name: "unplugin-bf",
  transformInclude(id) {
    return id.endsWith(".bf");
  },
  transform(code) {
    const transformed = hirnfick.compileToJsWeb(code);
    const wrapped = `export default new Function(\`${transformed} return main().output.trim();\`)`;
    return wrapped;
  },
});

export const unplugin = /* #__PURE__ */ createUnplugin(unpluginFactory);

export default unplugin;

信不信由你,我们已经完成了。现在我们的 JS 应用通过这个可爱的 unplugin 已经支持 Brainf**k 了。


工作原理

当 Vite/Rollup(或任何支持 unplugins 的打包工具)处理文件时,它会:

  1. 使用 transformInclude 检查文件名。只有以 .bf 结尾的文件会被传递进去。
  2. 将文件内容code传递给 transform 函数
  3. 使用 hirnfick.compileToJsWeb 将 Brainfk 源码编译成 JavaScript**。
  4. 将生成的 JS 包装在 new Function,该函数返回 Brainf**k 程序的去除首尾空白后的输出。
  5. 将该函数作为模块的默认导出,因此你可以像使用其他 JS 模块一样导入并运行它。

就这么简单——一个小巧、独立的桥梁,把晦涩的语言连接到现代 JavaScript。祝使用愉快!

Brainf**k → JavaScript 编译工作原理

unplugin 获取 .bf 文件的内容(一个字符串),并将其包装在一个导出默认函数的 JavaScript 模块中。
该函数运行编译后的 Brainf**k 代码,并返回 . 命令本应打印的内容,所有空白字符都会被去除。

最小示例

Brainf**k 源码:

+-.

编译后的 JavaScript 如下:

export default new Function(`let position = 0;
const cells = [0];
let output = '';

function putchar() {
  output += String.fromCharCode(cells[position]);
}

function main() {
  if (cells[position]  0) {
    cells[position] -= 1;
  }
  putchar(String.fromCharCode(cells[position]));

  return { cells, output };
}
 return main().output.trim();`)

你可以看到每条 Brainf**k 指令是如何映射到 JavaScript 的:

Brainf**k对应的 JavaScript
+cells[position] += 1;
-cells[position] -= 1;
.putchar(String.fromCharCode(cells[position]));

尝试一下

unplugin‑starter 仓库已经包含了一个 playground,帮你把一切都准备好。

  1. 创建一个 Brainfk 文件**

    hello-world.bf
    ++++++++[>++++[>++>+++>+++>++>+>->>+[>.>---.+++++++..+++.>>.>+.>++.
  2. main.ts 中导入并运行它

    import HelloWorld from './hello-world.bf'
    
    document.body.innerHTML = HelloWorld()

    VSCode 会报错,因为它不知道 .bf 文件会导出 JavaScript,但 unplugin 会在构建时处理它。(未来的 VSCode 插件可以消除这些警告。)

  3. 启动 playground

    cd playground
    npm i && npm run dev

    这会启动一个开发服务器(通常在 http://localhost:3000)。在浏览器中打开它会看到输出:

    Hello World output

    成功了!

⚠️ 警告:不要 在生产代码中使用 Brainf**k。它仅仅是一个有趣的实验。

扩展编译器

  • Input support via the , command.
  • Source maps (good luck!).
  • Ook! language support.

感谢!

我希望你和我写这篇文章时一样享受。如果你喜欢,请留下一个 ❤️。

我在业余时间写技术文章,爱喝咖啡。如果你想支持我的工作,你可以:

你也可以在 Bluesky 🦋 关注我。

请我喝咖啡按钮

Back to Blog

相关文章

阅读更多 »

jQuery 4

请提供您希望翻译的具体摘录或摘要文本,我才能为您进行翻译。

jQuery 4.0.0 发布

请提供您希望翻译的文章摘录或摘要文本,我才能为您进行翻译。