Created
November 13, 2018 04:25
-
-
Save zerobias/639c5aa6e7461ec4f6a7405098e2ed4e to your computer and use it in GitHub Desktop.
Don't try this at home
This file contains hidden or 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
//@flow | |
import {Stack} from "./Stack"; | |
import {ExecutionContext} from "./ExecutionContext"; | |
import {Api} from "./Api"; | |
import * as ASM from "./ASM"; | |
import {walk} from "./walk"; | |
const log = console.log.bind(console); | |
const zone = (name, fn) => api => | |
api | |
.watch(data => log("[begin zone]", name, data)) | |
.scope(name, fn) | |
.watch(data => log("[end zone]", name, data)); | |
const createEvent = name => payload => api => | |
api.add("runtime", payload).emit(name); | |
const setState = (name, payload) => api => | |
api.add(name, payload).emit(name); | |
const alpha = createEvent("alpha"); | |
const routine = thunk => { | |
const subroutine = thunk(); | |
return api => | |
api.thruRuntime((ctx, api) => { | |
ctx.callStack.push(ctx.currentCallStack); | |
ctx.currentCallStack = subroutine.cmd.reverse(); | |
}); | |
}; | |
const thread1 = new Api() | |
.add("baz_tag", {baz: 100}) | |
.watch((data, ctx, name) => { | |
log(`[sub ${name}]`, data(), ctx); | |
}) | |
.tag("baz_tag", (val, ctx, stack, tag) => | |
log(`[${tag}]`, val, ctx) | |
); | |
const subroutine = new Api() | |
.add("baz_tag", {baz: 100}) | |
.watch((data, ctx, name) => log(`[subroutine ${name}]`, data, ctx)) | |
.tag("baz_tag", (val, ctx, stack, tag) => | |
log(`[${tag}]`, val, ctx) | |
); | |
const betaScope = (api, name) => | |
api | |
// .stop(name) | |
.watch((data, ctx) => log(`[${name} scope]`, data, ctx)) | |
.add("foo_key", {thru: "foo key"}) | |
// .thruRuntime(ctx => ctx.currentCallStack.show()) | |
.thruRuntime((ctx, api) => { | |
ctx.callStack.push(ctx.currentCallStack); | |
ctx.currentCallStack = subroutine.cmd.reverse(); | |
}) | |
.thruRuntime(ctx => ctx.currentCallStack.show()) | |
.dynamic("foo_key") | |
.watch((data, ctx) => log(`[${name} scope]`, data, ctx)) | |
.tag("bar_tag", (val, ctx, stack, tag) => | |
log(`[${tag}]`, val, ctx) | |
); | |
const api = new Api() | |
//.stop() | |
.watch((data, ctx) => log("[begin]", data, ctx)) | |
.mov("runtime", "L1") | |
.emit("alpha") | |
.thru(alpha("gamma+")) | |
.tag("bar_tag", () => { | |
//unreachable as bar_tag wasn't defined | |
throw "forbidden"; | |
}) | |
.add("bar_tag", {bar: 10}) | |
.add("runtime", {baz: "from runtime"}) | |
.thru(setState("state alpha", "bar value")) | |
.mov("L1", "state alpha") | |
.add("thread 1", thread1) | |
.add("L1", () => Math.random() > 0.5) | |
.add("left", 10) | |
.copy("right", "left") | |
.eq("left", "right", "lreq") | |
.tag("lreq", res => log("lreq", res)) | |
.mapTag("left", n => n + 1) | |
.eq("left", "right", "lreq") | |
.tag("lreq", res => log("lreq", res)) | |
// .scope("run", api => api.thread("thread 1")) | |
.thread("thread 1") | |
.scope("beta", betaScope) | |
.map(str => str.length) | |
.map(str => "str length: " + str) | |
// .scope("foo_scope", api => | |
// api | |
// .watch(data => log("begin foo_scope", data)) | |
// .map(str => "str length: " + str) | |
// ) | |
// .unscope("alpha") | |
.watch((data, ctx) => log("[end]", data, ctx)); | |
const walker = () => { | |
const api = new Api().copy("val", "runtime").dynamic("val"); | |
//for (let i = 0; i < 10000; i++) { | |
// api.mapTag("val", n => n + 1); | |
// .add("isNum", new Api()) | |
//walk(api, new Stack().push("aleph")); | |
//} | |
api.watch((val, ctx) => { | |
ctx.val += 1; | |
//ctx; | |
// console.log(val); | |
}); | |
// console.log(api.cmd.array()); | |
const runtime = new Stack().push({val: 1}); | |
for (let i = 0; i < 100000; i++) { | |
walk(api, runtime); | |
} | |
}; | |
// const timeStart = process.hrtime(); | |
// walker() /*?.*/; | |
walk(api, new Stack().push("aleph")); | |
// const diff = process.hrtime(timeStart); | |
// console.log(`Benchmark took ${diff[0] * 1e9 + diff[1]} nanoseconds`); |
This file contains hidden or 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
//@flow | |
import {Stack} from "./Stack"; | |
import {ExecutionContext} from "./ExecutionContext"; | |
import * as ASM from "./ASM"; | |
function push(cmd: $Values<typeof ASM>, args, api: Api): Api { | |
api.cmd.push([++api.index, cmd, args]); | |
return api; | |
} | |
export class Api { | |
cmd = new Stack(); | |
parent: Stack; | |
index = 0; | |
emit(name: string) { | |
return push(ASM.EMIT, name, this); | |
} | |
map(fn: Function) { | |
return push(ASM.MAP, fn, this); | |
} | |
watch(fn: Function) { | |
return push(ASM.WATCH, fn, this); | |
} | |
scope(name: string, fn: (_: Api, name: string) => Api) { | |
let api = new Api(); | |
api.parent = this.cmd; | |
api = fn(api, name); | |
return push(ASM.SCOPE, [name, api], this); | |
} | |
dynamic(from: string) { | |
return push(ASM.DYNAMIC, [from], this); | |
} | |
when(pred, then) { | |
return push(ASM.WHEN, [pred, then], this); | |
} | |
mapTag(tag: string, fn: Function) { | |
push(ASM.MOV, ["L1", tag], this); | |
push(ASM.MAP, fn, this); | |
return push(ASM.MOV, [tag, "L1"], this); | |
} | |
mov(to: string, from: string) { | |
return push(ASM.MOV, [to, from], this); | |
} | |
copy(to: string, from: string) { | |
return push(ASM.COPY, [to, from], this); | |
} | |
add(to: string, value: mixed) { | |
return push( | |
ASM.ADD, | |
[to, value, {toRuntime: to === "runtime", toL1: to === "L1"}], | |
this | |
); | |
} | |
tag( | |
tag: string, | |
fn: ( | |
lastValue: mixed, | |
ctx: mixed, | |
tagStack: Stack, | |
tag: string | |
) => mixed | |
) { | |
return push(ASM.TAG, [tag, fn], this); | |
} | |
eq( | |
tagA: string, | |
tagB: string, | |
result: string, | |
comp: (a: any, b: any) => boolean = (a, b) => a === b | |
) { | |
return push(ASM.EQUAL, [tagA, tagB, result, comp], this); | |
} | |
thread(name: string) { | |
return push(ASM.THREAD, [name], this); | |
} | |
thru<T>(fn: (api: Api) => T): T { | |
return fn(this); | |
} | |
thruRuntime(fn: (context: ExecutionContext, api: Api) => mixed) { | |
return push(ASM.RUNTIME, fn, this); | |
} | |
stop(name: string = "root") { | |
return push(ASM.STOP, name, this); | |
} | |
use(fn: (o: *) => void) { | |
const o = {}; | |
o.watch = this.watch.bind(this); | |
o.tag = this.tag.bind(this); | |
o.mov = this.mov.bind(this); | |
o.emit = this.emit.bind(this); | |
o.map = this.map.bind(this); | |
o.add = this.add.bind(this); | |
o.stop = this.stop.bind(this); | |
o.dynamic = this.dynamic.bind(this); | |
o.thruRuntime = this.thruRuntime.bind(this); | |
o.thru = this.thru.bind(this); | |
o.scope = (name, fn) => | |
this.scope(name, (api, name) => api.use(fn)); | |
o.watch = this.watch.bind(this); | |
fn(o); | |
return this; | |
} | |
result() { | |
const clone = this.cmd.clone(); | |
return clone.values(); | |
} | |
} |
This file contains hidden or 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
//@flow | |
export const EMIT: "emit" = "emit"; | |
export const MAP: "map" = "map"; | |
export const WATCH: "watch" = "watch"; | |
export const SCOPE: "scope" = "scope"; | |
export const STOP: "stop" = "stop"; | |
export const MOV: "mov" = "mov"; | |
export const COPY: "copy" = "copy"; | |
export const THREAD: "thread" = "thread"; | |
export const EQUAL: "equal" = "equal"; | |
export const WHEN: "when" = "when"; | |
export const TAG: "tag" = "tag"; | |
export const ADD: "add" = "add"; | |
export const RUNTIME: "runtime" = "runtime"; | |
export const DYNAMIC: "dynamic" = "dynamic"; |
This file contains hidden or 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
//@flow | |
export class Node<T> { | |
next: null | Node<T> = null; | |
prev: null | Node<T> = null; | |
data: T; | |
constructor(data: T) { | |
this.data = data; | |
} | |
} | |
/** | |
* A linked list implementation in JavaScript. | |
*/ | |
export class DoubleLinkedList<T> { | |
/** | |
* Pointer to first item in the list. | |
* @property head | |
* @type Object | |
* @private | |
*/ | |
head: Node<T> | null = null; | |
/** | |
* Pointer to last item in the list. | |
* @property tail | |
* @type Object | |
* @private | |
*/ | |
tail: Node<T> | null = null; | |
length: number = 0; | |
/** | |
* Appends some data to the end of the list. This method traverses | |
* the existing list and places the value at the end in a new item. | |
* @param {variant} data The data to add to the list. | |
* @return {Void} | |
* @method add | |
*/ | |
add(data: T) { | |
//create a new item object, place data in | |
const node = new Node(data); | |
//special case: no items in the list yet | |
if (this.length == 0) { | |
this.head = node; | |
this.tail = node; | |
} else { | |
const {tail} = this; | |
if (tail) { | |
//attach to the tail node | |
tail.next = node; | |
node.prev = tail; | |
this.tail = node; | |
} | |
} | |
//don't forget to update the count | |
this.length++; | |
} | |
/** | |
* Retrieves the data in the given position in the list. | |
* @param {int} index The zero-based index of the item whose value | |
* should be returned. | |
* @return {variant} The value in the "data" portion of the given item | |
* or null if the item doesn't exist. | |
* @method item | |
*/ | |
item(index: number): T | null { | |
//check for out-of-bounds values | |
if (index > -1 && index < this.length) { | |
let current = this.head; | |
let i = 0; | |
while (i++ < index) { | |
if (current !== null) current = current.next; | |
} | |
return current ? current.data : null; | |
} else { | |
return null; | |
} | |
} | |
/** | |
* Removes the item from the given location in the list. | |
* @param {int} index The zero-based index of the item to remove. | |
* @return {variant} The data in the given position in the list or null if | |
* the item doesn't exist. | |
* @method remove | |
*/ | |
remove(index: number): T | null { | |
//check for out-of-bounds values | |
if (index > -1 && index < this.length) { | |
let current = this.head; | |
let i = 0; | |
//special case: removing first item | |
if (index === 0) { | |
if (current) { | |
this.head = current.next; | |
} | |
/* | |
* If there's only one item in the list and you remove it, | |
* then this.head will be null. In that case, you should | |
* also set this.tail to be null to effectively destroy | |
* the list. Otherwise, set the previous pointer on the new | |
* this.head to be null. | |
*/ | |
if (!this.head) { | |
this.tail = null; | |
} else { | |
this.head.prev = null; | |
} | |
//special case: removing last item | |
} else if (index === this.length - 1) { | |
current = this.tail; | |
if (current) { | |
const tail = (this.tail = current.prev); | |
if (tail) tail.next = null; | |
} | |
} else { | |
//find the right location | |
while (i++ < index) { | |
if (current) current = current.next; | |
} | |
//skip over the item to remove | |
if (current) { | |
if (current.prev !== null) { | |
current.prev.next = current.next; | |
if (current.next !== null) { | |
current.next.prev = current.prev; | |
} | |
} | |
} | |
} | |
//decrement the length | |
this.length--; | |
//return the value | |
return current ? current.data : null; | |
} else { | |
return null; | |
} | |
} | |
/** | |
* Returns the number of items in the list. | |
* @return {int} The number of items in the list. | |
* @method size | |
*/ | |
size() { | |
return this.length; | |
} | |
/** | |
* Converts the list into an array. | |
* @return {Array} An array containing all of the data in the list. | |
* @method toArray | |
*/ | |
toArray(reverse: boolean = false) { | |
const result = []; | |
let current = reverse ? this.tail : this.head; | |
while (current) { | |
result.push(current.data); | |
current = reverse ? current.prev : current.next; | |
} | |
return result; | |
} | |
*iterator(): Iterator<T> { | |
let current = this.head; | |
while (current) { | |
yield current.data; | |
current = current.next; | |
} | |
} | |
/** | |
* Converts the list into a string representation. | |
* @return {String} A string representation of the list. | |
* @method toString | |
*/ | |
toString() { | |
return this.toArray().toString(); | |
} | |
} |
This file contains hidden or 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
//@flow | |
import {Stack} from "./Stack"; | |
import {Register} from "./plexor"; | |
class Interruption {} | |
class Interruptor {} | |
let id = 0; | |
export class Device {} | |
export class ExecutionContext { | |
id = ++id; | |
L1 = new Stack(); | |
register = new Register(); | |
nameStack = new Stack().push("root"); | |
runtime: Stack; | |
callStack = new Stack(); | |
currentCallStack: Stack; | |
dataStack = new Stack().push({name: "root"}); | |
taggedMap: Map<string, Stack> = new Map(); | |
clear() { | |
this.taggedMap.clear(); | |
} | |
} |
This file contains hidden or 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
//@flow | |
import {Stack} from "./Stack"; | |
export const __innerStack = (s: Stack, serialize: Function) => { | |
const getSpace = () => | |
Array.from(new Array(__printLevel * 2), () => " ").join(""); | |
const result = [getSpace(), s.name ? s.name : "stack"]; | |
__printLevel += 1; | |
s.forEach((v, n) => { | |
result.push(`\n`, getSpace(), ...serialize(v)); | |
}); | |
__printLevel -= 1; | |
return result; | |
}; | |
let __printLevel = 0; | |
export const printStack = ( | |
s: Stack, | |
serialize = x => (x instanceof Stack ? printStack(x) : [x]) | |
) => { | |
const getSpace = () => | |
Array.from(new Array(__printLevel * 2), () => " ").join(""); | |
const result = [`\n`, getSpace(), s.name ? s.name : "stack"]; | |
__printLevel += 1; | |
s.forEach((v, n) => { | |
result.push(`\n`, getSpace(), ...serialize(v)); | |
}); | |
__printLevel -= 1; | |
return result; | |
}; | |
export const log = console.log.bind(console); | |
const byLine = (arr, spaces, space) => { | |
if (arr.length < 2) return arr; | |
return arr.reduce((acc, v) => spaces(acc, v, space), []); | |
}; | |
const printScope = (acc, space, [id, , [tag, {cmd}]]) => { | |
let accum; | |
if (acc.length === 0 || acc[0] === "[]") accum = [space.slice(1)]; | |
else accum = [...acc, space]; | |
return [ | |
...accum, | |
...[ | |
[id, tag], | |
...cmd | |
.array() | |
.reduceRight( | |
(acc, v) => [...acc, space + " ", [v[0], v[1]]], | |
[] | |
), | |
], | |
]; | |
}; | |
export const logNode = ( | |
[past, now, next], | |
map = x => x, | |
spaces = (acc, x, space) => { | |
const add = []; | |
if (acc.length !== 0) add.push(space); | |
if (x[1] === "scope") return printScope(acc, space, x); | |
return [...acc, ...add, [x[0], x[1]]]; | |
// acc.length === 0 ? [x] : ["\n ", x]) | |
}, | |
space = "\n " | |
) => { | |
let pastRes = ["[]"]; | |
let nextRes = ["[]"]; | |
if (past.length > 0) pastRes = past; | |
if (next.length > 0) nextRes = next; | |
let lres = byLine(pastRes, spaces, space); | |
if (lres[0] === "[]") lres = []; | |
let rres = byLine(nextRes, spaces, space); | |
if (rres[0] === "[]") rres = []; | |
let mapNow = map(now || []); | |
if (mapNow[1] === "scope") | |
mapNow = [[mapNow[0]], "scope " + now[2][0] + " [...]"]; | |
else mapNow = [mapNow]; | |
log(" ", ...lres); | |
log("now ", ...mapNow); | |
log(" ", ...rres, `\n`); | |
}; |
This file contains hidden or 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
//@flow | |
import {__innerStack} from "./printStack"; | |
export type Stacked = [mixed, [] | Stacked]; | |
export class Stack { | |
_: Stacked = ["unit", []]; | |
size = 0; | |
/*:: | |
name: string; | |
*/ | |
push(value: any): Stack { | |
this._ = [value, this._]; | |
this.size += 1; | |
return this; | |
} | |
pop() { | |
if (this.size === 0) return "unit"; | |
const [value, stack] = this._; | |
this._.length = 0; | |
this._ = stack; | |
this.size -= 1; | |
return value; | |
} | |
clone(): Stack { | |
const result = new Stack(); | |
result.size = this.size; | |
let next = []; | |
let target: Stacked = [this._[0], next]; | |
let reference = this._[1]; | |
result._ = target; | |
while (reference.length) { | |
next[0] = reference[0]; | |
target = next; | |
target[1] = next = []; | |
reference = reference[1]; | |
} | |
// if (this.name) result.name = this.name; | |
return result; | |
} | |
reverse() { | |
const result = new Stack(); | |
for (const value of this.values()) { | |
result.push(value); | |
} | |
// if (this.name) result.name = this.name; | |
return result; | |
} | |
slice(index: number) { | |
if (this.size <= index) return; | |
let stack = this._[1]; | |
let prev = this._; | |
let size = this.size; | |
while (size > index) { | |
prev.length = 0; | |
prev = stack; | |
stack = stack[1]; | |
size -= 1; | |
} | |
this.size = size; | |
this._ = stack; | |
} | |
peek() { | |
return this._[0]; | |
} | |
forEach( | |
fn: (val: mixed, n: number) => mixed, | |
thisArg?: any = null | |
) { | |
for (const [n, v] of this.entries()) fn(v, n); | |
} | |
*entries(): Iterator<[number, mixed]> { | |
if (this.size === 0) return; | |
let [value, stack] = this._; | |
let size = this.size; | |
yield [size, value]; | |
while ((size -= 1)) { | |
value = stack[0]; | |
stack = stack[1]; | |
yield [size, value]; | |
} | |
} | |
array() { | |
if (this.size === 0) return []; | |
const result = []; | |
let [value, stack] = this._; | |
let size = this.size; | |
// yield value; | |
result.push(value); | |
while ((size -= 1)) { | |
value = stack[0]; | |
stack = stack[1]; | |
// yield value; | |
result.push(value); | |
} | |
return result; // [...this.values()]; | |
} | |
show(print?: boolean) { | |
if (print === undefined) print = true; | |
const result = __innerStack( | |
this, | |
x => (x instanceof Stack ? x.show(false) : [x]) | |
); | |
if (print) console.log(...result); | |
else return result; | |
} | |
*values(): Iterator<mixed> { | |
if (this.size === 0) return; | |
let [value, stack] = this._; | |
let size = this.size; | |
yield value; | |
while ((size -= 1)) { | |
value = stack[0]; | |
stack = stack[1]; | |
yield value; | |
} | |
} | |
} | |
export class StackIterator { | |
target: Stack; | |
_: Stacked; | |
source: Stacked; | |
step = 0; | |
done: boolean; | |
next() { | |
if (this.done) return; | |
if (this._.length !== 2) { | |
this.done = true; | |
return; | |
} | |
const [value, _] = this._; | |
if (value === "unit") { | |
this.done = true; | |
return; | |
} | |
if (_.length !== 2) { | |
this.done = true; | |
return; | |
} | |
this._ = _; | |
this.step += 1; | |
return value; | |
} | |
array(map: Function = x => x) { | |
const result = []; | |
let value; | |
while ((value = this.next()) !== undefined) | |
result.push(map(value)); | |
return result; | |
} | |
node() { | |
const rest = this.clone() | |
.array() | |
.slice(1); | |
const past = this.clone() | |
.sync() | |
.array(); | |
let current = past[this.step]; | |
return [past.slice(0, this.step), current, rest]; | |
} | |
reset() { | |
this.step = 0; | |
this._ = this.source; | |
this.done = this.target.size === 0; | |
return this; | |
} | |
sync() { | |
this._ = this.target._; | |
return this; | |
} | |
clone() { | |
const clone = new StackIterator(); | |
clone.target = this.target; | |
clone.step = this.step; | |
clone._ = this._; | |
clone.source = this.source; | |
return clone; | |
} | |
static iterate(target: Stack): StackIterator { | |
const result = new StackIterator(); | |
result.target = target; | |
result.source = result.target._; | |
result.reset(); | |
// result.next(); | |
return result; | |
} | |
static iterateBack(target: Stack): StackIterator { | |
const result = new StackIterator(); | |
result.target = target.reverse(); | |
result.source = result.target._; | |
return result.reset(); | |
} | |
} |
This file contains hidden or 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
//@flow | |
import {Stack, StackIterator} from "./Stack"; | |
import {log, logNode} from "./printStack"; | |
import {ExecutionContext} from "./ExecutionContext"; | |
import {Api} from "./Api"; | |
import * as ASM from "./ASM"; | |
export const walk = (api: Api, runtime: Stack = new Stack()) => { | |
// api.cmd.name = "api.cmd"; | |
const ctx = new ExecutionContext(); | |
ctx.runtime = runtime; | |
const {callStack, L1, dataStack} = ctx; | |
ctx.callStack.push(api.cmd.reverse()); | |
// ctx.dataStack.name = "dataStack"; | |
// ctx.callStack.name = "callStack"; | |
// ctx.nameStack.name = "nameStack"; | |
// ctx.L1.name = "L1"; | |
let item; | |
let dataCurrent; | |
walk: while ( | |
(ctx.currentCallStack = ctx.callStack.pop()) !== "unit" | |
) { | |
// ctx.currentCallStack.name = "currentCallStack"; | |
// const iter = StackIterator.iterate(ctx.currentCallStack.clone()); | |
// logNode(iter.node(), ([id, name]) => [id, name]); | |
dataCurrent = ctx.dataStack.peek(); | |
current: while (ctx.currentCallStack.size) { | |
// ctx.nameStack.show(); | |
// iter.next(); | |
// logNode(iter.node(), ([id, name]) => [id, name]); | |
// log(...printStack(ctx.currentCallStack)); | |
item = ctx.currentCallStack.pop(); | |
const [index, type, value] = item; | |
// log(index, type, value, dataCurrent); | |
step: switch (type) { | |
case ASM.EMIT: { | |
// const data = L1.peek(); | |
break step; | |
} | |
case ASM.RUNTIME: | |
value( | |
ctx, | |
api, | |
ctx.L1.peek(), | |
dataCurrent, | |
ctx.nameStack.peek() | |
); | |
break step; | |
case ASM.MOV: { | |
const [to, from] = value; | |
if (fastcall(to, from, ctx)) break step; | |
const fromValue = fromName(from, ctx); | |
if (!fromValue) break step; | |
let toValue = fromName(to, ctx); | |
if (!toValue) { | |
toValue = new Stack(); | |
ctx.taggedMap.set(to, toValue); | |
} | |
toValue.push(fromValue.pop()); | |
break step; | |
} | |
case ASM.COPY: { | |
const [to, from] = value; | |
if (fastcall(to, from, ctx)) break step; | |
const fromValue = fromName(from, ctx); | |
if (!fromValue) break step; | |
let toValue = fromName(to, ctx); | |
if (!toValue) { | |
toValue = new Stack(); | |
ctx.taggedMap.set(to, toValue); | |
} | |
toValue.push(fromValue.peek()); | |
break step; | |
} | |
case ASM.DYNAMIC: { | |
const [from] = value; | |
const fromValue = fromName(from, ctx); | |
if (!fromValue) break step; | |
ctx.callStack.push(ctx.currentCallStack); | |
ctx.dataStack.push(fromValue.pop()); | |
continue walk; | |
} | |
case ASM.WHEN: { | |
const [pred, then] = value; | |
const threadStack: Stack | void = fromName(then, ctx); | |
const predStack: Stack | void = fromName(pred, ctx); | |
if (threadStack === undefined) break step; | |
if (predStack === undefined) break step; | |
if (!predStack.peek()) break step; | |
const thread: Api | void = threadStack.peek(); | |
if (thread === undefined) break step; | |
const thenVal = then.peek(); | |
ctx.nameStack.push(name); | |
ctx.dataStack.push({name}); | |
ctx.callStack.push(ctx.currentCallStack); | |
ctx.callStack.push(then.cmd.reverse()); | |
break step; | |
} | |
case ASM.EQUAL: { | |
const [aTag, bTag, resultTag, comparator] = value; | |
const forA = fromName(aTag, ctx); | |
if (forA === undefined) break step; | |
const forB = fromName(bTag, ctx); | |
if (forB === undefined) break step; | |
let res = fromName(resultTag, ctx); | |
if (!res) { | |
res = new Stack(); | |
ctx.taggedMap.set(resultTag, res); | |
} | |
const computed = comparator(forA.peek(), forB.peek()); | |
res.push(computed); | |
ctx.dataStack.push(computed); | |
break step; | |
} | |
case ASM.ADD: { | |
const [to, val, {toRuntime, toL1}] = value; | |
if (toRuntime) { | |
runtime.push(val); | |
} else if (toL1) { | |
ctx.L1.push(val); | |
} else { | |
let tagged = ctx.taggedMap.get(to); | |
if (!tagged) { | |
tagged = new Stack(); | |
ctx.taggedMap.set(to, tagged); | |
} | |
tagged.push(val); | |
} | |
break step; | |
} | |
case ASM.TAG: { | |
const [tag, fn] = value; | |
const tagged = ctx.taggedMap.get(tag); | |
if (tagged) { | |
const current = tagged.peek(); | |
fn(current, dataCurrent, tagged, tag); | |
} | |
break step; | |
} | |
case ASM.MAP: | |
ctx.L1.push(value(ctx.L1.pop(), dataCurrent)); | |
break step; | |
case ASM.WATCH: | |
value(ctx.L1.peek(), dataCurrent, ctx.nameStack.peek()); | |
break step; | |
case ASM.THREAD: { | |
const [name] = value; | |
const threadStack: Stack | void = ctx.taggedMap.get(name); | |
if (!threadStack) break step; | |
const thread: Api | void = threadStack.peek(); | |
if (!thread) break step; | |
ctx.nameStack.push(name); | |
ctx.dataStack.push({name}); | |
ctx.callStack.push(ctx.currentCallStack); | |
ctx.callStack.push(thread.cmd.reverse()); | |
continue walk; | |
} | |
case ASM.SCOPE: { | |
const [name, api] = value; | |
ctx.nameStack.push(name); | |
ctx.dataStack.push({name}); | |
ctx.callStack.push(ctx.currentCallStack); | |
ctx.callStack.push(api.cmd.reverse()); | |
continue walk; | |
} | |
// case ASM.STOP: | |
// break current; | |
case ASM.STOP: { | |
if (ctx.currentCallStack.peek() === value) break current; | |
let back = -1; | |
const found = ctx.nameStack | |
.array() | |
.findIndex((x, i) => value === x); | |
if (found === 0) break current; | |
if (found > 0) { | |
for (let i = 0; i < found; i++) { | |
ctx.callStack.pop(); | |
} | |
break current; | |
} | |
log("CAN NOT STOP", value); | |
break step; | |
} | |
} | |
} | |
ctx.dataStack.pop(); | |
ctx.nameStack.pop(); | |
} | |
ctx.clear(); | |
}; | |
const fastcall = (to, from, ctx) => { | |
switch (to) { | |
case "ax": | |
case "bx": | |
case "cx": | |
switch (from) { | |
case "ax": | |
case "bx": | |
case "cx": | |
ctx.register[to] = ctx.register[from]; | |
return true; | |
} | |
} | |
return false; | |
}; | |
const fromName = (name, ctx) => { | |
switch (name) { | |
case "runtime": | |
return ctx.runtime; | |
case "L1": | |
return ctx.L1; | |
default: | |
return ctx.taggedMap.get(name); | |
} | |
}; |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment