Skip to content

Instantly share code, notes, and snippets.

@grassator
Last active June 24, 2020 19:18
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save grassator/720b31bdbd7de22fb91a13dd81e13c2d to your computer and use it in GitHub Desktop.
Save grassator/720b31bdbd7de22fb91a13dd81e13c2d to your computer and use it in GitHub Desktop.
Forth-like DSL for JavaScript
// Copyright 2020 Dmitriy Kubyshkin
// MIT license
const forj = () => {
const stack = [];
const controlStack = [1];
const last = (stack) => stack.length && stack[stack.length - 1];
function interpreter(arg) {
if (last(controlStack) == 1) {
stack.push(arg);
//console.log("S:", stack);
}
return interpreter;
};
function define(name, getter) {
Object.defineProperty(interpreter, name, {
get() {
if (last(controlStack) == 1) {
//console.log("S:", stack);
getter.call(this);
}
return this;
}
});
}
function directive(name, getter) {
Object.defineProperty(interpreter, name, {
get() {
getter.call(this);
return this;
}
});
}
define("print", () => console.log(stack.pop()));
define("plus", () => stack.push(stack.pop() + stack.pop()));
define("mul", () => stack.push(stack.pop() * stack.pop()));
define("lt", () => stack.push(stack.pop() > stack.pop()));
define("eq", () => stack.push(stack.pop() === stack.pop()));
define("dup", () => stack.push(last(stack)));
define("drop", () => stack.pop());
interpreter.def = function(name, body) {
define(name, () => {
body(interpreter);
});
return this;
};
const loopStack = [];
interpreter.LOOP = function(body) {
loopStack.push(body);
while (last(loopStack) === body) {
body(interpreter);
}
return this;
};
define("CBREAK", () => {
if (stack.pop()) loopStack.pop();
});
directive("IF", () => {
//console.log("C:", controlStack);
//console.log("S:", stack);
if (last(controlStack)) {
controlStack.push(Number(stack.pop()));
} else {
controlStack.push(-1);
}
});
directive("ELSE", () => {
if(last(controlStack) == -1) return;
controlStack.push(Number(!controlStack.pop()));
});
directive("THEN", () => {
controlStack.pop();
});
return interpreter;
};
forj()
(1) .LOOP(_ => _
.dup.print
(1).plus
.dup
(11).eq
.CBREAK
)
forj()("").print;
forj()
.def("square", _ => _
.dup
.mul
)
(9).square.print
forj()("").print;
forj()
(2)(3)(4).plus.mul.print
;
forj()("").print;
forj()
(2)(10).lt .IF
(5)(10).lt .IF
("Yes").print
.THEN
.ELSE
(5)(10).lt .IF
("No").print
.THEN
.THEN
;
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment