Skip to content

synthetic-borealis/hirnfick

Repository files navigation

Hirnfick

GitHub license npm version Tests codecov npm downloads

A Brainfuck source-to-source compiler that runs in Node.js, Deno and web-browsers.

Contents

  1. Installation
  2. Usage
    1. Compiler
    2. Library
  3. Supported Output Languages
  4. Examples

Installation

Run npm i -g hirnfick to install globally or npm i hirnfick to install for a single project.

Usage

C++ style comments (i.e. // I'm a comment and /* I'm a comment too */) are supported.

Compiler

  hirnfick -i [input file] -o [output file] options

Options:

  • --lang [language] - Output language (default=js-node).
    • Supported options: js-web, js-node, js-deno, python, c, cpp, qbasic, pascal, rust.
  • --memory-size [fixed|dynamic] - Type of cells array (default=fixed).

Library

  • Use compileTo[VARIANT]() where [VARIANT] is the output language/variant ( e.g. compileToJsWeb()).
  • compileToJsWeb() generates a function that returns an object with two members:
    1. output - The output of the program.
    2. cells - The array of cells that were used by the program.
  • QBasic programs with dynamic arrays require PDS 7.1 or FreeBASIC to compile.
  • C++/JS style comments are supported.
  • For more information see the documentation.

Supported Output Languages

  • JavaScript.
  • Python.
  • C.
  • C++.
  • QBasic (manually tested with FreeBASIC 1.09.0, QuickBASIC 4.5 and PDS 7.1).
  • Pascal (tested with Free Pascal 3.2.2 and Borland Pascal 7.0).
  • Rust.

Table 1: Supported Commands by Output Language

Language > < + - . , [ ] Memory Size
JavaScript (Web) 30,000/Dynamic
JavaScript (Node.js) 30,000/Dynamic
JavaScript (Deno) 30,000/Dynamic
Python 30,000/Dynamic
C 30,000
C++ 30,000/Dynamic
QBasic 30,000/Dynamic
Pascal 30,000
Rust 30,000/Dynamic

Examples

CommonJS (Node)

const hirnfick = require('hirnfick');

const helloWorldBF = '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.'
  + '+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.';

try {
  const helloWorldJS = hirnfick.compileToJsNode(helloWorldBF);
  const helloWorld = new Function(`${helloWorldJS}`);
  helloWorld();
} catch (err) {
  console.error(`Error: ${err.message}`);
}

Syntax Checking - CommonJS (Node)

const hirnfick = require('hirnfick');

// This code prints 'Hello World!' to the screen
const validCode = '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>.'
  + '<-.<.+++.------.--------.>>+.>++.';

// This code has a mismatching numbers of opening brackets and closing brackets
const invalidCode = '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.+++++++..+++.>>'
  + '.<-.<.]]].------.--------.>>+.>++.';

console.log(hirnfick.hasMismatchingLoopBoundaries(validCode)); // false
console.log(hirnfick.hasMismatchingLoopBoundaries(invalidCode)); // true

ESM (Node)

import * as hirnfick from 'hirnfick';

const helloWorldBF = '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.'
  + '+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.';

try {
  const helloWorldJS = hirnfick.compileToJsNode(helloWorldBF);
  const helloWorld = new Function(`${helloWorldJS}`);
  helloWorld();
} catch (err) {
  console.error(`Error: ${err.message}`);
}

ESM (Deno)

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}`);
}

TypeScript (Deno)

import * as hirnfick from "https://cdn.jsdelivr.net/gh/synthetic-borealis/hirnfick/deno/index.ts";

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}`)
}

Web

<!DOCTYPE html>
<html lang="en">
  <head>
    <meta charset="UTF-8">
    <meta http-equiv="X-UA-Compatible" content="IE=edge">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>Document</title>
    <script src="https://unpkg.com/[email protected]/dist/hirnfick.js"></script>
  </head>
  <body>
    <p>
      <textarea id="output-box" readonly rows="14" cols="24"
                style="width: 90%;resize: none;"></textarea>
    </p>
    <button id="run-button">Run</button>
    <script>
      const runButton = document.getElementById('run-button');
      const outputBox = document.getElementById('output-box');
      const helloWorldBF = '++++++++[>++++[>++>+++>+++>+<<<<-]>+>+>->>+[<]<-]>>.>---.'
        + '+++++++..+++.>>.<-.<.+++.------.--------.>>+.>++.';

      outputBox.value = '';
      runButton.addEventListener('click', () => {
        try {
          const helloWorldProgram = hirnfick.compileToJsWeb(helloWorldCode);
          const helloWorld = new Function(`${helloWorldProgram} return main().output;`);

          outputBox.value += helloWorld();
        } catch (err) {
          outputBox.value = `Error: ${err.message}`;
        }
      });
    </script>
  </body>
</html>