braintsck
Version:
Brainfuck to JavaScript compiler in TypeScript
134 lines (99 loc) • 3.52 kB
text/typescript
// -- START HEADER --
// Copyright (c) benja2998. You may redistribute under the terms of the GPL-3.0-or-later.
// brainTSck is a Brainfuck to JavaScript compiler written in TypeScript.
// -- END HEADER --
// -- START IMPORTS --
import * as fs from 'fs';
import * as path from 'path';
// -- END IMPORTS --
// Check if the provided file exists
// If it does, return the contents of the file
// If it doesn't, exit with an error
if (process.argv[2] == undefined) {
console.log("Usage: braintsck <file>");
process.exit(1);
}
const file = process.argv[2];
if (!fs.existsSync(file)) {
console.log(`File ${file} does not exist`);
process.exit(1);
}
const contents = fs.readFileSync(file, 'utf8');
let compiledContents = "";
compiledContents = `#!/usr/bin/env node
// DO NOT MODIFY.
// This is an automatically generated file by brainTSck.
// If you want to modify it, modify ${file} and recompile by running: braintsck ${file}
const TAPE_SIZE = 30000;
const tape = new Uint8Array(TAPE_SIZE);
let pointer = 0;
`
// Display a banner
console.log(`
_ _ _____ ___ _
| |__ _ _ __ _(_)_ |_ _/ __| __| |__
| '_ \\ '_/ _\` | | ' \\| | \\__ \\/ _| / /
|_.__/\\_| \\__,_|_|_||_|_| |___/\\__|_\\_\\
`);
console.log(`Compiling ${file}...`);
console.time("Compilation time");
// In a loop, store each character of <contents> in a variable
for (let i = 0; i < contents.length; i++) {
const char = contents.charAt(i);
switch (char) {
case '+':
console.log("Compiling '+'");
compiledContents += `tape[pointer]++;
`;
break;
case '-':
console.log("Compiling '-'");
compiledContents += `tape[pointer]--;
`;
break;
case '>':
console.log("Compiling '>'");
compiledContents += `pointer = (pointer + 1) % TAPE_SIZE;
`;
break;
case '<':
console.log("Compiling '<'");
compiledContents += `pointer = (pointer - 1 + TAPE_SIZE) % TAPE_SIZE;
`;
break;
case '.':
console.log("Compiling '.'");
compiledContents += `process.stdout.write(String.fromCharCode(tape[pointer]));
`;
break;
case ',':
console.log("Compiling ','");
compiledContents += `{
const buffer = Buffer.alloc(1);
require('fs').readSync(0, buffer, 0, 1, null);
tape[pointer] = buffer[0];
}
`;
break;
case '[':
console.log("Compiling '['");
compiledContents += `while (tape[pointer] != 0) {
`;
break;
case ']':
console.log("Compiling ']'");
compiledContents += `}
`;
break;
default:
console.log(`Skipping ${char}`);
break;
}
}
console.timeEnd("Compilation time");
// Get the file name without the extension
const fileName = path.parse(file).name;
// Write the compiled contents to a file named <fileName>.js
fs.writeFileSync(`${fileName}.js`, compiledContents);
console.log(`Compiled ${file} to ${fileName}.js`);
console.log(`Run it by running: node ${fileName}.js`);