⚠️ 집에서 시도하지 마세요: 오늘 JS 앱에 Brainf**k 지원을 추가하세요!

발행: (2026년 1월 18일 오전 04:00 GMT+9)
10 min read
원문: Dev.to

Source: Dev.to

dev.to의 운영자 여러분, 이번 글은 조금 양해 부탁드립니다.
이 글에는 제목에서 짐작하셨겠지만 몇몇 욕설이 포함될 것입니다. 하지만 그 욕설들은 패키지 이름과 실제 기술 용어이며, 누구를 모욕하려는 의도는 전혀 없습니다. 가능한 한 적절히 검열하려고 합니다.

그리고 다시 시작합니다. 프로덕션에서 절대 해서는 안 될 일들입니다. 완전히 쓸모 없거나, 유지보수하는 사람들을 완전히 혼란스럽게 만들거나, 모두가 “아니요”와 “제발 하지 마세요”라고 외치게 만들 것입니다.


이번에는 난해한 프로그래밍 언어

특히, Brainf**k, Ook!의 방언으로, 안타깝게도 오랑우탄은 이해할 수 없습니다. 그리고 아니요, 제가 실제로는 반대라고 믿는 것을 거부합니다.

Brainf**k은 악명 높게 읽기 어렵습니다. 대부분 그 명령이 단일 문자이며, 스택 포인터를 1만큼 이동하고, 포인터가 가리키는 값은 1만큼 증가하거나 감소시키며, 포인터가 가리키는 현재 스택 요소가 0보다 큰 동안 루프를 돌기 때문입니다.

저는 최근에 unplugins 사용 및 생성에 관한 글을 썼으며, 그 안에서 Brainf**k 지원을 추가하는 이야기를 언급하고는 스스로 생각했습니다:

빌보 배긴스가 묻는 밈

그래서 여기까지 왔습니다. 만약 여러분이 앱의 절반을 번거롭고 복잡하며 읽을 수 없는 방식으로 만들고 싶다면, 지금이 그때입니다! 그리고 이를 오픈소스로 공개해서 다른 사람들도 똑같이 할 수 있게 할 수 있습니다!

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 스타터가 대부분의 보일러플레이트를 이미 제공하므로, 우리는 빈틈만 채우면 됩니다.

스타터 코드

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. 파일 필터 변경main.ts 대신 .bf 파일을 원합니다.
  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;

믿거나 말거나, 이제 끝났습니다. 이제 우리의 멋진 unplugin을 통해 JS 앱에서 Brainf**k을 지원합니다.

작동 방식

  1. 파일 이름을 확인 transformInclude를 사용합니다. .bf로 끝나는 파일만 통과됩니다.
  2. 파일 내용 (code)을 transform 함수에 전달합니다.
  3. Brainfk 소스**를 hirnfick.compileToJsWeb을 사용해 JavaScript로 컴파일합니다.
  4. 생성된 JSnew Function으로 감싸서 Brainf**k 프로그램의 트림된 출력을 반환합니다.
  5. 함수를 내보냅니다 모듈의 기본 내보내기로, 따라서 다른 JS 모듈처럼 import하고 실행할 수 있습니다.

끝입니다 – 이국적인 언어를 현대 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**kJavaScript 등가
+cells[position] += 1;
-cells[position] -= 1;
.putchar(String.fromCharCode(cells[position]));

직접 사용해 보기

unplugin‑starter 저장소에는 모든 설정이 이미 준비된 플레이그라운드가 포함되어 있습니다.

  1. Brainfk 파일 만들기**

    hello-world.bf
    ++++++++[>++++[>++>+++>+++>++>+>->>+[>.>---.+++++++..+++.>>.>+.>++.
  2. main.ts에서 가져와 실행하기

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

    VSCode는 .bf 파일이 JavaScript를 내보낸다는 것을 알지 못해 경고를 표시하지만, unplugin이 빌드 시 이를 처리합니다. (향후 VSCode 확장으로 이러한 경고를 없앨 수 있습니다.)

  3. 플레이그라운드 시작하기

    cd playground
    npm i && npm run dev

    이렇게 하면 개발 서버가 실행됩니다(보통 http://localhost:3000). 브라우저에서 열면 다음과 같은 출력이 표시됩니다:

    Hello World 출력

    정상적으로 동작합니다!

⚠️ 경고: 프로덕션 코드에 Brainf**k를 사용하지 마세요. 재미있는 실험일 뿐입니다.

컴파일러 확장

모험을 원한다면, 추가 기능을 넣을 수 있습니다:

  • 입력 지원, 명령으로.
  • 소스 맵 (행운을 빕니다!).
  • Ook! 언어 지원.

감사합니다!

이 글을 쓰는 만큼 여러분도 즐겁게 읽으셨길 바랍니다. 마음에 드셨다면 ❤️를 남겨 주세요.

저는 여가 시간에 기술 글을 쓰고 커피를 사랑합니다. 제 작업을 지원하고 싶으시다면 다음을 이용해 주세요:

또한 Bluesky 🦋에서 저를 팔로우하실 수 있습니다.

Buy me a coffee button

Back to Blog

관련 글

더 보기 »

jQuery 4

죄송하지만 현재 외부 웹사이트의 내용을 직접 확인할 수 없습니다. 번역을 원하시는 텍스트를 직접 제공해 주시면 한국어로 번역해 드리겠습니다.

jQuery 4.0.0 출시

번역할 텍스트를 제공해 주시겠어요? 텍스트를 알려주시면 한국어로 번역해 드리겠습니다.