Skip to content

Instantly share code, notes, and snippets.

@zacharycarter
Created August 9, 2019 19:46
Show Gist options
  • Save zacharycarter/e3e30f5277d62364d48d957e75f47ddc to your computer and use it in GitHub Desktop.
Save zacharycarter/e3e30f5277d62364d48d957e75f47ddc to your computer and use it in GitHub Desktop.
macros
template builtin = discard
proc add (a, b: int): int = builtin
proc modifyState (str: string) = builtin
proc foobar(foo: var Foo): Foo = builtin
proc debug(bar: var Bar): Bar = builtin
import macros, apiTypes
from compiler/idents import IdentCache
from compiler/vmdef import registerCallback, VmArgs, PCtx
from compiler/modulegraphs import ModuleGraph
from compiler/astalgo import debug
# from compiler/vm import
# # Getting values from VmArgs
# getInt, getFloat, getString, getBool, getNode, #getVarNode,
# # Setting result (return value)
# setResult
include compiler/vm
from compiler/ast import
# Types
PSym, PNode, TNodeKind,
# Getting values from PNodes
getInt, getFloat,
# Creating new PNodes
newNode, newFloatNode, addSon, newTree
from os import splitFile
from threadpool import FlowVar
import compiler/renderer
# Assume location of shared state type in ../state
import ../state
type
Script* = ref object
filename*: string
moduleName*: string
mainModule*: PSym
graph*: ModuleGraph
context*: PCtx
watcher*: FlowVar[int]
proc getVarNode*(a: VmArgs; i: Natural): PNode =
doAssert i < a.rc-1
let s = cast[seq[TFullReg]](a.slots)
doAssert s[i+a.rb+1].kind == rkRegisterAddr
let sreal = s[i+a.rb+1].regAddr[]
doAssert sreal.kind == rkNode
result = sreal.node
proc extractName(n: NimNode): string =
case n.kind
of nnkPostfix:
doAssert n[1].kind == nnkIdent
result = n[1].strVal
of nnkIdent:
result = n.strVal
else:
error("extractName??? " & $n.kind)
proc extractType(n: NimNode): NimNode =
# n is the type node
result = n
proc extractNameType(n: NimNode): tuple[name: string, dtype: NimNode] =
result[0] = extractName(n[0])
result[1] = extractType(n[1])
proc nodeToVal(dtype: NimNode): NimNode =
doAssert dtype.kind == nnkBracketExpr
case dtype[1].strVal
of "float":
result = ident("floatVal")
of "int":
result = ident("intVal")
of "string":
result = ident("strVal")
else:
error("??? broken")
proc addFloatField(nId: NimNode, idx: int, name: string, dtype: NimNode): NimNode =
let fieldName = ident(name)
let resIdent = ident("result")
result = quote do:
doAssert `nId`.sons[`idx`].sons[1].kind == nkFloatLit
`resIdent`.`fieldName` = n.sons[`idx`].sons[1].floatVal
proc addIntField(nId: NimNode, idx: int, name: string, dtype: NimNode): NimNode =
let fieldName = ident(name)
let resIdent = ident("result")
result = quote do:
doAssert `nId`.sons[`idx`].sons[1].kind == nkIntLit
`resIdent`.`fieldName` = n.sons[`idx`].sons[1].intVal.int
proc addStringField(nId: NimNode, idx: int, name: string, dtype: NimNode): NimNode =
let fieldName = ident(name)
let resIdent = ident("result")
result = quote do:
doAssert `nId`.sons[`idx`].sons[1].kind == nkStrLit
`resIdent`.`fieldName` = n.sons[`idx`].sons[1].strVal
proc setStringField(oId: NimNode, pnId: NimNode, sId: NimNode, name: string, dtype: NimNode): NimNode =
let
fieldName = ident(name)
result = quote do:
`pnId`.add nkExprColonExpr.newTree(
newSymNode(`sId`),
nkStrLit.newStrNode(`oId`.`fieldName`)
)
proc setFloatField(oId: NimNode, pnId: NimNode, sId: NimNode, name: string, dtype: NimNode): NimNode =
let
fieldName = ident(name)
result = quote do:
`pnId`.add nkExprColonExpr.newTree(
newSymNode(`sId`),
nkFloatLit.newFloatNode(`oId`.`fieldName`)
)
proc setIntField(oId: NimNode, pnId: NimNode, sId: NimNode, name: string, dtype: NimNode): NimNode =
let
fieldName = ident(name)
result = quote do:
`pnId`.add nkExprColonExpr.newTree(
newSymNode(`sId`),
nkIntLit.newIntNode(`oId`.`fieldName`)
)
proc handleSetScalar(oId: NimNode, pnId: NimNode, sId: NimNode, name: string, dtype: NimNode): NimNode =
result = newStmtList()
case dtype.strVal
of "float":
result.add setFloatField(oId, pnId, sId, name, dtype)
of "int":
result.add setIntField(oId, pnId, sId, name, dtype)
of "string":
result.add setStringField(oId, pnId, sId, name, dtype)
else:
discard
proc handleScalar(nId: NimNode, idx: int, name: string, dtype: NimNode): NimNode =
let nameLit = newLit name
result = quote do:
doAssert `nId`.sons[`idx`].sons[0].kind == nkSym
doAssert `nId`.sons[`idx`].sons[0].sym.name.s == `nameLit`
# type specific doAssert and assignment
case dtype.strVal
of "float":
result.add addFloatField(nId, idx, name, dtype)
of "int":
result.add addIntField(nId, idx, name, dtype)
of "string":
result.add addStringField(nId, idx, name, dtype)
else:
error("handleScalar ??? " & $dtype.strVal)
proc handleSetSeq(oId: NimNode, pnId: NimNode, sId: NimNode, name: string, dtype: NimNode): NimNode =
let
seqKind = dtype.nodeToVal().strVal
fieldName = ident(name)
eceId = ident"e"
bnId = ident"b"
result = quote do:
var `eceId` = nkExprColonExpr.newTree(
newSymNode(`sId`),
)
var `bnId` = nkBracket.newTree()
for val in `oid`.`fieldName`:
case `seqKind`
of "floatVal":
`bnId`.add nkFloatLit.newFloatNode(parseFloat(val))
`eceId`.add `bnId`
of "intVal":
`bnId`.add nkIntLit.newIntNode(parseInt(val))
`eceId`.add `bnId`
of "strVal":
`bnId`.add nkStrLit.newStrNode(val)
`eceId`.add `bnId`
else:
discard
`pnId`.add `eceId`
proc handleSeq(nId: NimNode, idx: int, name: string, dtype: NimNode): NimNode =
let
nameLit = newLit name
nodeToVal = dtype.nodeToVal
fieldName = ident(name)
resIdent = ident("result")
result = quote do:
doAssert `nId`.sons[`idx`].sons[0].kind == nkSym
doAssert `nId`.sons[`idx`].sons[0].sym.name.s == `nameLit`
for j in `nId`.sons[`idx`].sons[1].sons:
`resIdent`.`fieldName`.add j.`nodeToVal`
macro genSetProc(t: typedesc): untyped =
let
tImpl = t.getImpl
tsym = tImpl[0]
procName = ident("set" & $tSym)
doAssert tImpl[2].kind == nnkObjectTy
var
idxNameType = newSeq[(int, string, NimNode)]()
idx = 1
for ch in tImpl[2][2]:
case ch.kind
of nnkEmpty:
discard
of nnkIdentDefs:
let (name, dtype) = extractNameType(ch)
idxNameType.add (idx, name, dtype)
else:
error("genSetProc ??? " & $ch.treeRepr)
inc idx
let
oId = ident"o"
aId = ident"a"
icId = ident"ic"
mId = ident"m"
pnId = ident"pn"
sId = ident"s"
var procBody = newStmtList()
procBody.add quote do:
var `pnId` = nkObjConstr.newTree()
`pnId`.add nkEmpty.newNode()
let resId = ident"result"
for (idx, fieldName, dtype) in idxNameType:
procBody.add quote do:
var `sId` = newSym(skField, `icId`.getIdent(`fieldName`), `mId`, `mId`.info)
case dtype.kind
of nnkSym, nnkIdent:
procBody.add handleSetScalar(oId, pnId, sId, fieldName, dtype)
of nnkBracketExpr:
echo "\n\n\n\n"
echo dtype.repr
procBody.add handleSetSeq(oId, pnId, sId, fieldName, dtype)
else:
echo "No was ", dtype.kind
discard
procBody.add quote do:
setResult(`aId`, `pnId`)
result = quote do:
proc `procName`(`oId`: `tsym`, `aId`: VmArgs, `icId`: IdentCache, `mId`: PSym) =
`procBody`
macro genGetProc(t: typedesc): untyped =
let
tImpl = t.getImpl
tsym = tImpl[0]
procName = ident("get" & $tSym)
doAssert tImpl[2].kind == nnkObjectTy
var
idxNameType = newSeq[(int, string, NimNode)]()
idx = 1
for ch in tImpl[2][2]:
case ch.kind
of nnkEmpty:
discard
of nnkIdentDefs:
let (name, dtype) = extractNameType(ch)
idxNameType.add (idx, name, dtype)
else:
error("genGetProc ??? " & $ch.treeRepr)
inc idx
let
aId = ident"a"
iId = ident"i"
nId = ident"n"
var procBody = newStmtList()
procBody.add quote do:
let `nId` = getVarNode(`aId`, `iId`)
doAssert `nId`.sons[0].kind == nkEmpty
let resId = ident("result")
for (idx, name, dtype) in idxNameType:
procBody.add quote do:
doAssert `nId`.sons[`idx`].kind == nkExprColonExpr
case dtype.kind
of nnkSym, nnkIdent:
procBody.add handleScalar(nId, idx, name, dtype)
of nnkBracketExpr:
procBody.add handleSeq(nId, idx, name, dtype)
else:
echo "No was ", dtype.kind
discard
result = quote do:
proc `procName`(`aId`: VmArgs, `iId`: Natural): `tsym` =
`procBody`
template bindGetSetResultProc(t: typedesc) =
genGetProc(t)
genSetProc(t)
bindGetSetResultProc(Foo)
bindGetSetResultProc(Bar)
proc exposeScriptApi* (script: Script) =
template expose (procName, procBody: untyped): untyped {.dirty.} =
script.context.registerCallback(
script.moduleName & "." & astToStr(procName),
proc (a: VmArgs) =
procBody
)
expose add2:
# We need to use procs like getInt to retrieve the argument values from VmArgs
# Instead of using the return statement we need to use setResult
let arg1 = getInt(a, 0)
let arg2 = getInt(a, 1)
setResult(a, arg1 + arg2)
expose modifyState:
modifyMe = getString(a, 0)
echo "`", script.moduleName, "` has changed state.modifyMe to `", modifyMe, "`"
expose foobar:
# debug(getVarNode(a, 0))
var foo = getFoo(a, 0)
foo.name = "test"
echo "`", script.moduleName, "` has changed foo.name to `", foo.name, "`"
setFoo(foo, a, script.graph.cache, script.mainModule)
expose debug:
var bar = getBar(a, 0)
echo bar.ss[0]
bar.ss[0] = "barzzz"
setBar(bar, a, script.graph.cache, script.mainModule)
type
Foo* = object
name*: string
Bar* = object
ss*: seq[string]
proc newFoo(name: string): Foo =
result.name = name
proc newBar(): Bar =
result.ss.add("barssss")
let args = [8, 12]
echo "From NIMS to NIM and back: ", args[0], " + ", args[1], " = ",
add(args[0], args[1])
proc subtract* (a, b: int): int =
# var f = Foo(name: "initial")
# f = foobar(f)
# echo f.name
var bar = newBar()
bar = debug(bar)
echo bar.ss[0]
return a - b
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment