-
-
Save zacharycarter/e3e30f5277d62364d48d957e75f47ddc to your computer and use it in GitHub Desktop.
macros
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
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 |
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
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) |
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
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") |
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
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