Skip to content

Instantly share code, notes, and snippets.

@PanJarda
Last active November 11, 2017 23:52
Show Gist options
  • Save PanJarda/18d0adeb525c989d86a18ad40e58d499 to your computer and use it in GitHub Desktop.
Save PanJarda/18d0adeb525c989d86a18ad40e58d499 to your computer and use it in GitHub Desktop.
Toy - concatenative, functional, stack-based, truly postfix language.
const readline = require('readline');
const rl = readline.createInterface({
input: process.stdin,
output: process.stdout
});
let stack = [];
let consts = {
swapd: '[[swap] dip]',
popd: '[[pop] dip]',
dupd: '[[dup] dip]'
};
const eval = (word) => {
switch (word) {
case "dup":
stack.push(stack[stack.length-1]);
break;
case "swap":
var tmp = stack.pop();
var tmp2 = stack.pop();
stack.push(tmp);
stack.push(tmp2);
break;
case "dip":
let prog = stack.pop();
tmp = stack.pop();
stack.push(prog);
eval(".");
stack.push(tmp);
break;
case "p":
case "print":
console.log(stack[stack.length-1]);
break;
case "pop":
stack.pop();
break;
case "+":
stack.push(parseFloat(stack.pop()) + parseFloat(stack.pop()));
break;
case "-":
stack.push(parseFloat(stack.pop()) - parseFloat(stack.pop()));
break;
case "*":
stack.push(parseFloat(stack.pop()) * parseFloat(stack.pop()));
break;
case "sqrt":
stack.push(Math.sqrt(parseFloat(stack.pop())));
break;
case "/":
stack.push(parseFloat(stack.pop()) / parseFloat(stack.pop()));
break;
case ">":
stack.push(parseFloat(stack.pop()) > parseFloat(stack.pop()));
break;
case ">=":
stack.push(parseFloat(stack.pop()) > parseFloat(stack.pop()));
break;
case "<":
stack.push(parseFloat(stack.pop()) < parseFloat(stack.pop()));
break;
case "<=":
stack.push(parseFloat(stack.pop()) < parseFloat(stack.pop()));
break;
case "!=":
stack.push(parseFloat(stack.pop()) != parseFloat(stack.pop()));
break;
case "==":
stack.push(parseFloat(stack.pop()) == parseFloat(stack.pop()));
break;
case "?":
var predicate = stack.pop();
(predicate != '0' && predicate != 'false') ? eval(".") : stack.pop() && eval(".");
break;
case "q":
case "quit":
process.exit();
break;
case "c":
case "clear":
stack = [];
break;
case ".":
let item = stack.pop();
let lambda = item.match(/^\[(.*)\]$/);
if (lambda) {
lambda[1].split(/\s+(?=(?:[^\'"\[\]]*[\'"\[][^\'"\[\]]*[\'"\]])*[^\'"\[\]]*$)/).forEach(word=>eval(word))
} else {
stack.push(item);
}
break;
case ":":
consts[stack.pop()] = stack.pop();
break;
case "f":
case "dump":
stack.forEach(a => console.log(a));
break;
case "head":
stack.push(stack.pop().match(/^\[([^\[\]]*)\]$/)[1].split(/\s+(?=(?:[^\'"\[\]]*[\'"\[][^\'"\[\]]*[\'"\]])*[^\'"\[\]]*$)/)[0]);
break;
case "tail":
let content = stack.pop().match(/^\[([^\[\]]*)\]$/)[1].split(/\s+(?=(?:[^\'"\[\]]*[\'"\[][^\'"\[\]]*[\'"\]])*[^\'"\[\]]*$)/);
content.shift();
stack.push("[" + content.join(" ") + "]");
break;
case "cons":
stack.push("[" + stack.pop() + " " + stack.pop() + "]");
break;
case "map":
let array = stack.pop().match(/^\[([^\[\]]*)\]$/)[1].split(/\s+(?=(?:[^\'"\[\]]*[\'"\[][^\'"\[\]]*[\'"\]])*[^\'"\[\]]*$)/);
let fn = stack.pop();
stack.push("[" + array.map(item => {
stack.push(item);
stack.push(fn);
eval(".");
return stack.pop();}).join(" ") +"]");
break;
case "concat": // sezere dve makra a spoji je do jednoho
stack.push("[" + stack.pop().match(/\[(.*)\]/)[1] + " " + stack.pop().match(/\[(.*)\]/)[1] + "]");
break;
case "quote":
stack.push("[" + stack.pop() + "]");
break;
default:
var isquoted;
if (isquoted = word.toString().match(/^\[(.*)\]/)) {
stack.push(word);
} else {
if (consts[word]) {
eval(consts[word]); eval(".");
} else {
stack.push(word);
}
}
}
};
rl.on('line', (input) => {
let wordlist = input.split(/\s+(?=(?:[^\'"\[\]]*[\'"\[][^\'"\[\]]*[\'"\]])*[^\'"\[\]]*$)/);
wordlist.forEach(word => eval(word));
});
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment