nim-stew/std_shims/macros_shim.nim

237 lines
6.6 KiB
Nim

import
macros
export
macros
type
FieldDescription* = object
name*: NimNode
isPublic*: bool
typ*: NimNode
pragmas*: NimNode
caseField*: NimNode
caseBranch*: NimNode
const
nnkPragmaCallKinds = {nnkExprColonExpr, nnkCall, nnkCallStrLit}
proc findPragma*(pragmas: NimNode, pragmaSym: NimNode): NimNode =
for p in pragmas:
if p.kind == nnkSym and p == pragmaSym:
return p
if p.kind in nnkPragmaCallKinds and p.len > 0 and p[0].kind == nnkSym and p[0] == pragmaSym:
return p
iterator recordFields*(typeImpl: NimNode): FieldDescription =
# TODO: This doesn't support inheritance yet
let
objectType = typeImpl[2]
recList = objectType[2]
type
RecursionStackItem = tuple
currentNode: NimNode
currentChildItem: int
parentCaseField: NimNode
parentCaseBranch: NimNode
if recList.len > 0:
var traversalStack: seq[RecursionStackItem] = @[
(recList, 0, NimNode(nil), NimNode(nil))
]
template recuseInto(childNode: NimNode,
currentCaseField: NimNode = nil,
currentCaseBranch: NimNode = nil) =
traversalStack.add (childNode, 0, currentCaseField, currentCaseBranch)
while true:
assert traversalStack.len > 0
var stackTop = traversalStack[^1]
let recList = stackTop.currentNode
let idx = stackTop.currentChildItem
let n = recList[idx]
inc traversalStack[^1].currentChildItem
if idx == recList.len - 1:
discard traversalStack.pop
case n.kind
of nnkRecWhen:
for i in countdown(n.len - 1, 0):
let branch = n[i]
case branch.kind:
of nnkElifBranch:
recuseInto branch[1]
of nnkElse:
recuseInto branch[0]
else:
assert false
continue
of nnkRecCase:
assert n.len > 0
for i in countdown(n.len - 1, 1):
let branch = n[i]
case branch.kind
of nnkOfBranch:
recuseInto branch[^1], n[0], branch
of nnkElse:
recuseInto branch[0], n[0], branch
else:
assert false
recuseInto newTree(nnkRecCase, n[0])
continue
of nnkIdentDefs:
let fieldType = n[^2]
for i in 0 ..< n.len - 2:
var field: FieldDescription
field.name = n[i]
field.typ = fieldType
field.caseField = stackTop.parentCaseField
field.caseBranch = stackTop.parentCaseBranch
if field.name.kind == nnkPragmaExpr:
field.pragmas = field.name[1]
field.name = field.name[0]
if field.name.kind == nnkPostfix:
field.isPublic = true
field.name = field.name[1]
yield field
of nnkNilLit, nnkDiscardStmt, nnkCommentStmt, nnkEmpty:
discard
else:
assert false
if traversalStack.len == 0: break
proc skipPragma*(n: NimNode): NimNode =
if n.kind == nnkPragmaExpr: n[0]
else: n
# FIXED NewLit
proc newLitFixed*(c: char): NimNode {.compileTime.} =
## produces a new character literal node.
result = newNimNode(nnkCharLit)
result.intVal = ord(c)
proc newLitFixed*(i: int): NimNode {.compileTime.} =
## produces a new integer literal node.
result = newNimNode(nnkIntLit)
result.intVal = i
proc newLitFixed*(i: int8): NimNode {.compileTime.} =
## produces a new integer literal node.
result = newNimNode(nnkInt8Lit)
result.intVal = i
proc newLitFixed*(i: int16): NimNode {.compileTime.} =
## produces a new integer literal node.
result = newNimNode(nnkInt16Lit)
result.intVal = i
proc newLitFixed*(i: int32): NimNode {.compileTime.} =
## produces a new integer literal node.
result = newNimNode(nnkInt32Lit)
result.intVal = i
proc newLitFixed*(i: int64): NimNode {.compileTime.} =
## produces a new integer literal node.
result = newNimNode(nnkInt64Lit)
result.intVal = i
proc newLitFixed*(i: uint): NimNode {.compileTime.} =
## produces a new unsigned integer literal node.
result = newNimNode(nnkUIntLit)
result.intVal = BiggestInt(i)
proc newLitFixed*(i: uint8): NimNode {.compileTime.} =
## produces a new unsigned integer literal node.
result = newNimNode(nnkUInt8Lit)
result.intVal = BiggestInt(i)
proc newLitFixed*(i: uint16): NimNode {.compileTime.} =
## produces a new unsigned integer literal node.
result = newNimNode(nnkUInt16Lit)
result.intVal = BiggestInt(i)
proc newLitFixed*(i: uint32): NimNode {.compileTime.} =
## produces a new unsigned integer literal node.
result = newNimNode(nnkUInt32Lit)
result.intVal = BiggestInt(i)
proc newLitFixed*(i: uint64): NimNode {.compileTime.} =
## produces a new unsigned integer literal node.
result = newNimNode(nnkUInt64Lit)
result.intVal = BiggestInt(i)
proc newLitFixed*(b: bool): NimNode {.compileTime.} =
## produces a new boolean literal node.
result = if b: bindSym"true" else: bindSym"false"
proc newLitFixed*(f: float32): NimNode {.compileTime.} =
## produces a new float literal node.
result = newNimNode(nnkFloat32Lit)
result.floatVal = f
proc newLitFixed*(f: float64): NimNode {.compileTime.} =
## produces a new float literal node.
result = newNimNode(nnkFloat64Lit)
result.floatVal = f
proc newLitFixed*(s: string): NimNode {.compileTime.} =
## produces a new string literal node.
result = newNimNode(nnkStrLit)
result.strVal = s
proc newLitFixed*[N,T](arg: array[N,T]): NimNode {.compileTime.}
proc newLitFixed*[T](arg: seq[T]): NimNode {.compileTime.}
proc newLitFixed*(arg: tuple): NimNode {.compileTime.}
proc newLitFixed*(arg: object): NimNode {.compileTime.} =
result = nnkObjConstr.newTree(arg.type.getTypeInst[1])
for a, b in arg.fieldPairs:
result.add nnkExprColonExpr.newTree( newIdentNode(a), newLitFixed(b) )
proc newLitFixed*[N,T](arg: array[N,T]): NimNode {.compileTime.} =
result = nnkBracket.newTree
for x in arg:
result.add newLitFixed(x)
proc newLitFixed*[T](arg: seq[T]): NimNode {.compileTime.} =
var bracket = nnkBracket.newTree
for x in arg:
bracket.add newLitFixed(x)
result = nnkCall.newTree(
nnkBracketExpr.newTree(
nnkAccQuoted.newTree( bindSym"@" ),
getTypeInst( bindSym"T" )
),
bracket
)
proc newLitFixed*(arg: tuple): NimNode {.compileTime.} =
result = nnkPar.newTree
for a,b in arg.fieldPairs:
result.add nnkExprColonExpr.newTree(newIdentNode(a), newLitFixed(b))
iterator typedParams*(n: NimNode, skip = 0): (NimNode, NimNode) =
for i in (1 + skip) ..< n.params.len:
let paramNodes = n.params[i]
let paramType = paramNodes[^2]
for j in 0 ..< paramNodes.len - 2:
yield (paramNodes[j], paramType)