Created
August 26, 2017 10:10
-
-
Save dzaima/f86a51e631b7e3c36b36b0993b1e2c91 to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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, "&") | |
.replace(/</g, "<") | |
.replace(/>/g, ">") | |
+ "<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