Created
July 23, 2011 05:49
-
-
Save Maxdamantus/1101078 to your computer and use it in GitHub Desktop.
jsdis; Dis Virtual Machine implemented in JavaScript .. moved to https://github.com/Maxdamantus/jsdis
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
implement AltTest; | |
include "sys.m"; | |
include "draw.m"; | |
AltTest: module { | |
init: fn(c: ref Draw->Context, a: list of string); | |
}; | |
sys: Sys; | |
init(x: ref Draw->Context, y: list of string){ | |
sys = load Sys Sys->PATH; | |
# spawn rng(d := chan of int); | |
# for(;;) | |
# sys->print("%d\n", <-d); | |
# sys->print("%d\n", <-d); | |
# sys->print("%d\n", <-d); | |
# spawn loop(10000000, a := chan of int); | |
# spawn loop(1000000, b := chan of int); | |
# spawn loop(100000, c := chan of int); | |
# spawn w(a := chan of int); | |
# spawn w(b := chan of int); | |
# spawn w(c := chan of int); | |
a := chan of int; | |
b := chan of int; | |
c := chan of int; | |
d := chan of int; | |
e := chan of int; | |
spawn w(a, e); | |
spawn w(b, e); | |
<-e; <-e; | |
sys->print("about to alt\n"); | |
#for(;;) | |
alt{ | |
<-c => | |
sys->print("got c\n"); | |
<-a => | |
sys->print("got a\n"); | |
<-b => | |
sys->print("got b\n"); | |
} | |
} | |
w(g: chan of int, e: chan of int){ | |
if(e != nil) | |
spawn w(e, nil); | |
g<- = 42; | |
} | |
#se(s: string): int{ | |
# sys->print("%s\n", s); | |
# return 0; | |
#} | |
loop(n: int, c: chan of int){ | |
while(n > 0) | |
c<- = n--; | |
} | |
#rng(c: chan of int){ | |
# c<- = 42; | |
# c<- = 43; | |
# for(;;) | |
# alt{ | |
# c<- = 0 => sys->print("what"); | |
# c<- = 1 => sys->print("what"); | |
# c<- = 2 => sys->print("what"); | |
# c<- = 3 => sys->print("what"); | |
# c<- = 4 => sys->print("what"); | |
# c<- = 5 => sys->print("what"); | |
# c<- = 6 => sys->print("what"); | |
# c<- = 7 => sys->print("what"); | |
# c<- = 8 => sys->print("what"); | |
# c<- = 9 => sys->print("what"); | |
# } | |
#} |
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
var test = snarf("AltTest.dis"); | |
function showstuff(s){ | |
var r = "", i; | |
if(typeof s == "object"){ | |
if(s instanceof Array){ | |
for(i = 0; i < s.length; i++) | |
r += showstuff(s[i]) + ", "; | |
return "[" + r + "]"; | |
} | |
for(i in s) | |
r += i + ": " + showstuff(s[i]) + ", "; | |
return "{" + r + "}"; | |
} | |
return s; | |
} | |
function replicate(n, f){ | |
var r = []; | |
while(n-- > 0) | |
r.push(f()); | |
return r; | |
} | |
var dis = function(){ | |
var builtin; | |
function comp(i, n){ | |
return n == 32? i | 0 : | |
n < 32? i < 1 << n-1? i : i - (1 << n) : | |
i < Math.pow(2, n-1)? i : i - Math.pow(2, n); | |
} | |
function read(s){ | |
var i = 0; | |
function byte(){ | |
return s.charCodeAt(i++); | |
} | |
function chunk(l){ | |
i += l; | |
return s.substr(i - l, l); | |
} | |
function bigend32(){ | |
return byte() << 24 | byte() << 16 | byte() << 8 | byte(); | |
} | |
function utf8(){ | |
var x = i; | |
for(; s.charAt(i) != "\u0000"; i++); | |
return s.substr(x, i++ - x); | |
} | |
// TODO: ieee754 | |
function header(){ | |
var r = {}; | |
r.magic = op(); | |
if(r.magic == 923426) | |
r.signature = chunk(op()); | |
r.runtime_flag = op(); | |
r.stack_extent = op(); | |
r.code_size = op(); | |
r.data_size = op(); | |
r.type_size = op(); | |
r.link_size = op(); | |
r.entry_pc = op(); | |
r.entry_type = op(); | |
return r; | |
} | |
// operand = [] | [immed] | [ind, isfp] | [ind1, ind2, isfp] | |
// [code, mid_operand, left_operand, right_operand] | |
function instruction(){ | |
print("ins at " + i); | |
var opcode = byte(), addrmode = byte(), amm, amsd, r, x; | |
r = [opcode]; | |
amm = addrmode >> 6; | |
amsd = [addrmode >> 3 & 7, addrmode & 7]; | |
r.push( | |
amm == 0? [] : | |
amm == 1? [op()] : | |
[op(), !(amm & 1)]); | |
for(x = 0; x < 2; x++) | |
r.push( | |
amsd[x] == 3 || amsd[x] > 5? [] : | |
amsd[x] == 2? [op()] : | |
amsd[x] >> 1? [op(), op(), amsd[x] & 1] : | |
[op(), !!(amsd[x] & 1)]); | |
return r; | |
} | |
function type(){ | |
var num = op(), size = op(), ptrs = op(); | |
return { desc_number: num, size: size, number_ptrs: ptrs, | |
map: Array.prototype.map.call(chunk(ptrs), function(c){ return c.charCodeAt(0); }) }; | |
} | |
function datum(){ | |
print("data at " + i.toString(16)); | |
var code = byte(), count, offset, s, t; | |
count = code & 15? code & 15 : op(); | |
offset = op(); | |
if(code >> 4 == 7) | |
return { type: 7, data: count }; | |
switch(code >> 4){ | |
case 1: | |
return { type: "bytes", offset: offset, data: replicate(count, byte) }; | |
case 2: | |
return { type: "words", offset: offset, data: replicate(count, bigend32) }; | |
case 3: | |
// should I encode this into JS' UTF-16? | |
return { type: "string", offset: offset, data: chunk(count) }; | |
case 4: | |
return { type: "ieee754", offset: offset, data: replicate(count, ieee754) }; | |
case 5: | |
return { type: "array", offset: offset, data: replicate(count, function(){ | |
return replicate(2, bigend32); | |
}) }; | |
case 6: | |
/* wtf */ | |
return { type: "index" }; | |
case 7: | |
return { type: "pop", offset: offset, count: count }; | |
case 8: | |
return { type: "longs", offset: offset, data: replicate(count, function(){ | |
return replicate(8, byte); | |
}) }; | |
} | |
} | |
function link(){ | |
return { pc: op(), type: op(), sig: bigend32(), name: utf8() }; | |
} | |
function moduleimport(){ | |
function functionimport(){ | |
print("functionimport @ " + i.toString(16)); | |
return { sig: bigend32(), name: utf8() }; | |
} | |
var t = replicate(op(), functionimport); | |
print("moduleimport() = " + showstuff(t)); | |
return t; | |
} | |
function all(){ | |
var code, types, data = [], name, links, imports, head = header(), x; | |
code = replicate(head.code_size, instruction); | |
types = replicate(head.type_size, type); | |
while(byte()){ | |
i--; | |
data.push(datum()); | |
} | |
name = utf8(); | |
links = replicate(head.link_size, link); | |
imports = replicate(op(), moduleimport); | |
print("read all: " + i.toString(16)); | |
return { name: name, header: head, code: code, types: types, data: data, links: links, imports: imports }; | |
} | |
function op(){ | |
var b = byte(); | |
if((b & 128) == 0) | |
return comp(b & 127, 7); | |
if((b & (128 | 64)) == 128) | |
return comp((b & 63) << 8 | byte(), 14); | |
return comp((b & 63) << 24 | byte() << 16 | byte() << 8 | byte(), 30); | |
} | |
return all(); | |
} | |
function quotes(s){ | |
// TODO: .. | |
return s.toSource(); | |
} | |
function makemp(data){ | |
var mp = [], ins, x, y, m; | |
for(x = 0; x < data.length; x++) | |
switch((ins = data[x]).type){ | |
case "bytes": | |
case "words": | |
m = ins.type == "words"? 4 : 1; | |
for(y = 0; y < ins.data.length; y++) | |
mp[ins.offset + y*m] = ins.data[y]; | |
break; | |
case "string": | |
mp[ins.offset] = ins.data; | |
break; | |
case "ieee754": | |
// TODO: .. | |
break; | |
case "array": | |
for(y = 0; y < ins.data.length; y++) | |
mp[ins.offset + y*4] = [0, ins.data[1], []]; | |
break; | |
case "set": | |
// TODO: ?!# | |
break; | |
case "pop": | |
// TODO: ?!# | |
break; | |
case "longs": | |
// TODO: 0xff << 24 < 0 | |
for(y = 0; y < ins.data.length; y++) | |
mp[ins.offset + y*8] = [ | |
ins.data[y][4] << 24 | ins.data[y][5] << 16 | ins.data[y][6] << 8 | ins.data[y][7], | |
ins.data[y][0] << 24 | ins.data[y][1] << 16 | ins.data[y][2] << 8 | ins.data[y][3]]; | |
} | |
print("mp = " + mp.toSource()); | |
return mp; | |
} | |
function insc(s, p, c){ | |
return s.substr(0, p) + String.fromCharCode(c) + s.substr(p + 1); | |
} | |
var procs = []; | |
function start(module){ | |
procs.push(function(){ | |
return module([{ name: "init", sig: 0x4244b354 }])[0]([0,[]]); | |
}); | |
} | |
// keep calling this until it returns 0 | |
function run(){ | |
var r, n; | |
if(procs.length > 0) | |
if(r = procs[n = Math.random()*procs.length | 0]()) | |
procs[n] = r; | |
else | |
rem(procs, n); | |
return procs.length; | |
} | |
function rem(arr, n){ | |
if(n == arr.length - 1) | |
arr.pop(); | |
else | |
arr[n] = arr.pop(); | |
} | |
function runall(){ | |
while(run() > 0); | |
} | |
function spawner(fun){ | |
return procs.push(fun) - 1; | |
} | |
function crem(arr, n, s){ | |
print("crem(" + s + "); arr.length = " + arr.length + "; n = " + n); | |
var x; | |
for(x = 0; x < arr.length; x++) | |
print("crem: arr[" + x + "][2] = " + arr[x][2]); | |
if(n == arr.length - 1) | |
arr.pop(); | |
else{ | |
print("arr[" + n + "] = arr.pop()"); | |
arr[n] = arr.pop(); | |
print("arr[" + n + "][2] = n"); | |
arr[n][2] = n; | |
} | |
} | |
var channelc = 0; | |
function channel(){ | |
var cid = channelc++; | |
var receivers = [], senders = []; | |
function recv(ptr, cont){ | |
var n; | |
if(senders.length){ | |
ptr[1][ptr[0]] = senders[n = Math.random()*senders.length | 0][0]; | |
print("removing senders[" + n + "]"); | |
procs.push(senders[n][1]); | |
if(cont) | |
procs.push(cont); | |
crem(senders, n, "crem receivers, cid = " + cid); | |
}else{ | |
print("receivers.push (cid = " + cid + ") = " + | |
receivers.push(n = [ptr, cont, receivers.length])); | |
return function(){ | |
crem(receivers, n[2], "crem receivers, cid = " + cid); | |
}; | |
} | |
} | |
function send(val, cont){ | |
var n, ptr; | |
if(receivers.length){ | |
ptr = receivers[n = Math.random()*receivers.length | 0][0]; | |
print("removing receivers[" + n + "]"); | |
ptr[1][ptr[0]] = val; | |
procs.push(receivers[n][1]); | |
if(cont) | |
procs.push(cont); | |
crem(receivers, n, "crem receivers, cid = " + cid); | |
}else{ | |
print("senders.push (cid = " + cid + ") = " + | |
senders.push(n = [val, cont, senders.length])); | |
return function(){ | |
crem(senders, n[2], "crem receivers, cid = " + cid); | |
}; | |
} | |
} | |
function recvpoll(){ | |
print("recvpoll() = " + senders.length); | |
return senders.length; | |
} | |
function sendpoll(){ | |
print("sendpoll() = " + receivers.length); | |
return receivers.length; | |
} | |
return [send, recv, sendpoll, recvpoll]; | |
} | |
function alt(ptr, dst, cont){ | |
var ns = ptr[1][ptr[0]], nr = ptr[1][ptr[0] + 4], aborts = [], ready, x, t, c; | |
print("alt; ns = " + ns + "; nr = " + nr); | |
function abortfn(n){ | |
return function(){ | |
print("abort; n = " + n); | |
abortfnd(n); | |
dst[1][dst[0]] = n; | |
procs.push(cont); | |
}; | |
} | |
function abortfnd(n){ | |
print("abortfnd(" + n + "); aborts.length = " + aborts.length); | |
var x; | |
for(x = aborts.length - 1; x >= 0; x--) | |
if(x != n){ | |
print("aborts[" + x + "]()"); | |
aborts[x](); | |
} | |
} | |
// hopefully these are actually channels and pointers | |
for(x = 0; x < ns + nr; x++){ | |
print("alt.for"); | |
t = ptr[1][ptr[0] + 8 + x*8 + 4]; // val pointer | |
c = ptr[1][ptr[0] + 8 + x*8]; | |
if(c[x < ns? 2 : 3]()){ | |
print("alt.for.if1"); | |
if(aborts){ | |
print("alt.for.if1.if"); | |
abortfnd(-1); | |
aborts = undefined; | |
ready = []; | |
} | |
ready.push(x); | |
}else if(aborts){ | |
print("alt.for.if2"); | |
if(x < ns) | |
aborts.push(c[0](t[1][t[0]], abortfn(x))); | |
else | |
aborts.push(c[1](t, abortfn(x))); | |
} | |
} | |
if(ready){ | |
print("** ready"); | |
x = Math.floor(Math.random() * ready.length); | |
t = ptr[1][ptr[0] + 8 + x*8 + 4]; | |
c = ptr[1][ptr[0] + 8 + x*8]; | |
if(x < ns) | |
c[0](t[1][t[0]], cont); | |
else | |
c[1](t, cont); | |
dst[1][dst[0]] = x; | |
} | |
} | |
// loader :: (string, [importing]) -> [exporting] | |
function loader(name, imports){ | |
if(name[0] == "$") | |
return builtin[name.substr(1)](imports); | |
// wonder what will go here | |
} | |
function exporter(importing, exporting, main){ | |
var r = [], x, y; | |
for(x = 0; x < importing.length; x++) | |
for(y = 0; y < exporting.length; y++){ | |
if(importing[x].name == exporting[y].name && importing[x].sig == exporting[y].sig){ | |
print("exporter matched " + importing[x].name); | |
r[x] = function(pc){ | |
return function(fp, ret){ | |
return main([false, [0, []], pc], ret); | |
}; | |
}(exporting[y].pc); | |
break; | |
} | |
throw "module has no export (" + importing[x].name + ", " + importing[x].sig.toString(16) + ")"; | |
} | |
return r; | |
} | |
function getargs(fp){ | |
var x = 32; | |
function get(sz){ | |
return function(){ | |
for(; x % sz; x++); | |
x += sz; | |
return fp[1][fp[0] + x - sz]; | |
}; | |
} | |
return { | |
word: get(4), | |
byte: get(1), | |
dword: get(8), | |
}; | |
} | |
function pointer(base, offs){ | |
return { | |
base: base, offs: offs, | |
toString: function(){ | |
return base + "[1][" + base + "[0] + " + offs + "]"; | |
}, | |
addrof: function(){ | |
return "[" + offs + " + " + base + "[0], " + base + "[1]]" | |
} | |
}; | |
} | |
// module interface: | |
// module = ([importing]) -> [exporting] | |
// importing = { name: string, sig: int } | |
// exporting = (frame /* fp for the call */, return /* returned after fibre's last ret */) -> exporting | |
// return = () -> exporting | |
// the exporting function returns a continuation | |
// inter-module calls use exporting functions | |
function compile(source){ | |
function operand(ins, i, addrof){ | |
var n = ins[i + 1], j; | |
switch(n.length){ | |
case 0: | |
if(i == 0) | |
return operand(ins, 2); | |
throw "expected operand"; | |
case 1: | |
if(addrof) | |
throw "address of immediate"; | |
return "" + n[0]; | |
case 2: | |
j = pointer(n[1]? "fp" : "mp", n[0]); | |
return addrof? j.addrof() : j.toString(); | |
i = n[1]? "fp" : "mp"; | |
return addrof? "[" + n[0] + " + " + i + "[0], " + i + "[1]]" : i + "[1][" + i + "[0] + " + n[0] + "]"; | |
case 3: | |
j = pointer(n[2]? "fp" : "mp", n[0]); | |
j = pointer(j, n[1]); | |
return addrof? j.addrof() : j.toString(); | |
j = n[2]? "fp" : "mp"; | |
i = j + "[1][" + j + "[0] + " + n[0] + "]"; | |
return addrof? "[" + j + "[0] + " + n[1] + ", " + j + "[1]]" : | |
i + "[1][" + n[1] + " + " + i + "[0]]"; | |
// return (n[2]? "fp" : "mp") + "[" + n[0] + "][" + n[1] + "]"; | |
} | |
} | |
var code = [], x, y, m, ins; | |
code.push("return function(importing){"); | |
code.push("var mp = [0, newmp()], tmp, tmq, tmr;"); | |
code.push("function main(fps, ret){"); | |
code.push(" var fp = fps[1], pc = fps[2], ic;"); | |
code.push(" for(ic = 0; ic++ < 10000;) switch(pc){"); | |
for(x = 0; x < source.code.length; x++){ | |
code.push(" case " + x + ":"); | |
code.push(" print(\"pc = " + x + "\");"); | |
print("ins = " + showstuff(source.code[x])); | |
switch((ins = source.code[x])[0]){ | |
case 0x00: // nop | |
break; | |
case 0x01: // alt | |
code.push(" fps[2] = " + (x + 1) + ";"); | |
code.push(" alt(" + operand(ins, 1, true) + ", " + operand(ins, 2, true) + ", function(){"); | |
code.push(" return main(fps, ret);"); | |
code.push(" });"); | |
code.push(" return;"); | |
break; | |
case 0x03: // goto | |
code.push(" pc = " + operand(ins, 2, true) + ";"); | |
code.push(" pc = pc[1][pc[0] + " + operand(ins, 1) + "*4];"); | |
code.push(" print(\"mov -> \" + pc);"); | |
code.push(" break;"); | |
break; | |
case 0x04: // call | |
code.push(" fps[2] = " + (x + 1) + ";"); | |
code.push(" fps = [fps, fp = " + operand(ins, 1) + ", pc = " + operand(ins, 2) + "];"); | |
code.push(" break;"); | |
break; | |
case 0x05: // frame | |
code.push(" " + operand(ins, 2) + " = [0, []];"); | |
break; | |
case 0x06: // spawn | |
code.push(" void function(nfps){"); | |
code.push(" spawner(function(){"); | |
code.push(" return main(nfps);"); | |
code.push(" });"); | |
code.push(" }([false, " + operand(ins, 1) + ", " + operand(ins, 2) + "]);"); | |
break; | |
case 0x08: // load | |
code.push(" " + operand(ins, 2) + " = loader(" + operand(ins, 1) + ", imports[" + operand(ins, 0) + "]);"); | |
break; | |
case 0x09: // mcall | |
code.push(" fps[2] = " + (x + 1) + ";"); | |
code.push(" return function(n, f){"); | |
code.push(" return function(){"); | |
code.push(" return n(f, function(){"); | |
code.push(" return main(fps, ret);"); | |
code.push(" });"); | |
code.push(" };"); | |
code.push(" }(" + operand(ins, 2) + "[" + operand(ins, 0) + "], " + operand(ins, 1) + ");"); | |
break; | |
case 0x0c: // ret | |
code.push(" if(!(fps = fps[0]))"); | |
code.push(" return ret;"); | |
code.push(" fp = fps[1];"); | |
code.push(" pc = fps[2];"); | |
code.push(" break;"); | |
break; | |
case 0x0d: // jmp | |
code.push(" pc = " + operand(ins, 2) + ";"); | |
code.push(" break;"); | |
break; | |
case 0x0f: // exit | |
code.push(" return;"); | |
break; | |
case 0x11: // newa | |
code.push(" " + operand(ins, 2) + " = [0, " + operand(ins, 1) + ", []];"); | |
break; | |
case 0x8e: // consl | |
case 0x1a: // consb | |
case 0x1b: // consw | |
case 0x1c: // consp | |
case 0x1d: // consf | |
case 0x1e: // consm | |
case 0x1f: // consmp | |
// Should I add a length element? | |
code.push(" " + operand(ins, 2) + " = [" + operand(ins, 1) + ", " + operand(ins, 2) + "];"); | |
break; | |
case 0x20: // headb | |
case 0x21: // headw | |
case 0x22: // headp | |
case 0x23: // headf | |
case 0x24: // headm | |
case 0x25: // headmp | |
case 0x8d: // headl | |
code.push(" " + operand(ins, 2) + " = " + operand(ins, 1) + "[0];"); | |
break; | |
case 0x26: // tail | |
code.push(" " + operand(ins, 2) + " = " + operand(ins, 1) + "[1];"); | |
break; | |
case 0x56: // lenl | |
code.push(" for(tmp = 0, tmq = " + operand(ins, 1) + "; tmq; tmp++, tmq = tmq[1]);"); | |
code.push(" " + operand(ins, 2) + " = tmp;"); | |
code.push(" tmq = undefined;"); | |
break; | |
case 0x12: // newcb | |
case 0x13: // newcw | |
case 0x14: // newcf | |
case 0x15: // newcp | |
case 0x16: // newcm | |
case 0x17: // newcmp | |
case 0x8f: // newcl | |
code.push(" " + operand(ins, 2) + " = channel();"); | |
break; | |
case 0x18: // send | |
code.push(" fps[2] = " + (x + 1) + ";"); | |
code.push(" " + operand(ins, 2) + "[0](" + operand(ins, 1) + ", function(){"); | |
code.push(" return main(fps, ret);"); | |
code.push(" });"); | |
code.push(" return;"); | |
break; | |
case 0x19: // recv | |
code.push(" fps[2] = " + (x + 1) + ";"); | |
code.push(" " + operand(ins, 1) + "[1](" + operand(ins, 2, true) + ", function(){"); | |
code.push(" return main(fps, ret);"); | |
code.push(" });"); | |
code.push(" return;"); | |
break; | |
case 0x27: // lea | |
code.push(" " + operand(ins, 2) + " = " + operand(ins, 1, true) + ";"); | |
break; | |
// the following seems weird .. documentation suggests | |
// indw, etc grab the value from the array; behaviour | |
// suggests it grabs the address, like indx | |
case 0x28: // indx | |
case 0x52: // indc | |
case 0x72: // indw | |
case 0x73: // indf | |
case 0x74: // indb | |
case 0x91: // indl | |
// TODO: multiply index by element size .. maybe | |
code.push(" tmp = " + operand(ins, 1) + ";"); | |
code.push(" " + operand(ins, 0) + " = [tmp[0] + " + operand(ins, 2) + ", tmp[2]];"); | |
break; | |
case 0x29: // movp | |
case 0x2a: // movm | |
case 0x2b: // movmp | |
case 0x2c: // movb | |
case 0x2d: // movw | |
case 0x2e: // movf | |
case 0x76: // movl | |
code.push(" " + operand(ins, 2) + " = " + operand(ins, 1) + ";"); | |
break; | |
case 0x3a: // addw | |
case 0x53: // addc | |
case 0x39: // addb | |
case 0x3b: // addf | |
code.push(" " + operand(ins, 2) + " = " + operand(ins, 0) + " + " + operand(ins, 1) + ";"); | |
break; | |
case 0x77: // addl | |
// TODO: check logic .. negatives? | |
code.push(" tmp = (" + operand(ins, 1) + "[0] + " + operand(ins, 0) + "[0]) % 0x100000000;"); | |
code.push(" " + operand(ins, 2) + " = [tmp, (tmp < " + operand(ins, 1) + "[0]? 1 : 0) + " + | |
operand(ins, 1) + "[1] + " + operand(ins, 0) + "[1]];"); | |
break; | |
case 0x78: // subl | |
case 0x3c: // subb | |
case 0x3d: // subw | |
case 0x3e: // subf | |
// TODO: long | |
code.push(" " + operand(ins, 2) + " = " + operand(ins, 0) + " - " + operand(ins, 1) + ";"); | |
break; | |
case 0x51: // insc | |
code.push(" " + operand(ins, 2) + " = insc(" + operand(ins, 2) + ", " + operand(ins, 0) + ", " + operand(ins, 1) + ");"); | |
break; | |
case 0x5a: // bleb | |
case 0x60: // blew | |
case 0x66: // blef | |
case 0x6c: // blec | |
case 0x83: // blel | |
case 0x62: // bgew | |
case 0x85: // bgel | |
case 0x68: // bgef | |
case 0x6e: // bgec | |
case 0x5c: // bgeb | |
case 0x61: // bgtw | |
case 0x84: // bgtl | |
case 0x67: // bgtf | |
case 0x6d: // bgtc | |
case 0x5b: // bgtb | |
case 0x81: // bnel | |
case 0x64: // bnef | |
case 0x6a: // bnec | |
case 0x58: // bneb | |
case 0x5e: // bnew | |
// TODO: handle blel | |
code.push(" if(" + operand(ins, 1) + " " + | |
([0x5a, 0x60, 0x66, 0x6c, 0x83].indexOf(ins[0]) >= 0? "<=" : | |
[0x62, 0x85, 0x68, 0x6e, 0x5c].indexOf(ins[0]) >= 0? ">=" : | |
[0x61, 0x84, 0x67, 0x6d, 0x5b].indexOf(ins[0]) >= 0? ">" : | |
"!=") + | |
" " + operand(ins, 0) + "){"); | |
code.push(" pc = " + operand(ins, 2) + ";"); | |
code.push(" break;"); | |
code.push(" }"); | |
break; | |
case 0x55: // lena | |
code.push(" " + operand(ins, 2) + " = " + operand(ins, 1) + "[1];"); | |
break; | |
case 0x63: // beqf | |
case 0x86: // beql | |
case 0x69: // beqc | |
case 0x57: // beqb | |
case 0x5d: // beqw | |
if(ins[0] == 0x86) // blel | |
code.push(" if(" + operand(ins, 1) + "[0] == " + operand(ins, 0) + "[0] && " + | |
operand(ins, 1) + "[1] == " + operand(ins, 0) + "[1]){"); | |
else | |
code.push(" if(" + operand(ins, 1) + " == " + operand(ins, 0) + "){"); | |
code.push(" pc = " + operand(ins, 2) + ";"); | |
code.push(" break;"); | |
code.push(" }"); | |
break; | |
case 0x6f: // slicea | |
code.push(" tmp = " + operand(ins, 2) + ";"); | |
code.push(" tmq = " + operand(ins, 1) + ";"); | |
code.push(" " + operand(ins, 2) + " = [tmp[0] + tmq, " + operand(ins, 0) + " - tmq, tmp[2]];"); | |
break; | |
default: | |
code.push(" // unknown instruction: " + ins[0].toString(16)); | |
} | |
} | |
code.push(" default:"); | |
code.push(" throw \"pc out of bounds\";"); | |
code.push(" }"); | |
code.push("fps[2] = 0;"); | |
code.push("return function(){ return main(fps, ret); };"); | |
code.push("}"); | |
code.push("return exporter(importing, exports, main);"); | |
code.push("}"); | |
//return code.join("\n"); | |
print(code.join("\n")); | |
return Function("exports", "entry", "imports", "exporter", "loader", "spawner", "channel", "insc", "alt", "newmp", code.join("\n"))( | |
source.links, | |
source.entry_pc, | |
source.imports, | |
exporter, | |
loader, | |
spawner, | |
channel, | |
insc, | |
alt, | |
function(data){ // trying not to keep a reference to `source` | |
return function newmp(){ | |
return makemp(data); | |
}; | |
}(source.data)); | |
} | |
builtin = { | |
Sys: function(importing){ | |
var x, ret = []; | |
for(x = 0; x < importing.length; x++) | |
if(importing[x].name == "print" && importing[x].sig == comp(0xac849033, 32)) | |
ret[x] = function(fp, cont){ | |
// print("fp = " + fp.toSource()); | |
print("sys->print: " + printx(getargs(fp))); | |
return cont; | |
}; | |
else | |
throw "requested invalid export (" + importing[x].name + ", " + importing[x].sig + ") from $Sys"; | |
return ret; | |
} | |
}; | |
function printx(args){ | |
var fmt = args.word(), p, c, done, isbig, out = []; | |
for(p = 0; (c = fmt.indexOf("%", p)) >= 0; p = c){ | |
out.push(fmt.substr(p, c - p)); | |
isbig = false; | |
for(done = false; !done && c < fmt.length;) | |
switch(fmt[++c]){ | |
case "s": | |
out.push(args.word()); | |
done = true; | |
break; | |
case "d": | |
if(isbig) | |
out.push(args.dword()); // TODO: .. | |
else | |
out.push(args.word() | 0); | |
done = true; | |
break; | |
case "b": | |
isbig = true; | |
break; | |
case "%": | |
out.push("%"); | |
done = true; | |
break; | |
} | |
c++; | |
} | |
out.push(fmt.substr(p)); | |
return out.join(""); | |
} | |
var t; | |
print(showstuff(t = read(test))); | |
/*print*/(showstuff(t = compile(t))); | |
start(t); | |
runall(); | |
}(); |
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
implement ListTest; | |
include "sys.m"; | |
include "draw.m"; | |
sys: Sys; | |
ListTest: module { | |
init: fn(c: ref Draw->Context, a: list of string); | |
}; | |
init(c: ref Draw->Context, a: list of string){ | |
sys = load Sys Sys->PATH; | |
l := 42 :: 43 :: nil; | |
m := l; | |
m = tl m; | |
sys->print("%d %d %d\n", hd l, hd tl l, hd m); | |
} |
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
implement RandTest; | |
include "sys.m"; | |
include "draw.m"; | |
sys: Sys; | |
RandTest: module { | |
init: fn(c: ref Draw->Context, a: list of string); | |
}; | |
init(c: ref Draw->Context, a: list of string){ | |
sys = load Sys Sys->PATH; | |
test := array[1000] of int; | |
for(i := 0; i < len test; i++) | |
test[i] = i; | |
randomise(test); | |
sys->print("before:\n"); | |
printarr(test); | |
parasort(test, nil); | |
sys->print("after:\n"); | |
printarr(test); | |
} | |
randomise(arr: array of int){ | |
c := chan of int; | |
d := chan of int; | |
for(i := 0; i < len arr; i++) | |
spawn get(arr, i, c, d); | |
for(i = 0; i < len arr; i++) | |
<-d; | |
for(i = 0; i < len arr; i++) | |
arr[i] = <-c; | |
} | |
get(arr: array of int, i: int, c: chan of int, d: chan of int){ | |
t := arr[i]; | |
d<- = 0; | |
c<- = t; | |
} | |
printarr(arr: array of int){ | |
for(x := 0; x < len arr; x++) | |
sys->print("[%d] = %d\n", x, arr[x]); | |
} | |
swap(arr: array of int, m: int, n: int){ | |
t := arr[m]; | |
arr[m] = arr[n]; | |
arr[n] = t; | |
} | |
parasort(arr: array of int, notify: chan of int){ | |
if(len arr == 2){ | |
if(arr[0] > arr[1]) | |
swap(arr, 0, 1); | |
}else if(len arr > 2){ | |
pv := arr[store := 0]; | |
swap(arr, len arr - 1, 0); | |
for(x := 0; x < len arr - 1; x++) | |
if(arr[x] < pv) | |
swap(arr, x, store++); | |
swap(arr, store, len arr - 1); | |
c := chan of int; | |
spawn parasort(arr[0:store], c); | |
spawn parasort(arr[store+1:], c); | |
<-c; <-c; | |
} | |
if(notify != nil) | |
notify<- = 0; | |
} |
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
implement RefTest; | |
include "sys.m"; | |
include "draw.m"; | |
sys: Sys; | |
RefTest: module { | |
init: fn(c: ref Draw->Context, a: list of string); | |
}; | |
w := big 0; | |
s := 0; | |
init(c: ref Draw->Context, a: list of string){ | |
sys = load Sys Sys->PATH; | |
x := "hello"; | |
x[1] = 'i'; | |
x[5] = 's'; | |
x[5] = 't'; | |
y := array[2] of int; | |
y[0] = 42; | |
y[1] = 43; | |
z := sys->print("%s %bd %d!\n", x, big 1234567, add(y[0], y[1])); | |
z++; | |
# if(w++ != big 5) | |
# init(c, a); | |
# spawn th1(); | |
# spawn th2(); | |
d := chan of int; | |
spawn chantest(d); | |
# spawn thread(); | |
# while(s != 1234); | |
sys->print("end!!"); | |
sys->print("%d\n", <-d); | |
test := array[10] of int; | |
for(i := 0; i < len test; i++) | |
test[i] = i; | |
randomise(test); | |
printarr(test); | |
} | |
add(a, b: int): int { | |
return a + b; | |
} | |
thread(){ | |
s = 1234; | |
} | |
randomise(arr: array of int){ | |
c := chan of int; | |
for(i := 0; i < len arr; i++) | |
spawn put(arr, i, c); | |
for(i = 0; i < len arr; i++) | |
c<- = arr[i]; | |
} | |
put(arr: array of int, i: int, c: chan of int){ | |
arr[i] = <-c; | |
} | |
chantest(a: chan of int){ | |
a<- = 42; | |
} | |
th1(){ | |
for(;;) | |
sys->print("thread1!"); | |
} | |
th2(){ | |
for(;;) | |
sys->print("thread2!"); | |
} | |
printarr(arr: array of int){ | |
for(x := 0; x < len arr; x++) | |
sys->print("[%d] = %d\n", x, arr[x]); | |
} | |
swap(arr: array of int, m: int, n: int){ | |
t := arr[m]; | |
arr[m] = arr[n]; | |
arr[n] = t; | |
} | |
parasort(arr: array of int, notify: chan of int){ | |
if(len arr < 3){ | |
if(arr[0] > arr[1]) | |
swap(arr, 0, 1); | |
}else{ | |
pv := arr[store := 0]; | |
for(x := 0; x < len arr; x++) | |
if(arr[x] <= pv) | |
swap(arr, x, store++); | |
c := chan of int; | |
spawn parasort(arr[0:pv], c); | |
spawn parasort(arr[pv+1:], c); | |
<-c; <-c; | |
} | |
if(notify != nil) | |
notify<- = 0; | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment