Updated to work with nim 0.20

- Attempt to fix deprecated this:self pragma by injecting self to methods and properties (needs more testing)
- Changed import headers to use / (slash) instead of . (period)
- Fixed object branch in godotapigen.nim
- Fixed deprecated nimNode.ident with nimNode.strVal

Fix toGodotName function

Consider procCall calls as special cases, otherwise it gives problems in _init function

Fix infinite recursive call in Godot 3.2
This commit is contained in:
Dwana Games 2019-06-21 20:11:29 -05:00 • committed by Ruslan Mustakov
commit 0fecfdb3b8
23 changed files with 294 additions and 211 deletions

View file

@ -3,7 +3,7 @@
import hashes
import vector3
import internal.godotinternaltypes, internal.godotstrings
import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi
proc initAABB*(pos, size: Vector3): AABB {.inline.} =

View file

@ -1,7 +1,7 @@
# Copyright 2018 Xored Software, Inc.
import hashes
import internal.godotinternaltypes, internal.godotarrays
import internal/godotinternaltypes, internal/godotarrays
type
Array* = ref object

View file

@ -1,8 +1,8 @@
# Copyright 2018 Xored Software, Inc.
import hashes
import internal.godotinternaltypes, internal.godotdictionaries,
internal.godotvariants, internal.godotstrings
import internal/godotinternaltypes, internal/godotdictionaries,
internal/godotvariants, internal/godotstrings
type
Dictionary* = ref object

View file

@ -2,8 +2,8 @@
import hashes
import internal.godotinternaltypes, internal.godotnodepaths,
internal.godotstrings
import internal/godotinternaltypes, internal/godotnodepaths,
internal/godotstrings
type
NodePath* = ref object

View file

@ -4,7 +4,7 @@ import hashes
import vector3
import internal.godotinternaltypes, internal.godotstrings
import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi
proc initPlane*(a, b, c, d: float32): Plane {.inline.} =

View file

