Skip to content

Instantly share code, notes, and snippets.

@dzaima
Created August 26, 2017 10:10
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 dzaima/f86a51e631b7e3c36b36b0993b1e2c91 to your computer and use it in GitHub Desktop.
Save dzaima/f86a51e631b7e3c36b36b0993b1e2c91 to your computer and use it in GitHub Desktop.
const STRING = 0,
FUNCTION = 1;
function tokenize (prog) {
var tokens = [];
while (prog != "") {
let token;
prog = prog.replace(/^("(\\.|[^"])*"|[^"][^ ]*)( |$)/, (all, f)=>(token = f,""));
let type = FUNCTION;
if (token[0] == "\"") {
type = STRING;
token = eval(token);
}
tokens.push({val: token, type: type});
}
return tokens;
}
function run (program, inputs) {
BigNumber.config({ DECIMAL_PLACES: 100, ROUNDING_MODE: 4 })//TODO up DECIMAL_PLACES
var tokens = tokenize(program);
var inputPtr = 0;
var stack = [];
var cptr;
var ptrStack = [new (function() {
this.ptr = 0;
this.start = 0;
this.end = tokens.length;
this.next = () => {
if (this.ptr < this.end-1) this.ptr++;
else return this.cont();
return true;
}
this.cont = () => false;
this.counter = 0;
this.continuer = () => false;
})()];//{ptr:0, continue: () => false, next: (ptr) => ptr+1, start: 0, end: () => program.length}
var endables = ["iterate","repeat","if"];
const functions = {
"+": (a,b) => ((a instanceof BigNumber && b instanceof BigNumber)? push(a.plus(b)) : push(a+b)),
"iterate": (a) => ptrStack.push(new (function(iteratable, cptr) {
this.ptr = cptr;
this.start = cptr;
this.end = findEnd(cptr);
this.iteratable = iteratable instanceof BigNumber? functions["1rangeIncl"](iteratable) : iteratable;
this.counter = 0;
this.next = () => {
if (this.ptr < this.end-1) this.ptr++;
else return this.cont();
return true;
}
this.cont = () => {
if (this.counter < this.iteratable.length) {
push(this.iteratable[this.counter]);
this.counter++;
this.ptr = this.start;
return true;
} else return false;
}
//console.log(this.iteratable,this.counter);
this.cont(); //push the initial item
})(a, cptr+1)),
"repeat": (a) => ptrStack.push(new (function(count, cptr) {
this.ptr = cptr;
this.start = cptr;
this.end = findEnd(cptr);
this.count = count;
this.counter = 0;
this.next = () => {
if (this.ptr < this.end-1) this.ptr++;
else return this.cont();
return true;
}
this.cont = () => {
if (this.count.comparedTo(this.counter) > 0) {
this.counter++;
this.ptr = this.start;
return true;
} else return false;
}
//console.log(this.iteratable,this.counter);
this.cont(); //push the initial item
})(a, cptr+1)),
"1rangeIncl": (a) => {
if (a instanceof BigNumber) {
let range = [];
for (let i = new BigNumber(1); i.comparedTo(a)<=0; i=i.plus(1)) range.push(i);
return range;
} else {
throw new Error("range on non-numbers not implemented!"); //TODO
}
},
"output": (a) => document.write(
a.toString()
.replace(/&/g, "&amp;")
.replace(/</g, "&lt;")
.replace(/>/g, "&gt;")
+ "<br>"),
"end": () => {throw new Error("end called (normally it would be skipped over by its creators)");},
"duplicate": (a) => {push(a); push(a);},
"pop": (a) => {},
"if": (a) => {
let truthy = true;
if (a instanceof BigNumber && a.comparedTo(0) == 0
|| a.length === 0) truthy = false;
ptrStack.push(new (function(truthy, cptr) {
this.ptr = cptr;
this.start = cptr;
this.end = findEnd(cptr);
this.truthy = truthy;
this.next = () => {
if (!truthy) return false;
if (this.ptr < this.end-1) this.ptr++;
else return this.cont();
return true;
}
this.cont = () => {
return false;
}
})(truthy, cptr+1));
}
}
//actual program running
while (ptrStack.length > 0) {
let ptrObj = ptrStack[ptrStack.length-1];
cptr = ptrObj.ptr;
console.log(cptr);
//function calling
if (tokens[cptr].type==FUNCTION) {
if (functions[tokens[cptr].val]) {
let args = [];
let currentFunction = functions[tokens[cptr].val];
for (let i = 0; i < currentFunction.length; i++) {
args[i] = pop();
}
currentFunction(...args);
} else {
//numbers
push(new BigNumber(tokens[cptr].val));
}
} else push(tokens[cptr].val);
//logging
let token = tokens[cptr].val.substring(0,6);
while (token.length < 6) token+= " ";
console.log(token+"@"+cptr+": "+ arrtostring(stack))// + " ", JSON.stringify(ptrStack)
if (ptrObj.next() == false) {
let lastobj = ptrStack.pop();
if (ptrStack.length > 0) {
let olderobj = ptrStack[ptrStack.length-1];
olderobj.ptr = lastobj.end;
olderobj.next();
}
}
}
//useful functions
function pop() {
if (stack.length > 0) {
return stack.pop();
} else {
let inp = inputs[inputPtr];
if (typeof inp === "number") inp = new BigNumber(inp);
inputPtr = (inputPtr+1) % inputs.length;
return inp;
}
}
function push (obj) {
if (typeof obj === "number") stack.push(new BigNumber(obj));
else stack.push(obj);
}
function findEnd(sptr) {
let indentation = 1;
let ptr = sptr+1;
while (indentation > 0 && ptr <= tokens.length) {
if (tokens[ptr].type == FUNCTION) {
if (endables.includes(tokens[ptr].val)) indentation++;
else if (tokens[ptr].val == "end") indentation--;
}
ptr++;
}
return ptr-1;
}
}
function arrtostring (arr) {
arr = arr.map((c) => {
if (c instanceof BigNumber) return c.toString();
else if (Array.isArray(c)) return arrtostring(c);
else if (typeof c === "string") return JSON.stringify(c);
else throw new Error("bad item", c);
});
return "[" + arr.join(",") + "]";
}
//run('2 + iterate 3 + output end "done" output', [7])
// 0 1 2 3 4 5 6 7 8
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment