Skip to content

Instantly share code, notes, and snippets.

@fowlmouth
Last active August 29, 2015 14:22
Show Gist options
  • Save fowlmouth/851106be4aeeced923e6 to your computer and use it in GitHub Desktop.
Save fowlmouth/851106be4aeeced923e6 to your computer and use it in GitHub Desktop.
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
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