@ -3,8 +3,8 @@
import hashes
import godotcoretypes
import internal.godotinternaltypes, internal.godotpoolarrays,
internal.godotstrings
import internal/godotinternaltypes, internal/godotpoolarrays,
internal/godotstrings
import vector2, vector3, colors
template definePoolArrayBase(T, GodotT, DataT, fieldName, newProcName,

View file

@ -2,7 +2,7 @@
import hashes
import internal.godotinternaltypes, internal.godotstrings
import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi
proc initQuat*(x, y, z, w: float32): Quat {.inline.} =

View file

@ -3,7 +3,7 @@
import hashes
import vector2
import internal.godotinternaltypes, internal.godotstrings
import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi
{.push stackTrace: off.}

View file

@ -2,7 +2,7 @@
import hashes
import godotcoretypes, internal.godotinternaltypes, gdnativeapi
import godotcoretypes, internal/godotinternaltypes, gdnativeapi
proc initRID*(): RID {.inline.} =
getGDNativeAPI().ridNew(result)

View file

@ -2,7 +2,7 @@
import hashes, vector2
import internal.godotinternaltypes, internal.godotstrings
import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi
proc initTransform2D*(): Transform2D {.inline.} =

View file

@ -2,7 +2,7 @@
import hashes
import internal.godotinternaltypes, internal.godotstrings
import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi
import basis, vector3

View file

@ -1,9 +1,9 @@
import tables, hashes
import godotcoretypes
import internal.godotinternaltypes, internal.godotvariants,
internal.godotstrings, internal.godotdictionaries,
internal.godotarrays
import internal/godotinternaltypes, internal/godotvariants,
internal/godotstrings, internal/godotdictionaries,
internal/godotarrays
type
Variant* = ref object

View file

@ -2,7 +2,7 @@
import math, godotbase, hashes
import internal.godotinternaltypes, internal.godotstrings
import internal/godotinternaltypes, internal/godotstrings
import godotcoretypes, gdnativeapi
{.push stackTrace: off.}

View file

@ -1,6 +1,6 @@
# Copyright 2018 Xored Software, Inc.
import internal.godotinternaltypes, core.godotcoretypes, macros
import internal/godotinternaltypes, core/godotcoretypes, macros
type
ColorData* {.byref.} = object
@ -3593,7 +3593,7 @@ proc setGDNativeAPIInternal(apiStruct: pointer, initOptions: ptr GDNativeInitOpt
# Not used
discard
if not header.next.isNil:
if not header.next.isNil and header != header.next:
setGDNativeAPIInternal(header.next, initOptions,
foundCoreApi, foundNativeScriptApi)

View file

@ -1,14 +1,14 @@
# Copyright 2018 Xored Software, Inc.
import core.godotbase, godotinternal
import core.godotcoretypes
import core.vector2, core.rect2, core.vector3, core.transform2d, core.planes,
core.quats
import core.aabb, core.basis, core.transforms, core.colors, core.nodepaths,
core.rids
import core.dictionaries, core.arrays, core.poolarrays, core.variants
import core/godotbase, godotinternal
import core/godotcoretypes
import core/vector2, core/rect2, core/vector3, core/transform2d, core/planes,
core/quats
import core/aabb, core/basis, core/transforms, core/colors, core/nodepaths,
core/rids
import core/dictionaries, core/arrays, core/poolarrays, core/variants
import nim.godotmacros, nim.godotnim
import nim/godotmacros, nim/godotnim
export godotbase, godotcoretypes, vector2, rect2, vector3, transform2d, planes,
quats, aabb, basis, transforms, colors, nodepaths, rids, dictionaries,

View file

@ -2,17 +2,22 @@
import streams, json, os, strutils, times, sets, tables, options
import sequtils, algorithm
import compiler.ast, compiler.renderer, compiler.idents, compiler.astalgo
import compiler/ast, compiler/renderer, compiler/idents, compiler/astalgo, compiler/lineinfos
when (NimMajor, NimMinor, NimPatch) >= (0, 19, 0):
var gic* = newIdentCache()
var gic = newIdentCache()
proc getIdent(ident: string): PIdent =
getIdent(gic, ident)
proc ident(ident: string): PNode =
result = newNode(nkIdent)
result.ident = getIdent(ident)
result = PNode(kind: nkIdent, ident: getIdent(ident))
proc newPNode(kind: TNodeKind): PNode =
result = PNode(kind: kind)
result.info.fileIndex = InvalidFileIdx
result.info.col = int16(-1)
result.info.line = uint16(0)
proc addChain(node: PNode, others: varargs[PNode]): PNode {.discardable.} =
for other in others:
@ -21,37 +26,37 @@ proc addChain(node: PNode, others: varargs[PNode]): PNode {.discardable.} =
proc newIdentDefs(name, typ: PNode,
defaultVal: PNode = nil): PNode =
result = newNode(nkIdentDefs)
result = newPNode(nkIdentDefs)
result.add(name)
result.add(typ)
if defaultVal.isNil:
result.add(newNode(nkEmpty))
result.add(newPNode(nkEmpty))
else:
result.add(defaultVal)
proc newProc(name: PNode, params: openArray[PNode], body = newNode(nkEmpty),
proc newProc(name: PNode, params: openArray[PNode], body = newPNode(nkEmpty),
procType = nkProcDef): PNode =
result = newNode(procType)
result = newPNode(procType)
result.add(name)
result.add(newNode(nkEmpty))
result.add(newNode(nkEmpty))
let formalParams = newNode(nkFormalParams)
result.add(newPNode(nkEmpty))
result.add(newPNode(nkEmpty))
let formalParams = newPNode(nkFormalParams)
for param in params:
formalParams.add(param)
result.add(formalParams)
result.add(newNode(nkEmpty))
result.add(newNode(nkEmpty))
result.add(newPNode(nkEmpty))
result.add(newPNode(nkEmpty))
result.add(body)
proc newIfStmt(condition, body: PNode): PNode =
result = newNode(nkIfStmt)
let branch = newNode(nkElifBranch)
result = newPNode(nkIfStmt)
let branch = newPNode(nkElifBranch)
result.add(branch)
branch.add(condition)
branch.add(body)
proc newCall(theProc: PNode, args: varargs[PNode]): PNode =
result = newNode(nkCall)
result = newPNode(nkCall)
result.add(theProc)
for arg in args:
result.add(arg)
@ -60,66 +65,66 @@ proc newCall(theProc: string, args: varargs[PNode]): PNode =
newCall(ident(theProc), args)
proc newStrLit(s: string): PNode =
result = newNode(nkStrLit)
result = newPNode(nkStrLit)
result.strVal = s
proc newRStrLit(s: string): PNode =
result = newNode(nkRStrLit)
result = newPNode(nkRStrLit)
result.strVal = s
proc newCStringLit(s: string): PNode =
newNode(nkCallStrLit).addChain(ident("cstring"), newRStrLit(s))
newPNode(nkCallStrLit).addChain(ident("cstring"), newRStrLit(s))
proc newIntLit(val: BiggestInt): PNode =
result = newNode(nkIntLit)
result = newPNode(nkIntLit)
result.intVal = val
proc newInt64Lit(val: BiggestInt): PNode =
result = newNode(nkInt64Lit)
result = newPNode(nkInt64Lit)
result.intVal = val
proc newFloatLit(val: BiggestFloat): PNode =
result = newNode(nkFloatLit)
result = newPNode(nkFloatLit)
result.floatVal = val
proc newFloat64Lit(val: BiggestFloat): PNode =
result = newNode(nkFloat64Lit)
result = newPNode(nkFloat64Lit)
result.floatVal = val
proc newNilLit(): PNode =
result = newNode(nkNilLit)
result = newPNode(nkNilLit)
proc newDotExpr(left, right: PNode): PNode =
result = newNode(nkDotExpr)
result = newPNode(nkDotExpr)
result.add(left)
result.add(right)
proc newCommand(left, right: PNode): PNode =
result = newNode(nkCommand)
result = newPNode(nkCommand)
result.add(left)
result.add(right)
proc infix(left, op, right: PNode): PNode =
result = newNode(nkInfix)
result = newPNode(nkInfix)
result.add(op)
result.add(left)
result.add(right)
proc postfix(left: PNode, op: string): PNode =
result = newNode(nkPostfix)
result = newPNode(nkPostfix)
result.add(ident(op))
result.add(left)
proc prefix(op: string, right: PNode): PNode =
result = newNode(nkPrefix)
result = newPNode(nkPrefix)
result.add(ident(op))
result.add(right)
proc newBracketExpr(first, bracket: PNode): PNode =
newNode(nkBracketExpr).addChain(first, bracket)
newPNode(nkBracketExpr).addChain(first, bracket)
proc newEmptyNode(): PNode =
newNode(nkEmpty)
newPNode(nkEmpty)
type GodotType = ref object
name: string
@ -212,42 +217,42 @@ proc toNimStyle(name: string): string =
proc newRefTypeNode(typeSection: PNode, typ, base, doc: string,
isExported = true) =
let typeDef = newNode(nkTypeDef)
let typeDef = newPNode(nkTypeDef)
typeSection.add(typeDef)
if isExported:
typeDef.add(postfix(ident(typ), "*"))
else:
typeDef.add(ident(typ))
typeDef.add(newNode(nkEmpty)) # generic
let objTy = newNode(nkObjectTy)
let refTy = newNode(nkRefTy)
typeDef.add(newPNode(nkEmpty)) # generic
let objTy = newPNode(nkObjectTy)
let refTy = newPNode(nkRefTy)
refTy.add(objTy)
typeDef.add(refTy)
objTy.add(newNode(nkEmpty))
let inherit = newNode(nkOfInherit)
objTy.add(newPNode(nkEmpty))
let inherit = newPNode(nkOfInherit)
inherit.add(ident(base))
objTy.add(inherit)
if doc.len > 0:
let recList = newNode(nkRecList)
let docNode = newNode(nkCommentStmt)
let recList = newPNode(nkRecList)
let docNode = newPNode(nkCommentStmt)
docNode.comment = doc
recList.add(docNode)
objTy.add(recList)
else:
objTy.add(newNode(nkEmpty))
objTy.add(newPNode(nkEmpty))
proc makeConstSection(constObj: JsonNode): PNode =
if constObj.len == 0:
return newNode(nkEmpty)
return newPNode(nkEmpty)
result = newNode(nkConstSection)
result = newPNode(nkConstSection)
for field, val in constObj:
let def = newNode(nkConstDef)
let def = newPNode(nkConstDef)
def.add(postfix(ident(field), "*"))
def.add(newNode(nkEmpty)) # infer type
def.add(newPNode(nkEmpty)) # infer type
var valNode: PNode
if val.kind == JInt:
valNode = newInt64Lit(val.num)
@ -257,7 +262,7 @@ proc makeConstSection(constObj: JsonNode): PNode =
elif val.kind == JBool:
valNode = ident($val.bval)
elif val.kind == JString:
valNode = newNode(nkStrLit)
valNode = newPNode(nkStrLit)
valNode.strVal = val.str
else:
raise newException(ValueError, "Unexpected constant kind: " & $val.kind)
@ -286,7 +291,7 @@ type
isBase: bool
isDiscardable: bool
const standardTypes = toSet(
const standardTypes = toHashSet(
["bool", "cint", "int", "uint8", "int8", "uint16", "int16", "uint32", "int32",
"uint64", "Error",
"int64", "float32", "cfloat", "float64", "GodotString", "Vector2", "Rect2",
@ -295,18 +300,18 @@ const standardTypes = toSet(
"PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray",
"PoolVector2Array", "PoolVector3Array", "PoolColorArray"])
const smallIntTypes = toSet(["uint8", "int8", "uint16", "int16", "uint32",
"int32", "cint", "int", "Error"])
const int64Types = toSet(["uint64", "int64"])
const smallIntTypes = toHashSet(["uint8", "int8", "uint16", "int16", "uint32",
"int32", "cint", "int", "Error"])
const int64Types = toHashSet(["uint64", "int64"])
const intTypes = union(smallIntTypes, int64Types)
const float64Types = toSet(["float64", "cdouble"])
const float32Types = toSet(["float32", "cfloat"])
const float64Types = toHashSet(["float64", "cdouble"])
const float32Types = toHashSet(["float32", "cfloat"])
const floatTypes = union(float64Types, float32Types)
const arrayTypes = toSet(["Array", "PoolByteArray",
const arrayTypes = toHashSet(["Array", "PoolByteArray",
"PoolIntArray", "PoolRealArray", "PoolStringArray", "PoolVector2Array",
"PoolVector3Array", "PoolColorArray"])
const wrapperTypes = union(arrayTypes,
toSet(["NodePath", "Dictionary", "Variant"]))
toHashSet(["NodePath", "Dictionary", "Variant"]))
proc getInternalPtr(varName: PNode, typ: string): PNode =
assert(typ in wrapperTypes)
@ -314,7 +319,7 @@ proc getInternalPtr(varName: PNode, typ: string): PNode =
proc newNilCheck(ident, toAssign: PNode): PNode =
newIfStmt(newCall("isNil", ident),
newNode(nkAsgn).addChain(ident).addChain(
newPNode(nkAsgn).addChain(ident).addChain(
toAssign
)
)
@ -387,6 +392,8 @@ proc makeDefaultValue(arg: MethodArg): PNode =
result = newCall("newVariant")
else:
failed = true
elif arg.typ == "Dictionary":
result = newCall("newDictionary")
else:
failed = true
@ -403,12 +410,12 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
meth: MethodInfo, withImplementation: bool) =
var body: PNode
if not withImplementation:
body = newNode(nkEmpty)
body = newPNode(nkEmpty)
elif meth.godotName == "_init" and meth.typ.godotName == "Object":
# It's not real (calling it crashes) and will be removed later,
# but we use init() convention in Nim, so it needs to work.
body = newNode(nkStmtList).addChain(
newNode(nkDiscardStmt).addChain(newNode(nkEmpty)))
body = newPNode(nkStmtList).addChain(
newPNode(nkDiscardStmt).addChain(newPNode(nkEmpty)))
else:
let methGodotName = if meth.godotName.startsWith('_'):
"underscore" & meth.godotName[1..^1]
@ -419,12 +426,12 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
if methodBindName[0].isUpperAscii():
methodBindName[0] = methodBindName[0].toLowerAscii()
if methodBindName notin methodBindRegistry:
let methodBindDecl = newNode(nkVarSection).addChain(
let methodBindDecl = newPNode(nkVarSection).addChain(
newIdentDefs(
newNode(nkPragmaExpr).addChain(
newPNode(nkPragmaExpr).addChain(
ident(methodBindName)).addChain(
newNode(nkPragma).addChain(ident("threadvar"))),
newNode(nkPtrTy).addChain(ident("GodotMethodBind"))
newPNode(nkPragma).addChain(ident("threadvar"))),
newPNode(nkPtrTy).addChain(ident("GodotMethodBind"))
))
tree.add(methodBindDecl)
methodBindRegistry.incl(methodBindName)
@ -433,7 +440,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
newCall("getMethod", newCStringLit(meth.typ.godotName),
newCStringLit(meth.godotName))
)
let vars = newNode(nkVarSection)
let vars = newPNode(nkVarSection)
var varargsName = none(string)
var isVarargs: bool
var staticArgsLen: int
@ -448,13 +455,13 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
elif arg.kind == ArgKind.Bound:
let argName = boundArgName(idx)
vars.add(newIdentDefs(
ident(argName), newNode(nkEmpty), arg.makeDefaultValue()))
ident(argName), newPNode(nkEmpty), arg.makeDefaultValue()))
let argsAlloc = newNode(nkCast).addChain(
newNode(nkPtrTy).addChain(
newNode(nkBracketExpr).addChain(
let argsAlloc = newPNode(nkCast).addChain(
newPNode(nkPtrTy).addChain(
newPNode(nkBracketExpr).addChain(
ident("array"), ident("MAX_ARG_COUNT"),
if isVarargs: newNode(nkPtrTy).addChain(ident("GodotVariant"))
if isVarargs: newPNode(nkPtrTy).addChain(ident("GodotVariant"))
else: ident("pointer"))))
staticArgsLen = if varargsName.isNone: meth.args.len
else: meth.args.len - 1
@ -465,24 +472,24 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
newDotExpr(ident(varargsName.get), ident("len"))))
argsAlloc.add(newCall("godotAlloc", newCall("cint", infix(
newCall("sizeof", ident("Variant")), ident("*"),
newNode(nkPar).addChain(argLenNode))))
newPNode(nkPar).addChain(argLenNode))))
)
else:
argLenNode = newCall("cint", newIntLit(staticArgsLen))
vars.add(newIdentDefs(
ident("argsStatic"),
newNode(nkBracketExpr).addChain(
newPNode(nkBracketExpr).addChain(
ident("array"), newIntLit(staticArgsLen), ident("pointer")),
newNode(nkEmpty)))
newPNode(nkEmpty)))
argsAlloc.add(newCommand(ident("addr"), ident("argsStatic")))
vars.add(newIdentDefs(argsName, newNode(nkEmpty), argsAlloc))
vars.add(newIdentDefs(argsName, newPNode(nkEmpty), argsAlloc))
let argConversions = newNode(nkStmtList)
let argConversions = newPNode(nkStmtList)
for idx, arg in meth.args:
var argName = if arg.kind == ArgKind.Bound: ident(boundArgName(idx))
else: ident(arg.name)
if arg.kind == ArgKind.VarArgs:
argName = newNode(nkBracketExpr).addChain(
argName = newPNode(nkBracketExpr).addChain(
ident(varargsName.get),
infix(ident("idx"), ident("-"), newIntLit(staticArgsLen)))
let argIdx = if arg.kind == ArgKind.VarArgs: ident("idx") else: newIntLit(idx)
@ -501,19 +508,19 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
[arg.typ, meth.godotName, meth.typ.godotName])
if not isStandardType and varargsName.isNone:
if arg.typ == "string":
argConversions.add(newNode(nkVarSection).addChain(
argConversions.add(newPNode(nkVarSection).addChain(
newIdentDefs(ident("argToPassToGodot" & $idx), newEmptyNode(),
newCall("toGodotString", argName))))
else:
let objVal = newIfStmt(
prefix("not", newDotExpr(argName, ident"isNil")),
newDotExpr(argName, ident("godotObject"))
).addChain(newNode(nkElse).addChain(newNilLit()))
argConversions.add(newNode(nkLetSection).addChain(
).addChain(newPNode(nkElse).addChain(newNilLit()))
argConversions.add(newPNode(nkLetSection).addChain(
newIdentDefs(ident("argToPassToGodot" & $idx), newEmptyNode(), objVal)))
let argAsgn = newNode(nkAsgn).addChain(
newNode(nkBracketExpr).addChain(
newNode(nkBracketExpr).addChain(argsName), argIdx),
let argAsgn = newPNode(nkAsgn).addChain(
newPNode(nkBracketExpr).addChain(
newPNode(nkBracketExpr).addChain(argsName), argIdx),
convArg
)
if arg.kind != ArgKind.VarArgs:
@ -521,14 +528,14 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
argAsgn
)
else:
argConversions.add(newNode(nkVarSection).addChain(
newIdentDefs(ident("idx"), newNode(nkEmpty),
argConversions.add(newPNode(nkVarSection).addChain(
newIdentDefs(ident("idx"), newPNode(nkEmpty),
newIntLit(staticArgsLen))))
let argLoop = newNode(nkWhileStmt)
let argLoop = newPNode(nkWhileStmt)
argConversions.add(argLoop)
argLoop.add(infix(ident("idx"), ident("<"), argLenNode)
)
argLoop.add(newNode(nkStmtList).addChain(
argLoop.add(newPNode(nkStmtList).addChain(
argAsgn,
newCommand(ident("inc"), ident("idx"))))
@ -537,26 +544,26 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
newDotExpr(ident(methodBindName),
ident(if isVarargs: "call" else: "ptrCall")),
newDotExpr(ident("self"), ident("godotObject")),
if meth.args.len > 0: argsName else: newNode(nkNilLit),
if meth.args.len > 0: argsName else: newPNode(nkNilLit),
argLenNode,
if not isVarargs: ident(retName) else: ident("callError")
)
if not isVarargs:
theCall.sons.delete(3)
let freeCall = newCall("godotFree", argsName)
body = newNode(nkStmtList)
body = newPNode(nkStmtList)
if meth.typ.isSingleton:
let varName = singletonName(meth.typ.name)
body.add(newNilCheck(varName, newCall(
newBracketExpr(ident("getSingleton"), ident(meth.typ.name)))))
body.add(newNode(nkLetSection).addChain(newIdentDefs(
ident("self"), newNode(nkEmpty), varName
body.add(newPNode(nkLetSection).addChain(newIdentDefs(
ident("self"), newPNode(nkEmpty), varName
)))
body.add(nilCheck)
body.add(vars)
body.add(argConversions)
if not isVarargs:
let retPtrDecl = newNode(nkVarSection).addChain(
let retPtrDecl = newPNode(nkVarSection).addChain(
newIdentDefs(ident(retName), ident("pointer"), newEmptyNode())
)
body.add(retPtrDecl)
@ -571,43 +578,43 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
var addrToAssign = newCall("addr", retValIdent)
if returnType in smallIntTypes:
isConversionRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs(
body.add(newPNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("int64"),
)))
elif returnType in float32Types:
isConversionRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs(
body.add(newPNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("float64"),
)))
elif returnType in wrapperTypes:
isWrapperRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs(
body.add(newPNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("Godot" & returnType),
)))
elif returnType in standardTypes:
addrToAssign = newCall("addr", ident("result"))
elif returnType == "string":
isStringRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs(
body.add(newPNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("GodotString"),
)))
elif returnType != "void":
isObjRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs(
retValIdent, newNode(nkPtrTy).addChain(ident("GodotObject")),
body.add(newPNode(nkVarSection).addChain(newIdentDefs(
retValIdent, newPNode(nkPtrTy).addChain(ident("GodotObject")),
)))
body.add(newNode(nkAsgn).addChain(ident(retName), addrToAssign))
body.add(newPNode(nkAsgn).addChain(ident(retName), addrToAssign))
if not isVarargs:
body.add(theCall)
else:
if meth.returnType.isSome:
isVariantRet = true
let callStmt = newNode(nkLetSection).addChain(
let callStmt = newPNode(nkLetSection).addChain(
newIdentDefs(
newNode(nkPragmaExpr).addChain(
ident(retName), newNode(nkPragma).addChain(ident("used"))),
newNode(nkEmpty), theCall))
newPNode(nkPragmaExpr).addChain(
ident(retName), newPNode(nkPragma).addChain(ident("used"))),
newPNode(nkEmpty), theCall))
body.add(callStmt)
if varargsName.isNone:
@ -621,42 +628,42 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
let errCheck = newIfStmt(
infix(newDotExpr(ident("callError"), ident("error")), ident("!="),
newDotExpr(ident("VariantCallErrorType"), ident("OK"))),
newNode(nkRaiseStmt).addChain(
newPNode(nkRaiseStmt).addChain(
newCall("newCallError", ident("callError")))
)
body.add(errCheck)
if isVariantRet:
let convErrDef = newNode(nkLetSection).addChain(
newIdentDefs(ident("convErr"), newNode(nkEmpty),
let convErrDef = newPNode(nkLetSection).addChain(
newIdentDefs(ident("convErr"), newPNode(nkEmpty),
newCall("fromVariant", ident("result"),
newCall("newVariant", retValIdent))))
let convCheck = newIfStmt(
infix(ident("convErr"), ident("!="),
newDotExpr(ident("ConversionResult"), ident("OK"))),
newNode(nkRaiseStmt).addChain(
newPNode(nkRaiseStmt).addChain(
newCall("newConversionError", ident("convErr")))
)
body.add(convErrDef)
body.add(convCheck)
if isStringRet:
body.add(newNode(nkAsgn).addChain(
body.add(newPNode(nkAsgn).addChain(
ident("result"), prefix("$", retValIdent)))
body.add(newCall("deinit", retValIdent))
elif isConversionRet:
body.add(newNode(nkAsgn).addChain(
body.add(newPNode(nkAsgn).addChain(
ident("result"),
newCall(meth.returnType.get, retValIdent)))
elif isWrapperRet:
body.add(newNode(nkAsgn).addChain(
body.add(newPNode(nkAsgn).addChain(
ident("result"),
newCall("new" & meth.returnType.get, retValIdent)))
elif isObjRet:
body.add(newNode(nkAsgn).addChain(ident("result"),
body.add(newPNode(nkAsgn).addChain(ident("result"),
newCall(newBracketExpr(ident("asNimGodotObject"),
newCall("type", ident("result"))),
retValIdent, ident("false"), ident("true"))))
elif isStringRet:
body.add(newNode(nkAsgn).addChain(ident("result"),
body.add(newPNode(nkAsgn).addChain(ident("result"),
newCall("$", retValIdent)))
let procType = if meth.isVirtual: nkMethodDef
@ -665,7 +672,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
if meth.returnType.isSome:
params.add(ident(meth.returnType.get))
else:
params.add(newNode(nkEmpty))
params.add(newPNode(nkEmpty))
if not meth.typ.isSingleton:
params.add(newIdentDefs(ident("self"), ident(toNimType(meth.typ.name))))
@ -676,7 +683,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
params.add(newIdentDefs(ident(arg.name), ident(arg.typ), defaultValue))
of ArgKind.VarArgs:
params.add(newIdentDefs(ident(arg.name),
newNode(nkBracketExpr).addChain(ident("varargs"), ident(arg.typ))))
newPNode(nkBracketExpr).addChain(ident("varargs"), ident(arg.typ))))
of ArgKind.Bound:
discard
@ -684,9 +691,9 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
else: meth.name,
params, body, procType)
if not withImplementation:
let pragma = newNode(nkPragma)
let pragma = newPNode(nkPragma)
pragma.add(ident("gcsafe"))
pragma.add(newNode(nkExprColonExpr).addChain(ident("locks"),
pragma.add(newPNode(nkExprColonExpr).addChain(ident("locks"),
newIntLit(0)))
if meth.isVirtual and meth.isBase and meth.typ.name != "PhysicsBody":
# Nim doesn't like `base` on PhysicsBody methods - wtf
@ -738,7 +745,7 @@ proc getMethodInfo(methodObj: JsonNode, types: Table[string, GodotType],
let returnType = if methodObj["return_type"].str != "void":
some(toNimType(types, methodObj["return_type"].str))
else: none(string)
const discardableMethods = toSet(["emit_signal"])
const discardableMethods = toHashSet(["emit_signal"])
result = MethodInfo(
name: ident(nimName),
typ: typ,
@ -767,7 +774,7 @@ proc makeProperty(types: Table[string, GodotType], tree: PNode,
return
let getterNameStr = toNimStyle(propertyObj["name"].str)
let getterName = ident(getterNameStr)
let setterName = newNode(nkAccQuoted).addChain(ident(getterNameStr & "="))
let setterName = newPNode(nkAccQuoted).addChain(ident(getterNameStr & "="))
let getter = findMethod(obj, propertyObj["getter"].str)
let nimType = if getter.isNil: toNimType(types, propertyObj["type"].str)
@ -853,10 +860,10 @@ proc newRegisterClassNode(typ: GodotType): PNode =
)
proc genSingletonDecl(typ: string): PNode =
result = newNode(nkVarSection)
result = newPNode(nkVarSection)
let name = singletonName(typ)
let threadvar = newNode(nkPragma).addChain(ident("threadvar"))
result.add(newIdentDefs(newNode(nkPragmaExpr).addChain(name, threadvar),
let threadvar = newPNode(nkPragma).addChain(ident("threadvar"))
result.add(newIdentDefs(newPNode(nkPragmaExpr).addChain(name, threadvar),
ident(typ)))
proc shouldExport(typ: GodotType, types: Table[string, GodotType]): bool =
@ -873,9 +880,9 @@ proc sortByDerivedCount(types: Table[string, GodotType]): seq[GodotType] =
proc genTypeFile(types: Table[string, GodotType], targetDir: string) =
let sortedTypes = sortByDerivedCount(types)
let godotApiTypesTree = newNode(nkStmtList)
godotApiTypesTree.add(newNode(nkImportStmt).addChain(ident("godot")))
let typeSection = newNode(nkTypeSection)
let godotApiTypesTree = newPNode(nkStmtList)
godotApiTypesTree.add(newPNode(nkImportStmt).addChain(ident("godot")))
let typeSection = newPNode(nkTypeSection)
godotApiTypesTree.add(typeSection)
for typ in sortedTypes:
@ -897,10 +904,10 @@ proc genSingletonWithDerived(tree: PNode, typ: GodotType,
types: Table[string, GodotType]) =
let sortedTypes = sortByDerivedCount(types)
var parents = initSet[string]()
var parents = initHashSet[string]()
parents.incl(typ.name)
let typeDecl = newNode(nkTypeSection)
let typeDecl = newPNode(nkTypeSection)
tree.add(typeDecl)
proc genDecl(typ: GodotType) =
newRefTypeNode(typeDecl, typ.name, typ.baseName, typ.doc,
@ -950,17 +957,17 @@ proc genApi*(targetDir: string, apiJsonFile: string) =
for typ in types.values():
let moduleName = typeNameToModuleName(typ.name)
echo "Generating ", moduleName, ".nim..."
let tree = newNode(nkStmtList)
let importStmt = newNode(nkImportStmt)
let tree = newPNode(nkStmtList)
let importStmt = newPNode(nkImportStmt)
importStmt.add(ident("godot"))
importStmt.add(ident("godottypes"))
importStmt.add(ident("godotinternal"))
tree.add(importStmt)
let exportStmt = newNode(nkExportStmt)
let exportStmt = newPNode(nkExportStmt)
exportStmt.add(ident("godottypes"))
tree.add(exportStmt)
var methodBindRegsitry = initSet[string]()
var methodBindRegsitry = initHashSet[string]()
let obj = typ.jsonNode
if typ.baseName != "NimGodotObject":
let baseModule = typeNameToModuleName(typ.baseName)
@ -1021,7 +1028,6 @@ when isMainModule:
import os
const usage = """Tool for wrapping Godot API into Nim
godotapigen [godot binary path] [target directory]"""
proc main() =
@ -1052,4 +1058,4 @@ when isMainModule:
genApi(targetDir, jsonFile)
main()
main()

View file

@ -1,8 +1,8 @@
# Copyright 2018 Xored Software, Inc.
import internal.godotinternaltypes, internal.godotarrays,
internal.godotnodepaths, internal.godotpoolarrays, internal.godotstrings,
internal.godotvariants, internal.godotdictionaries
import internal/godotinternaltypes, internal/godotarrays,
internal/godotnodepaths, internal/godotpoolarrays, internal/godotstrings,
internal/godotvariants, internal/godotdictionaries
import gdnativeapi
export godotinternaltypes, godotarrays, godotnodepaths, godotpoolarrays,

View file

@ -1,6 +1,6 @@
# Copyright (c) 2018 Xored Software, Inc.
import godotinternaltypes, gdnativeapi, core.godotcoretypes
import godotinternaltypes, gdnativeapi, core/godotcoretypes
proc len*(self: GodotArray): cint {.inline.} =
getGDNativeAPI().arraySize(self)

View file

@ -1,7 +1,7 @@
# Copyright (c) 2018 Xored Software, Inc.
import godotinternaltypes, gdnativeapi
import core.godotcoretypes
import core/godotcoretypes
template genPoolArrayAPI(ArrayT, initIdent, DataT,
newProc, newCopyProc, newWithArrayProc, appendProc,

View file

@ -1,6 +1,6 @@
# Copyright 2018 Xored Software, Inc.
import core.godotcoretypes, godotinternaltypes, gdnativeapi
import core/godotcoretypes, godotinternaltypes, gdnativeapi
proc getType*(p: GodotVariant): VariantType {.inline.} =
getGDNativeAPI().variantGetType(p)

View file

@ -1,8 +1,8 @@
# Copyright 2018 Xored Software, Inc.
import macros, tables, typetraits, strutils, sets, sequtils, options
import godotinternal, internal.godotvariants
import godotnim, core.variants
import macros, tables, typetraits, strutils, sets, sequtils, options, algorithm
import godotinternal, internal/godotvariants
import godotnim, core/variants
type
VarDecl = ref object
@ -51,15 +51,15 @@ template parseError(node: NimNode, msg: string) =
proc extractNames(definition: NimNode):
tuple[name, parentName: string] =
if definition.kind == nnkIdent:
result.name = $(definition.ident)
result.name = definition.strVal
else:
if not (definition.kind == nnkInfix and
definition[0].ident == toNimIdent("of")):
definition[0].strVal == "of"):
parseError(definition, "invalid type definition")
result.name = $(definition[1].ident)
result.name = definition[1].strVal
case definition[2].kind:
of nnkIdent:
result.parentName = $definition[2].ident
result.parentName = definition[2].strVal
else:
parseError(definition[2], "parent type expected")
@ -72,13 +72,13 @@ proc newCStringLit(s: string): NimNode {.compileTime.} =
newNimNode(nnkCallStrLit).add(ident("cstring"), newRStrLit(s))
iterator pragmas(node: NimNode):
tuple[key: NimIdent, value: NimNode, index: int] =
tuple[key: string, value: NimNode, index: int] =
assert node.kind in {nnkPragma, nnkEmpty}
for index in countdown(node.len - 1, 0):
if node[index].kind == nnkExprColonExpr:
yield (node[index][0].ident, node[index][1], index)
yield (node[index][0].strVal, node[index][1], index)
elif node[index].kind == nnkIdent:
yield (node[index].ident, nil, index)
yield (node[index].strVal, nil, index)
proc removePragmaNode(statement: NimNode,
pname: string): NimNode {.compileTime.} =
@ -91,9 +91,8 @@ proc removePragmaNode(statement: NimNode,
result = nil
var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma()
else: statement[1]
let pnameIdent = toNimIdent(pname)
for ident, val, i in pragmas(pragmas):
if ident == pnameIdent:
if ident == pname:
pragmas.del(i)
return val
@ -104,9 +103,8 @@ proc removePragma(statement: NimNode, pname: string): bool =
return false
var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma()
else: statement[1]
let pnameIdent = toNimIdent(pname)
for ident, val, i in pragmas(pragmas):
if ident == pnameIdent:
if ident == pname:
pragmas.del(i)
return true
@ -178,8 +176,9 @@ proc parseVarSection(decl: NimNode): seq[VarDecl] =
else:
result.add(identDefsToVarDecls(decl[i]))
proc parseType(definition, callSite: NimNode): ObjectDecl =
let body = callSite[^1]
proc parseType(ast: NimNode): ObjectDecl =
let definition = ast[0]
let body = ast[^1]
result = ObjectDecl(
fields: newSeq[VarDecl](),
methods: newSeq[MethodDecl]()
@ -187,11 +186,11 @@ proc parseType(definition, callSite: NimNode): ObjectDecl =
(result.name, result.parentName) = extractNames(definition)
var isTool = false
for i in 2..(callSite.len - 2):
let option = callSite[i]
for i in 1..(ast.len - 2):
let option = ast[i]
if option.kind != nnkIdent:
parseError(option, "type specifier expected")
if option.ident == toNimIdent("tool"):
if option.strVal == "tool":
isTool = true
else:
parseError(option, "valid type specifier expected")
@ -214,7 +213,7 @@ proc parseType(definition, callSite: NimNode): ObjectDecl =
macro invokeVarArgs(procIdent, objIdent;
minArgs, maxArgs: static[int], numArgsIdent,
argSeqIdent; argTypes: seq[NimNode],
hasReturnValue, isStaticCall: static[bool]): typed =
hasReturnValue, isStaticCall: static[bool]): untyped =
## Produces statement in form:
##
## .. code-block:: nim
@ -287,7 +286,7 @@ macro invokeVarArgs(procIdent, objIdent;
" arguments, but got " & $numArgs)
result.add(newNimNode(nnkElse).add(getAst(
printInvokeErr($procIdent.ident, minArgs, maxArgs, numArgsIdent))))
printInvokeErr(procIdent.strVal, minArgs, maxArgs, numArgsIdent))))
proc typeError(nimType: string, value: string, godotType: VariantType,
className: cstring, propertyName: cstring): string =
@ -433,6 +432,73 @@ proc toGodotStyle(s: string): string {.compileTime.} =
else:
result.add(c)
proc checkReplaceSelfVar(node: NimNode, childIndex: int, varsList, propsList: seq[string]) {.compileTime.} =
let identName = node[childIndex].strVal
if varsList.binarySearch(identName) == -1 and propsList.binarySearch(identName) != -1:
var newChild = newDotExpr(ident("self"), node[childIndex])
node.del childIndex
node.insert(childIndex, newChild)
proc checkReplaceSelfMethod(node: NimNode, childIndex: int, methodsList: seq[string]) {.compileTime.} =
if methodsList.binarySearch(node[childIndex].strVal) != -1:
var newChild = newDotExpr(ident("self"), node[childIndex])
node.del childIndex
node.insert(childIndex, newChild)
proc applySelf(node: NimNode, varsList: ref seq[string], propsList, methodsList: seq[string]) {.compileTime.} =
var lowIndx = -1
var highIndx = node.len - 1
var isBlock: bool = false
case node.kind:
of nnkCommand, nnkCall:
if node[0].kind == nnkDotExpr:
lowIndx = 0
elif node[0].kind == nnkIdent:
if node[0].strVal != "procCall":
checkReplaceSelfMethod(node, 0, methodsList)
lowIndx = 1
else:
lowIndx = 1
of nnkInfix..nnkPostfix, nnkExprColonExpr, nnkObjConstr, nnkCast:
lowIndx = 1
of nnkExprEqExpr, nnkPar, nnkCurly..nnkBracketExpr, nnkRange, nnkDerefExpr, nnkIfExpr, nnkTableConstr, nnkAddr, nnkAsgn,
nnkIfStmt, nnkCaseStmt, nnkVarSection, nnkLetSection, nnkConstSection, nnkDefer, nnkRaiseStmt, nnkReturnStmt, nnkStmtList,
nnkStmtListExpr, nnkTupleConstr:
lowIndx = 0
of nnkIdentDefs:
lowIndx = 2
if node[0].kind == nnkIdent:
let index = lowerBound(varsList[], node[0].strVal)
varsList[].insert(node[0].strVal, index)
of nnkVarTuple:
lowIndx = node.len - 1
for i in 0..node.len - 3:
if node[i].kind == nnkIdent:
let index = lowerBound(varsList[], node[i].strVal)
varsList[].insert(node[i].strVal, index)
of nnkDotExpr:
lowIndx = 0
highIndx = 0
of nnkElifExpr, nnkElseExpr, nnkOfBranch..nnkElse, nnkWhenStmt..nnkWhileStmt, nnkTryStmt, nnkFinally, nnkBlockStmt, nnkBlockExpr:
isBlock = true
lowIndx = 0
of nnkConstDef:
if node[0].kind == nnkIdent:
let index = lowerBound(varsList[], node[0].strVal)
varsList[].insert(node[0].strVal, index)
else:
discard
if lowIndx != -1:
var nodeVars = varsList
for i in lowIndx..highIndx:
if isBlock and i == highIndx:
new(nodeVars)
nodeVars[] = varsList[]
if node[i].kind == nnkIdent:
checkReplaceSelfVar(node, i, nodeVars[], propsList)
else:
applySelf(node[i], nodeVars, propsList, methodsList)
proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
result = newNimNode(nnkStmtList)
@ -480,11 +546,6 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
else:
initMethod.body.insert(0, initBody)
# {.this: self.} for convenience
result.add(newNimNode(nnkPragma).add(newNimNode(nnkExprColonExpr).add(
ident("this"), ident("self")
)))
# Nim proc defintions
var decls = newSeqOfCap[NimNode](obj.methods.len)
for meth in obj.methods:
@ -539,6 +600,25 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
genSym(nskProc, "getFunc"),
newStrLitNode(hintStr), hintIdent, usage,
ident($hasDefaultValue), field.defaultValue)))
# Keep track of object's fields and methods (used instead of deprecated this:self pragma)
var propsList: seq[string] = @[]
for field in obj.fields:
let indx = lowerBound(propsList, field.name.strVal)
propsList.insert(field.name.strVal, indx)
var methodsList: seq[string] = @[]
for meth in obj.methods:
let indx = lowerBound(methodsList, meth.name)
methodsList.insert(meth.name, indx)
# Inject self to properties and methods
for meth in obj.methods:
let varsList = new(seq[string])
for v in meth.nimNode[3]:
if v.kind == nnkIdentDefs:
varsList[].add v[0].strVal
applySelf(meth.nimNode[6], varsList, propsList, methodsList)
# Register methods
template registerGodotMethod(classNameLit, classNameIdent, methodNameIdent,
@ -604,7 +684,7 @@ N_NOINLINE(void, nimGC_setStackBottom)(void* thestackbottom);
let hasReturnValueBool = not (meth.returnType.isNil or
meth.returnType.kind == nnkEmpty or
(meth.returnType.kind == nnkIdent and
meth.returnType.ident == toNimIdent("void")))
meth.returnType.strVal == "void"))
let hasReturnValue = if hasReturnValueBool: ident("true")
else: ident("false")
result.add(getAst(
@ -630,11 +710,7 @@ N_NOINLINE(void, nimGC_setStackBottom)(void* thestackbottom);
GodotMethodAttributes(), refDec)
result.add(getAst(registerRefIncDec(classNameLit)))
{.push warning[Deprecated]: off.}
# immediate macros are deprecated, but `untyped` doesn't make it immediate,
# as the warning and the documentation claim.
macro gdobj*(definition: untyped, body: typed): typed {.immediate.} =
macro gdobj*(ast: varargs[untyped]): untyped =
## Generates Godot type. Self-documenting example:
##
## .. code-block:: nim
@ -678,7 +754,7 @@ macro gdobj*(definition: untyped, body: typed): typed {.immediate.} =
## `gdnew <godotnim.html#gdnew>`_ or by using
## `load <godotapi/resource_loader.html#load,string,string,bool>`_ or any other way
## that you can find in `Godot API <index.html#modules-godot-api>`_.
let typeDef = parseType(definition, callsite())
let typeDef = parseType(ast)
result = genType(typeDef)
{.push warning[Deprecated]: on.}

View file

@ -2,13 +2,13 @@
import tables, typetraits, macros, unicode, strutils, sets
import gdnativeapi
import core.godotcoretypes, core.godotbase
import core.vector2, core.rect2,
core.vector3, core.transform2d,
core.planes, core.quats, core.aabb,
core.basis, core.transforms, core.colors,
core.nodepaths, core.rids, core.dictionaries,
core.arrays, core.poolarrays, core.variants
import core/godotcoretypes, core/godotbase
import core/vector2, core/rect2,
core/vector3, core/transform2d,
core/planes, core/quats, core/aabb,
core/basis, core/transforms, core/colors,
core/nodepaths, core/rids, core/dictionaries,
core/arrays, core/poolarrays, core/variants
import godotinternal
## This module defines ``NimGodotObject`` and ``toVariant``/``fromVariant``
@ -343,20 +343,20 @@ proc newRStrLit(s: string): NimNode {.compileTime.} =
result = newNimNode(nnkRStrLit)
result.strVal = s
macro toGodotName(T: typedesc): string =
macro toGodotName(T: typedesc): untyped =
if T is GodotString or T is string:
"String"
newStrLitNode"String"
elif T is SomeFloat:
"float"
newStrLitNode"float"
elif T is SomeUnsignedInt or T is SomeSignedInt:
"int"
newStrLitNode"int"
else:
let nameStr = (($T.getType()[1][1].symbol).split(':')[0])
let nameStr = ((T.getType()[1][1].strVal).split(':')[0])
case nameStr:
of "File", "Directory", "Thread", "Mutex", "Semaphore":
"_" & nameStr
newStrLitNode("_" & nameStr)
else:
nameStr
newStrLitNode(nameStr)
macro asCString(s: static[string]): cstring =
result = newNimNode(nnkCallStrLit).add(

View file

@ -1 +1,2 @@
--path:"$projectdir/../"
--path:"$projectdir/../"
-d:userealtimeGC