mirror of
https://github.com/osmarks/random-stuff
synced 2024-11-09 13:59:55 +00:00
178 lines
3.9 KiB
JavaScript
178 lines
3.9 KiB
JavaScript
|
const { regex, sequenceOf, char, choice, many1, many, str, coroutine, possibly } = require("arcsecond")
|
||
|
const readline = require("readline-sync")
|
||
|
|
||
|
const spaces = regex(/^ */)
|
||
|
const whitespace = regex(/^[ \n\t]*/)
|
||
|
const name = regex(/^[^ \n\t():]+/)
|
||
|
const code = many(coroutine(function*() {
|
||
|
yield spaces
|
||
|
return yield choice([
|
||
|
coroutine(function*() {
|
||
|
yield char("(")
|
||
|
const x = yield code
|
||
|
yield spaces
|
||
|
yield char(")")
|
||
|
return x
|
||
|
}),
|
||
|
name
|
||
|
])
|
||
|
}))
|
||
|
const program = sequenceOf([
|
||
|
many1(coroutine(function*() {
|
||
|
yield whitespace
|
||
|
const n = yield name
|
||
|
yield whitespace
|
||
|
yield str(":=")
|
||
|
const c = yield code
|
||
|
return { code: c, name: n }
|
||
|
})),
|
||
|
possibly(whitespace)
|
||
|
]).map(([x, _]) => x)
|
||
|
|
||
|
const parsed = program.run(`_mulloop := (pop warp new new new new new new new new new new warp _mulloop)
|
||
|
10* := warp new enter warp _mulloop exit pop warp exit send warp enter
|
||
|
[ := new enter
|
||
|
0 := 10*
|
||
|
1 := 10* new
|
||
|
2 := 10* new new
|
||
|
3 := 10* new new new
|
||
|
4 := 10* new new new new
|
||
|
5 := 10* new new new new new
|
||
|
6 := 10* new new new new new new
|
||
|
7 := 10* new new new new new new new
|
||
|
8 := 10* new new new new new new new new
|
||
|
9 := 10* new new new new new new new new new
|
||
|
] := exit
|
||
|
. := ] write [
|
||
|
|
||
|
main := [ 7 2 . 1 0 1 . 1 0 8 . 1 0 8 . 1 1 1 . 4 4 . 3 2 . 1 1 9 . 1 1 1 . 1 1 4 . 1 0 8 . 1 0 0 . 3 3 . 1 0 . ]
|
||
|
`).result
|
||
|
//const parsed = program.run(`main := read write main`).result
|
||
|
|
||
|
// ---------
|
||
|
|
||
|
let stackL = {depth: 0, children: []}, stackR = {depth: 0, children: []};
|
||
|
let currentIsLeft = true;
|
||
|
|
||
|
function depthDelta(x) {
|
||
|
if(currentIsLeft)
|
||
|
stackL["depth"]+=x;
|
||
|
else
|
||
|
stackR["depth"]+=x;
|
||
|
}
|
||
|
|
||
|
function currentStack() {
|
||
|
let depth, currentStack;
|
||
|
|
||
|
if(currentIsLeft) {
|
||
|
depth = stackL["depth"];
|
||
|
currentStack = stackL["children"];
|
||
|
} else {
|
||
|
depth = stackR["depth"];
|
||
|
currentStack = stackR["children"];
|
||
|
}
|
||
|
|
||
|
for(let i = 0; i < depth; i++) {
|
||
|
const s = currentStack.length - 1
|
||
|
currentStack = currentStack[s];
|
||
|
}
|
||
|
|
||
|
return currentStack;
|
||
|
}
|
||
|
|
||
|
// ---------
|
||
|
|
||
|
function wrap_new() {
|
||
|
currentStack().push([]);
|
||
|
}
|
||
|
|
||
|
function wrap_pop() {
|
||
|
currentStack().pop();
|
||
|
}
|
||
|
|
||
|
function wrap_enter() {
|
||
|
depthDelta(1)
|
||
|
}
|
||
|
|
||
|
function wrap_exit() {
|
||
|
depthDelta(-1)
|
||
|
}
|
||
|
|
||
|
function wrap_warp() {
|
||
|
currentIsLeft = !currentIsLeft;
|
||
|
}
|
||
|
|
||
|
function wrap_send() {
|
||
|
let toMove = currentStack().pop();
|
||
|
|
||
|
wrap_warp();
|
||
|
|
||
|
currentStack().push(toMove);
|
||
|
|
||
|
wrap_warp()
|
||
|
}
|
||
|
|
||
|
function wrap_read(n) {
|
||
|
let thisStack = [];
|
||
|
|
||
|
for(let i = 0; i < n; i++) {
|
||
|
thisStack.push([]);
|
||
|
}
|
||
|
|
||
|
currentStack().push(thisStack);
|
||
|
}
|
||
|
|
||
|
function wrap_write() {
|
||
|
return currentStack().pop().length;
|
||
|
}
|
||
|
|
||
|
// ---------
|
||
|
|
||
|
const env = {
|
||
|
warp: wrap_warp,
|
||
|
read: () => {
|
||
|
wrap_read(readline.question("input char: ").codePointAt(0))
|
||
|
},
|
||
|
write: () => {
|
||
|
console.log("output char:", String.fromCodePoint(wrap_write()))
|
||
|
},
|
||
|
send: wrap_send,
|
||
|
exit: wrap_exit,
|
||
|
enter: wrap_enter,
|
||
|
pop: wrap_pop,
|
||
|
new: wrap_new,
|
||
|
}
|
||
|
|
||
|
for (const def of parsed) {
|
||
|
env[def.name] = def.code
|
||
|
}
|
||
|
|
||
|
const DEBUG = false
|
||
|
|
||
|
const execute = code => {
|
||
|
for (const fn of code) {
|
||
|
//console.log("stacks", stackL, stackR)
|
||
|
// is bracketed, run if stack not empty
|
||
|
if (Array.isArray(fn)) {
|
||
|
if (currentStack().length !== 0) {
|
||
|
if (DEBUG) console.log("brackets", fn)
|
||
|
execute(fn)
|
||
|
}
|
||
|
// is a regular function call or whatever, run it
|
||
|
} else {
|
||
|
const v = env[fn]
|
||
|
if (!v) {
|
||
|
throw new Error(fn + " is undefined")
|
||
|
}
|
||
|
if (typeof v === "function") {
|
||
|
if (DEBUG) console.log("builtin", fn)
|
||
|
v()
|
||
|
} else {
|
||
|
if (DEBUG) console.log("normal", fn)
|
||
|
execute(v)
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
execute(env.main)
|