Last active
August 29, 2015 14:22
-
-
Save fowlmouth/851106be4aeeced923e6 to your computer and use it in GitHub Desktop.
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
import cmodel, stdobj | |
type | |
Instr* {.pure.} = enum | |
NOP, PushNIL, PushPOD, Pop, Dup, Send | |
iseq = seq[byte] | |
import tables | |
type InstrBuilder* = object | |
iset*: iseq | |
index*: int | |
labels*: Table[string,int] | |
proc initInstrBuilder* : InstrBuilder = | |
newSeq result.iset, 0 | |
result.labels = initTable[string,int]() | |
type | |
RawBytes* = cstring | |
Serializable* = concept obj | |
var builder: InstrBuilder | |
serialize(obj, builder) | |
var source: RawBytes | |
unserialize(obj, source) | |
proc ensureLen* (some: var seq; len: int) {.inline.}= | |
if some.len < len: some.setLen len | |
template addByte (i: var InstrBuilder; b: untyped): stmt = | |
let byt = byte(b) | |
i.iset.ensureLen i.index+1 | |
i.iset[i.index] = byt | |
i.index += 1 | |
template addNullBytes (i: var InstrBuilder; n: int): stmt = | |
i.iset.ensureLen i.index+n | |
i.index += n | |
proc pushPOD* (i: var InstrBuilder; obj: Serializable) = | |
mixin serialize | |
let ty = typeComponent(type(obj)) | |
let id = ty.nim_type | |
do_assert id < 127, "FIX ASAP" # make this two bytes if it gets big | |
do_assert id > 0, "invalid id "& $id & "::"& ty.name | |
i.addByte Instr.PushPOD | |
i.addByte id | |
serialize(obj, i) | |
proc pushNIL* (i: var InstrBuilder) = | |
i.addByte Instr.PushNIL | |
proc dup* (i: var InstrBuilder) = | |
i.addByte Instr.Dup | |
proc pop* (i: var InstrBuilder) = | |
i.addByte Instr.Pop | |
proc send* (i: var InstrBuilder; msg:string; args:int) = | |
let L = msg.len | |
i.addByte Instr.Send | |
i.addByte args | |
i.addByte L | |
let IDX = i.index | |
i.addNullBytes L | |
copyMem i.iset[IDX].addr, msg.cstring, L | |
proc done* (i: var InstrBuilder): iseq = | |
i.iset.setLen i.index | |
return i.iset | |
import endians | |
proc serialize* (some:int; builder:var InstrBuilder) = | |
let i = builder.index | |
builder.addNullBytes sizeof(some) | |
let dest = builder.iset[i].addr | |
var some = some | |
when sizeof(some) == 4: | |
bigEndian32(dest, some.addr) | |
elif sizeof(some) == 8: | |
bigEndian64(dest, some.addr) | |
else: | |
static: | |
assert false, "wat the size of int is on your masheen omg fix" | |
proc unserialize* (some:var int; source:RawBytes): int = | |
when sizeof(some) == 4: | |
bigEndian32(some.addr, source) | |
result = 4 | |
elif sizeof(some) == 8: | |
bigEndian64(some.addr, source) | |
result = 8 | |
defPrimitiveComponent(RawBytes, RawBytes) | |
defineMessage(cxInt, "loadFromRaw:") | |
do (byteSrc): | |
let dat = byteSrc.dataPtr(RawBytes) | |
let my_int = this.asPtr(int) | |
let len_read = my_int[].unserialize dat[] | |
assert len_read == sizeof(int) | |
result = objInt(len_read) | |
type | |
VM = object | |
stack*: seq[Object] | |
iset*: seq[byte] | |
pc*: int | |
sp*: int | |
proc initVM* (iset: seq[byte]): VM = | |
VM(stack: @[], iset: iset) | |
import strutils | |
proc tick* (vm: var VM) = | |
template push (o:Object):stmt = | |
vm.sp += 1 | |
vm.stack.ensureLen vm.sp+1 | |
vm.stack[vm.sp] = o | |
template pop : Object = | |
let r = vm.stack[vm.sp] | |
vm.sp -= 1 | |
r | |
template top : Object = | |
vm.stack[vm.sp] | |
template iset: iseq = vm.iset | |
var idx = vm.pc | |
var cstr: cstring | |
case iset[idx].Instr | |
of Instr.NOP: | |
idx += 1 | |
of Instr.Dup: | |
idx += 1 | |
push top() | |
of Instr.Pop: | |
idx += 1 | |
discard pop() | |
of Instr.PushNIL: | |
idx += 1 | |
push nil.Object | |
of Instr.PushPOD: | |
idx += 1 | |
let id = iset[idx].int | |
let ty = dataComponent(id) | |
idx += 1 | |
let cstr = cast[cstring](iset[idx].addr) | |
let src = objRawBytes(cstr) | |
let obj = ty.aggr.instantiate() | |
let L = obj.send("loadFromRaw:", src).dataVar(int) | |
idx += L | |
push obj | |
of Instr.Send: | |
idx += 1 | |
let argN = iset[idx].int | |
idx += 1 | |
let L = iset[idx].int | |
idx += 1 | |
var str = newString(L) | |
copyMem str[0].addr, iset[idx].addr, L | |
idx += L | |
#yield "SEND "& $args &" "&str | |
var args = newSeq[Object](argN) | |
let H = <argN | |
echo "popping ", argN, " args" | |
for i in 0 .. H: | |
echo "." | |
args[H-i] = pop() | |
let recv = pop() | |
push recv.send(str, args) | |
else: | |
echo "wat to do here ?? ", idx | |
quit 1 | |
vm.pc = idx | |
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
import vm, cmodel, stdobj | |
import macros | |
macro showEffect (body, code:untyped):stmt = | |
let do_debug = defined(debug) | |
result = newStmtList() | |
for node in code.children: | |
result.add node | |
if do_debug: | |
let nodestr = repr(node) | |
result.add(quote do: | |
echo "effect from ", `nodestr`, ": ", `body`.iset) | |
var body = initInstrBuilder() | |
showEffect(body): | |
body.pushPOD int(1) | |
body.pushPOD int(1) | |
body.send "+", 1 | |
body.send "print", 0 | |
var vm1 = initVM(body.done) | |
while vm1.pc < vm1.iset.high: | |
vm1.tick |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment