javascript

This commit is contained in:
nora 2022-05-16 12:25:31 +02:00
parent a52cbda492
commit 54b5c9b1f8
7 changed files with 186 additions and 54 deletions

2
js/.gitignore vendored Normal file
View file

@ -0,0 +1,2 @@
node_modules
.idea

4
js/.prettierrc.json Normal file
View file

@ -0,0 +1,4 @@
{
"singleQuote": true,
"printWidth": 100
}

2
js/fizzbuzz.bf vendored Normal file
View file

@ -0,0 +1,2 @@
++[-].

10
js/package.json Normal file
View file

@ -0,0 +1,10 @@
{
"name": "brainfuck",
"version": "1.0.0",
"main": "src/index.js",
"license": "MIT",
"type": "module",
"devDependencies": {
"prettier": "^2.6.2"
}
}

110
js/src/index.js Normal file
View file

@ -0,0 +1,110 @@
import fs from 'fs/promises';
function lex(string) {
const tokens = [];
for (let i = 0; i < string.length; i++) {
const char = string[i];
if (['+', '-', '>', '<', '.', ',', '[', ']'].includes(char)) {
tokens.push({
char,
span: i
});
}
}
return tokens;
}
function ParseError(message, span) {
this.message = message;
this.span = span;
}
function Parser(tokens) {
this.tokens = tokens;
this.position = 0;
}
Parser.prototype.next = function() {
const token = this.tokens[this.position];
this.position++;
return token;
};
Parser.prototype.parse = function(isLoop) {
const body = [];
let nextToken;
while ((nextToken = this.next()) !== undefined) {
switch (nextToken.char) {
case '[': {
const loopBody = this.parse(true);
body.push(loopBody);
break;
}
case ']': {
if (isLoop) {
return body;
} else {
throw new ParseError('No matching `[` found', nextToken.span);
}
}
default: {
body.push(nextToken);
}
}
}
if (isLoop) {
throw new ParseError('No matching `]` found', this.tokens[this.tokens.length - 1].span);
} else {
return body;
}
};
function reportError(source, message, span) {
let lineIdx = 0;
let lastNewlineIdx = 0;
for (let i = 0; i < source.length; i++) {
const char = source[i];
if (i === span) {
break;
}
if (char === '\n') {
lineIdx++;
lastNewlineIdx = i;
}
}
const lines = source.split('\n');
const line = lines[lineIdx];
const lineNumber = String(lineIdx + 1);
const linePrefix = `${lineNumber} | `;
const lineSpan = span - lastNewlineIdx;
console.error(`error: ${message}`);
console.error(`${linePrefix}${line}`);
console.error(`${' '.repeat(linePrefix.length)}${'-'.repeat(lineSpan)}^`);
}
const file = process.argv[2];
if (!file) {
console.error('Usage: [filename]');
process.exit(1);
}
const source = await fs.readFile(file, 'utf-8');
const tokens = lex(source);
const parser = new Parser(tokens);
try {
const ast = parser.parse(false);
console.log(ast);
} catch (parseError) {
if (!(parseError instanceof ParseError)) {
throw parseError;
}
reportError(source, parseError.message, parseError.span);
}

8
js/yarn.lock Normal file
View file

@ -0,0 +1,8 @@
# THIS IS AN AUTOGENERATED FILE. DO NOT EDIT THIS FILE DIRECTLY.
# yarn lockfile v1
prettier@^2.6.2:
version "2.6.2"
resolved "https://registry.yarnpkg.com/prettier/-/prettier-2.6.2.tgz#e26d71a18a74c3d0f0597f55f01fb6c06c206032"
integrity sha512-PkUpF+qoXTqhOeWL9fu7As8LXsIUZ1WYaJiY/a7McAQzxjk82OF0tibkFXVCDImZtWxbvojFjerkiLb0/q8mew==