{"id":21167805,"url":"https://github.com/graypegg/unfuck","last_synced_at":"2025-07-09T17:33:47.502Z","repository":{"id":57386044,"uuid":"66207382","full_name":"graypegg/unfuck","owner":"graypegg","description":":black_flag: An optimizing Brainfuck to Javascript compiler","archived":false,"fork":false,"pushed_at":"2018-04-29T00:28:00.000Z","size":149,"stargazers_count":14,"open_issues_count":0,"forks_count":2,"subscribers_count":4,"default_branch":"master","last_synced_at":"2024-04-23T06:25:14.779Z","etag":null,"topics":["brainfuck","compiler","esolang","esoteric-language","optimiser"],"latest_commit_sha":null,"homepage":"","language":"JavaScript","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/graypegg.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2016-08-21T15:59:24.000Z","updated_at":"2023-06-04T20:43:38.000Z","dependencies_parsed_at":"2022-09-14T16:00:35.498Z","dependency_job_id":null,"html_url":"https://github.com/graypegg/unfuck","commit_stats":null,"previous_names":["toish/unfuck"],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graypegg%2Funfuck","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graypegg%2Funfuck/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graypegg%2Funfuck/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/graypegg%2Funfuck/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/graypegg","download_url":"https://codeload.github.com/graypegg/unfuck/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":225578937,"owners_count":17491282,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["brainfuck","compiler","esolang","esoteric-language","optimiser"],"created_at":"2024-11-20T15:02:32.977Z","updated_at":"2024-11-20T15:02:33.636Z","avatar_url":"https://github.com/graypegg.png","language":"JavaScript","funding_links":[],"categories":[],"sub_categories":[],"readme":"# Unf*ck. [![Build Status](https://travis-ci.org/toish/unfuck.svg?branch=master)](https://travis-ci.org/toish/unfuck) [![codecov](https://codecov.io/gh/toish/unfuck/branch/master/graph/badge.svg)](https://codecov.io/gh/toish/unfuck)\n\nThis module exposes a simple API to convert Brainf*ck to a Javascript function.\n\n## Installation\n```bash\n$ npm install --save unfuck\n```\n\n```javascript\nvar uf = require('unfuck');\n```\n\n## API\n`uf.compiler({ Settings Object })`\n\nReturns a compiler object preloaded with the settings provided.\n\n```javascript\n{\n\ttype: \u003cUint8Array | Uint16Array | Int8Array ... etc\u003e,\n\twidth: \u003cAny Integer\u003e,\n\tin: \u003cNumber | String\u003e,\n\tout: \u003cNumber | String\u003e,\n\ttarget: \u003c'simple-es6' | 'interactive-es6' | 'promise-es6'\u003e,\n}\n```\n\n### type\n**Takes:** An array constructor\u003cbr\u003e\n**Default:** `Uint8Array`\u003cbr\u003e\nDictates the type of the array representing the 'tape'. I suggest using [typed arrays](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/TypedArray#TypedArray_objects) because most versions of Brainfuck require some kind of bounded integer, but you can use the `Array` constructor as a value here for full 64bit integers. (Uint8Array is the most common, this bounds the values in the tape between 0 and 254)\n\n### width\n**Takes:** `Number`\u003cbr\u003e\n**Default:** `10240`\u003cbr\u003e\nThe length of the 'tape'. Values at cells beyond this number, or less than 0, result in a error. You'll want this to be high, but not too high, as all cells are initiated with the value `0`, so 10240 8bit cells uses 10kB of memory at start-up. *(The size of each cell is determined by the type setting)*\n\n### in\n**Takes:** A type constructor (`String` or `Number`)\u003cbr\u003e\n**Default:** `String`\u003cbr\u003e\nThe type of data the resulting javascript function will take as input. (The target option determines the source of input.)\n\n* If it's set to `String`, the function will insert each [charCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/charCodeAt) sequentially when `,` is used.\n* If it's set to `Number`, the function will insert the number supplied as input sequentially when `,` is used.\n\n### out\n**Takes:** A type constructor (`String` or `Number`)\u003cbr\u003e\n**Default:** `String`\u003cbr\u003e\nThe type of data the resulting javascript function will return or include in it's output callback. (The target option determines the mode of output.)\n\n* If it's set to `String`, the function will convert the number on the tape to a character via [fromCharCode](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/String/fromCharCode)\n* If it's set to `Number`, the function will return the numerical value of the cell on the tape.\n\n### target\n**Takes:** `String`\u003cbr\u003e\n**Default:** `'simple-es6'`\u003cbr\u003e\nUnfuck comes with a couple different compilation targets which affect how the outputted javascript can be used.\n\n| Name | Description | Example Usage |\n| :--: | ----------- | ------------- |\n| `'simple-es6'` | Input is taken as an `Array` or `String` *(depending input type, `Number` and `String` respectively)* in the first and only parameter of the outputted javascript function. Each instance of `,` in Brainfuck will take the first element off of this array and insert it onto the tape.  Every instance of `.` will add the current cell's value to either an Array or a String *(depending output type, `Number` and `String` respectively)* that is returned **after halting**. | `c.use(',-.')([4,3])`\u003cbr\u003e`c.use(',-.')('abc')` |\n| `'interactive-es6'` | Input is received synchronously from the first parameter to the outputted javascript function, it should be a function which can take the current cell value as it's first parameter. The output is also processed synchronously by the second parameter which should be a function that takes the current cell as it's first parameter. | `c.use(',-.')((x)=\u003e{`\u003cbr\u003e\u0026nbsp;\u0026nbsp;`getLine('Number?')`\u003cbr\u003e`}, (x)=\u003e{`\u003cbr\u003e\u0026nbsp;\u0026nbsp;`console.log(x)`\u003cbr\u003e`})` |\n| `'promise-es6'` | Input is taken as an `Array` or `String` *(depending input type, `Number` and `String` respectively)* in the first and only parameter of the outputted javascript function. Each instance of `,` in Brainfuck will take the first element off of this array and insert it onto the tape. Every instance of `.` will add the current cell's value to either an Array or a String *(depending output type, `Number` and `String` respectively)* that is returned in a Promise that will **resolve after the brainfuck program halts**. (The promise is returned immediately.) Any errors are caught inside the promise and get rejected. | `f(out){ console.log(out) }`\u003cbr\u003e`c.use(',-.')([4,3]).then(f)`\u003cbr\u003e`c.use(',-.')('abc').then(f)` |\n\n---\n\n`compiler.compile( Brainfuck String )`\n\nReturns an object containing the sanitized brainfuck code, a copy of the Abstract Syntax Tree, and the outputted compiled code in a string. See example below for example output of this function.\n\n---\n\n`compiler.use( Brainfuck String )`\n\nReturns a real Javascript function which takes input as it's only parameter and returns output, both in the type specified by the compiler object.\n\n---\n\n`compiler.run( Brainfuck String, Input )`\n\nExecutes the brainfuck function with input. Input should be pre-formatted to the compilers specs. (I.E. Number =\u003e [Int], String =\u003e \"String\")\n\n\n## Examples\n\n### Basic Use\nIf you just want to test out the compiler, you can run a simple hello world program using this:\n\n```javascript\n// Import Unfuck module.\nvar uf = require('unfuck');\n\n// Create a compiler using the default configuration.\nvar compiler = uf.compiler();\n\n// Output 'Hello World!' to the console. \nconsole.log(\n\tcompiler.run( // Runs the compiled JS function right after compiling.\n\t\t'++++++++[\u003e++++[\u003e++\u003e+++\u003e+++\u003e+\u003c\u003c\u003c\u003c-]\u003e+\u003e+\u003e-\u003e\u003e+[\u003c]\u003c-]\u003e\u003e.\u003e---.+++++++..+++.\u003e\u003e.\u003c-.\u003c.+++.------.--------.\u003e\u003e+.\u003e++.', // The brainfuck program itself.\n\t\t'' // This is for program input, which the hello world program doesn't utilize\n\t)\n);\n```\n\n### Compilation output with Abstract Syntax Tree\nUsing the `.compile()` method lets you access a copy of the generated AST, for whatever reason you need it for.\n\n\n```javascript\nvar uf = require('unfuck');\n\nvar compiler = uf.compiler({\n\ttype: Uint16Array,\n\tin: Number,\n\tout: String,\n\twidth: 9999\n});\n\nconsole.log( compiler.compile('++++++[\u003e++++++++++\u003c-]\u003e+++++.') );\n```\n\nWhich outputs the following:\n\n```javascript\n{\n    \"bf\": \"++++++[\u003e++++++++++\u003c-]\u003e+++++.\",\n    \"ast\": [\n        {\n            \"is\": \"SFT\",\n            \"body\": 6\n        },\n        {\n            \"is\": \"MUL\",\n            \"body\": {\n                \"factors\": [\n                    {\n                        \"move\": 1,\n                        \"factor\": 10\n                    }\n                ]\n            }\n        },\n        {\n            \"is\": \"RELSFT\",\n            \"body\": {\n                \"value\": 5,\n                \"move\": 1\n            }\n        },\n        {\n            \"is\": \"MOV\",\n            \"body\": 1\n        },\n        {\n            \"is\": \"OUT\"\n        }\n    ],\n    \"out\": \"(function(i){var i=i.split('').map(x=\u003ex.charCodeAt())||[];var o=[];var t=new Uint8Array(30000);var p=0;t[p]+=6;t[p+1]+=t[p]*10;t[p]=0;t[p+1]+=5;p+=1;o.push(t[p]);return o.map(x=\u003eString.fromCharCode(x)).join('');})\"\n}\n```\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraypegg%2Funfuck","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fgraypegg%2Funfuck","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fgraypegg%2Funfuck/lists"}