attempt to make 0.19 compatible

workaround for nim/macro/typedesc issue

work-around for nim-lang/Nim#7375

fixed more isNil usages

fixed new name of setStackBottom
This commit is contained in:
Fabian Keller 2018-12-30 12:40:10 +01:00 • committed by Ruslan Mustakov
commit 3a935b9308
6 changed files with 94 additions and 100 deletions

View file

@ -71,7 +71,7 @@ proc fixupHrefs(file: string) =
proc getGitHash(): string =
result = execProcess("git rev-parse HEAD")
if not result.isNil and result.len > 0:
if result.len > 0:
result = result.replace("\L", "").replace("\r", "")
proc buildDocs*(outDir, godotNimDir, godotBin: string) =
@ -112,7 +112,7 @@ proc buildDocs*(outDir, godotNimDir, godotBin: string) =
var gitHash: string
withDir(godotBinAbs.parentDir()):
gitHash = getGitHash()
if gitHash.isNil or gitHash.len == 0:
if gitHash.len == 0:
raise newException(Exception,
"Godot executable is not under Git repository")

View file

@ -73,12 +73,9 @@ proc newVariant*(r: cdouble): Variant {.inline.} =
proc newVariant*(s: string): Variant {.inline.} =
new(result, variantFinalizer)
if s.isNil:
initGodotVariant(result.godotVariant)
else:
var godotStr = s.toGodotString()
initGodotVariant(result.godotVariant, godotStr)
godotStr.deinit()
var godotStr = s.toGodotString()
initGodotVariant(result.godotVariant, godotStr)
godotStr.deinit()
import basis, nodepaths
import planes, quats, rect2, aabb, rids

View file

@ -1,9 +1,15 @@
# Copyright 2018 Xored Software, Inc.
import streams, json, os, strutils, times, sets, tables
import streams, json, os, strutils, times, sets, tables, options
import sequtils, algorithm
import compiler.ast, compiler.renderer, compiler.idents, compiler.astalgo
when (NimMajor, NimMinor, NimPatch) >= (0, 19, 0):
var gic* = newIdentCache()
proc getIdent(ident: string): PIdent =
getIdent(gic, ident)
proc ident(ident: string): PNode =
result = newNode(nkIdent)
result.ident = getIdent(ident)
@ -139,19 +145,19 @@ proc findCommonRoot(typeRegistry: Table[string, GodotType],
var idx = 0
while true:
var curType: string
var curType = none(string)
var allEqual = true
for chain in chains:
if idx >= chain.len:
allEqual = false
break
if curType.isNil:
curType = chain[idx]
elif curType != chain[idx]:
if curType.isNone:
curType = some(chain[idx])
elif curType.get != chain[idx]:
allEqual = false
break
if allEqual:
result = curType
result = curType.get
else:
break
inc idx
@ -224,7 +230,7 @@ proc newRefTypeNode(typeSection: PNode, typ, base, doc: string,
inherit.add(ident(base))
objTy.add(inherit)
if not doc.isNil:
if doc.len > 0:
let recList = newNode(nkRecList)
let docNode = newNode(nkCommentStmt)
docNode.comment = doc
@ -275,7 +281,7 @@ type
godotName: string
typ: GodotType
args: seq[MethodArg]
returnType: string
returnType: Option[string]
isVirtual: bool
isBase: bool
isDiscardable: bool
@ -428,7 +434,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
newCStringLit(meth.godotName))
)
let vars = newNode(nkVarSection)
var varargsName: string
var varargsName = none(string)
var isVarargs: bool
var staticArgsLen: int
var argLenNode = newIntLit(0)
@ -436,7 +442,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
if meth.args.len > 0:
for idx, arg in meth.args:
if arg.kind == ArgKind.VarArgs:
varargsName = arg.name
varargsName = some(arg.name)
isVarargs = true
vars.add(newIdentDefs(ident("callError"), ident("VariantCallError")))
elif arg.kind == ArgKind.Bound:
@ -450,13 +456,13 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
ident("array"), ident("MAX_ARG_COUNT"),
if isVarargs: newNode(nkPtrTy).addChain(ident("GodotVariant"))
else: ident("pointer"))))
staticArgsLen = if varargsName.isNil: meth.args.len
staticArgsLen = if varargsName.isSome: meth.args.len
else: meth.args.len - 1
if not varargsName.isNil:
if varargsName.isSome:
argLenNode = newCall("cint",
infix(newIntLit(staticArgsLen),
ident("+"),
newDotExpr(ident(varargsName), ident("len"))))
newDotExpr(ident(varargsName.get), ident("len"))))
argsAlloc.add(newCall("godotAlloc", newCall("cint", infix(
newCall("sizeof", ident("Variant")), ident("*"),
newNode(nkPar).addChain(argLenNode))))
@ -477,12 +483,12 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
else: ident(arg.name)
if arg.kind == ArgKind.VarArgs:
argName = newNode(nkBracketExpr).addChain(
ident(varargsName),
ident(varargsName.get),
infix(ident("idx"), ident("-"), newIntLit(staticArgsLen)))
let argIdx = if arg.kind == ArgKind.VarArgs: ident("idx") else: newIntLit(idx)
let isStandardType = arg.typ in standardTypes
let isWrappedType = arg.typ in wrapperTypes
let convArg = if not varargsName.isNil:
let convArg = if varargsName.isSome:
getInternalPtr(newCall("toVariant", argName), "Variant")
elif isWrappedType: getInternalPtr(argName, arg.typ)
elif isStandardType: newCall("unsafeAddr", argName)
@ -493,7 +499,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
raise newException(ValueError,
"Non-standard type $# for varargs params of method $# of type $#" %
[arg.typ, meth.godotName, meth.typ.godotName])
if not isStandardType and varargsName.isNil:
if not isStandardType and varargsName.isNone:
if arg.typ == "string":
argConversions.add(newNode(nkVarSection).addChain(
newIdentDefs(ident("argToPassToGodot" & $idx), newEmptyNode(),
@ -560,31 +566,32 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
var isStringRet: bool
var isWrapperRet: bool
let retValIdent = if not isVarargs: ident("ptrCallVal") else: ident(retName)
if not meth.returnType.isNil and not isVarargs:
if meth.returnType.isSome and not isVarargs:
let returnType = meth.returnType.get
var addrToAssign = newCall("addr", retValIdent)
if meth.returnType in smallIntTypes:
if returnType in smallIntTypes:
isConversionRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("int64"),
)))
elif meth.returnType in float32Types:
elif returnType in float32Types:
isConversionRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("float64"),
)))
elif meth.returnType in wrapperTypes:
elif returnType in wrapperTypes:
isWrapperRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("Godot" & meth.returnType),
retValIdent, ident("Godot" & returnType),
)))
elif meth.returnType in standardTypes:
elif returnType in standardTypes:
addrToAssign = newCall("addr", ident("result"))
elif meth.returnType == "string":
elif returnType == "string":
isStringRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("GodotString"),
)))
elif meth.returnType != "void":
elif returnType != "void":
isObjRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs(
retValIdent, newNode(nkPtrTy).addChain(ident("GodotObject")),
@ -594,7 +601,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
if not isVarargs:
body.add(theCall)
else:
if not meth.returnType.isNil:
if meth.returnType.isSome:
isVariantRet = true
let callStmt = newNode(nkLetSection).addChain(
newIdentDefs(
@ -603,14 +610,14 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
newNode(nkEmpty), theCall))
body.add(callStmt)
if varargsName.isNil:
if varargsName.isNone:
for idx, arg in meth.args:
if arg.typ == "string":
body.add(newCall("deinit", ident("argToPassToGodot" & $idx)))
if meth.args.len > 0 and not varargsName.isNil:
if meth.args.len > 0 and varargsName.isSome:
body.add(freeCall)
if not varargsName.isNil:
if varargsName.isSome:
let errCheck = newIfStmt(
infix(newDotExpr(ident("callError"), ident("error")), ident("!="),
newDotExpr(ident("VariantCallErrorType"), ident("OK"))),
@ -638,11 +645,11 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
elif isConversionRet:
body.add(newNode(nkAsgn).addChain(
ident("result"),
newCall(meth.returnType, retValIdent)))
newCall(meth.returnType.get, retValIdent)))
elif isWrapperRet:
body.add(newNode(nkAsgn).addChain(
ident("result"),
newCall("new" & meth.returnType, retValIdent)))
newCall("new" & meth.returnType.get, retValIdent)))
elif isObjRet:
body.add(newNode(nkAsgn).addChain(ident("result"),
newCall(newBracketExpr(ident("asNimGodotObject"),
@ -655,8 +662,8 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
let procType = if meth.isVirtual: nkMethodDef
else: nkProcDef
var params = newSeqOfCap[PNode](meth.args.len + 2)
if not meth.returnType.isNil:
params.add(ident(meth.returnType))
if meth.returnType.isSome:
params.add(ident(meth.returnType.get))
else:
params.add(newNode(nkEmpty))
if not meth.typ.isSingleton:
@ -684,7 +691,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
if meth.isVirtual and meth.isBase and meth.typ.name != "PhysicsBody":
# Nim doesn't like `base` on PhysicsBody methods - wtf
pragma.add(ident("base"))
if meth.isDiscardable and not meth.returnType.isNil:
if meth.isDiscardable and meth.returnType.isSome:
pragma.add(ident("discardable"))
procDecl.sons[4] = pragma
tree.add(procDecl)
@ -729,8 +736,8 @@ proc getMethodInfo(methodObj: JsonNode, types: Table[string, GodotType],
nimName = nimName & "Impl"
let returnType = if methodObj["return_type"].str != "void":
toNimType(types, methodObj["return_type"].str)
else: nil
some(toNimType(types, methodObj["return_type"].str))
else: none(string)
const discardableMethods = toSet(["emit_signal"])
result = MethodInfo(
name: ident(nimName),
@ -764,13 +771,13 @@ proc makeProperty(types: Table[string, GodotType], tree: PNode,
let getter = findMethod(obj, propertyObj["getter"].str)
let nimType = if getter.isNil: toNimType(types, propertyObj["type"].str)
else: getMethodInfo(getter, types, typ).returnType
else: getMethodInfo(getter, types, typ).returnType.get("void")
let getterInfo = MethodInfo(
name: getterName,
typ: typ,
godotName: propertyObj["getter"].str,
args: @[],
returnType: nimType
args: newSeq[MethodArg](),
returnType: some(nimType)
)
let setterInfo = MethodInfo(
name: setterName,
@ -779,10 +786,12 @@ proc makeProperty(types: Table[string, GodotType], tree: PNode,
args: @[MethodArg(name: "val", typ: nimType)]
)
if "index" in propertyObj and propertyObj["index"] != newJInt(-1):
getterInfo.args = @[MethodArg(defaultVal: newJString($propertyObj["index"]),
typ: "int", kind: ArgKind.Bound)] & getterInfo.args
setterInfo.args = @[MethodArg(defaultVal: newJString($propertyObj["index"]),
typ: "int", kind: ArgKind.Bound)] & setterInfo.args
getterInfo.args =
@[MethodArg(defaultVal: newJString($propertyObj["index"]),
typ: "int", kind: ArgKind.Bound)] & getterInfo.args
setterInfo.args =
@[MethodArg(defaultVal: newJString($propertyObj["index"]),
typ: "int", kind: ArgKind.Bound)] & setterInfo.args
generateMethod(tree, methodBindRegistry, getterInfo, withImplementation)
generateMethod(tree, methodBindRegistry, setterInfo, withImplementation)
@ -920,7 +929,7 @@ proc genApi*(targetDir: string, apiJsonFile: string) =
let className = godotClassName.replace("_", "")
var baseClassName = obj["base_class"].str
baseClassName = toNimType(baseClassName.replace("_", ""))
if baseClassName.isNil or baseClassName.len == 0:
if baseClassName.len == 0:
baseClassName = "NimGodotObject"
var doc = ""
for attr in classAttributes:

View file

@ -38,10 +38,7 @@ proc `$`*(self: GodotString): string =
proc toGodotString*(s: string): GodotString {.inline.} =
## Converts the Nim string into ``GodotString``
if s.isNil:
initGodotString(result)
else:
initGodotString(result, cstring(s), cint(s.len + 1))
initGodotString(result, cstring(s), cint(s.len + 1))
proc toGodotString*(s: cstring): GodotString {.inline.} =
## Converts the cstring into ``GodotString``

View file

@ -1,6 +1,6 @@
# Copyright 2018 Xored Software, Inc.
import macros, tables, typetraits
import macros, tables, typetraits, strutils, sets, sequtils, options
import godotinternal, internal.godotvariants
import godotnim, core.variants
@ -10,8 +10,8 @@ type
typ: NimNode
defaultValue: NimNode
isNoGodot: bool
hint: string
hintStr: string
hint: Option[string]
hintStr: Option[string]
usage: NimNode
isExported: bool
@ -111,12 +111,12 @@ proc removePragma(statement: NimNode, pname: string): bool =
return true
proc removeStrPragma(statement: NimNode,
pname: string): string {.compileTime.} =
pname: string): Option[string] {.compileTime.} =
## Removes the pragma from the node and returns value of the pragma
## Works for routine nodes or nnkPragmaExpr
let node = removePragmaNode(statement, pname)
result = if node.isNil: nil
else: $node
result = if node.isNil: none(string)
else: some($node)
proc isExported(node: NimNode): bool {.compileTime.} =
if node.kind == nnkPragmaExpr:
@ -197,7 +197,7 @@ proc parseType(definition, callSite: NimNode): ObjectDecl =
parseError(option, "valid type specifier expected")
result.isTool = isTool
if result.parentName.isNil: result.parentName = "Object"
if result.parentName == "": result.parentName = "Object"
for statement in body:
case statement.kind:
of nnkVarSection:
@ -424,9 +424,6 @@ template registerGodotField(classNameLit, classNameIdent, propNameLit,
unsafeAddr attr, setFunc, getFunc)
hintStrGodot.deinit()
static:
import strutils, sets, sequtils
proc toGodotStyle(s: string): string {.compileTime.} =
result = newStringOfCap(s.len + 10)
for c in s:
@ -447,7 +444,7 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
let objTy = newNimNode(nnkObjectTy)
typeDef.add(newNimNode(nnkRefTy).add(objTy))
objTy.add(newEmptyNode())
if obj.parentName.isNil:
if obj.parentName == "":
objTy.add(newEmptyNode())
else:
objTy.add(newNimNode(nnkOfInherit).add(ident(obj.parentName)))
@ -506,23 +503,25 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
result.add(meth.nimNode)
# Register Godot object
let parentName = if obj.parentName.isNil: newStrLitNode("Object")
let parentName = if obj.parentName == "": newStrLitNode("Object")
else: newStrLitNode(obj.parentName)
let classNameLit = newStrLitNode(obj.name)
let classNameIdent = ident(obj.name)
let isRef: bool = if obj.parentName.isNil: false
let isRef: bool = if obj.parentName == "": false
else: obj.parentName in refClasses
# Wrapping bools with a newLit is required as a temporary workaround for
# https://github.com/nim-lang/Nim/issues/7375
result.add(getAst(
registerGodotClass(classNameIdent, classNameLit, isRef, parentName,
genSym(nskProc, "createFunc"), obj.isTool)))
registerGodotClass(classNameIdent, classNameLit, newLit(isRef), parentName,
genSym(nskProc, "createFunc"), newLit(obj.isTool))))
# Register fields (properties)
for field in obj.fields:
if field.isNoGodot: continue
let hintStr = if field.hintStr.isNil: "NIM"
else: field.hintStr
let hint = if field.hint.isNil: "NIM"
else: field.hint
let hintStr = if field.hintStr.isNone: "NIM"
else: field.hintStr.get
let hint = if field.hint.isNone: "NIM"
else: field.hint.get
let usage =
if field.usage.isNil:
newLit(ord(GodotPropertyUsage.Default) or
@ -546,7 +545,7 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
methodNameLit, minArgs, maxArgs,
argTypes, methFuncIdent, hasReturnValue) =
{.emit: """/*TYPESECTION*/
N_NOINLINE(void, setStackBottom)(void* thestackbottom);
N_NOINLINE(void, nimGC_setStackBottom)(void* thestackbottom);
""".}
proc methFuncIdent(obj: ptr GodotObject, methodData: pointer,
userData: pointer, numArgs: cint,
@ -554,7 +553,7 @@ N_NOINLINE(void, setStackBottom)(void* thestackbottom);
GodotVariant {.noconv.} =
var stackBottom {.volatile.}: pointer
{.emit: """
setStackBottom((void*)(&`stackBottom`));
nimGC_setStackBottom((void*)(&`stackBottom`));
""".}
let self = cast[classNameIdent](userData)
const isStaticCall = methodNameLit == cstring"_ready" or

View file

@ -1,6 +1,6 @@
# Copyright 2018 Xored Software, Inc.
import tables, typetraits, macros, unicode
import tables, typetraits, macros, unicode, strutils, sets
import gdnativeapi
import core.godotcoretypes, core.godotbase
import core.vector2, core.rect2,
@ -101,8 +101,6 @@ var classRegistryStatic* {.compileTime.}: TableRef[FNV1Hash, ObjectInfo]
static:
classRegistryStatic = newTable[FNV1Hash, ObjectInfo]()
static:
import sets, strutils
var nativeClasses {.compileTime.} = newSeq[string]()
var refClasses* {.compileTime.} = newSeq[string]()
@ -204,7 +202,7 @@ macro baseNativeType(T: typedesc): cstring =
if typeName == "NimGodotObject":
break
t = getType(t[1][1])
if baseT.isNil:
if baseT == "":
result = newNilLit()
else:
let rStr = newNimNode(nnkRStrLit)
@ -345,26 +343,20 @@ proc newRStrLit(s: string): NimNode {.compileTime.} =
result = newNimNode(nnkRStrLit)
result.strVal = s
static:
import strutils
macro toGodotName(T: typedesc): string =
var godotName: string
proc toGodotName(T: typedesc): string =
if T is GodotString or T is string:
godotName = "String"
"String"
elif T is SomeFloat:
godotName = "float"
"float"
elif T is SomeUnsignedInt or T is SomeSignedInt:
godotName = "int"
if godotName.isNil or godotName.len == 0:
"int"
else:
let nameStr = (($T.getType()[1][1].symbol).split(':')[0])
godotName = case nameStr:
of "File", "Directory", "Thread", "Mutex", "Semaphore":
"_" & nameStr
else:
nameStr
result = newLit(godotName)
case nameStr:
of "File", "Directory", "Thread", "Mutex", "Semaphore":
"_" & nameStr
else:
nameStr
macro asCString(s: static[string]): cstring =
result = newNimNode(nnkCallStrLit).add(
@ -717,7 +709,7 @@ proc fromVariant*(s: var string, val: Variant): ConversionResult =
if val.getType() == VariantType.String:
s = val.asString()
elif val.getType() == VariantType.Nil:
s = nil
s = ""
else:
result = ConversionResult.TypeError
@ -839,7 +831,7 @@ proc fromVariant*[T: Table or TableRef or OrderedTable or OrderedTableRef](t: va
{.emit: """/*TYPESECTION*/
N_LIB_EXPORT N_CDECL(void, NimMain)(void);
N_NOINLINE(void, setStackBottom)(void* thestackbottom);
N_NOINLINE(void, nimGC_setStackBottom)(void* thestackbottom);
""".}
var nativeLibHandle: pointer
@ -855,7 +847,7 @@ proc godot_nativescript_init(handle: pointer) {.
var stackBottom {.volatile.}: pointer
{.emit: """
NimMain();
setStackBottom((void*)(&`stackBottom`));
nimGC_setStackBottom((void*)(&`stackBottom`));
""".}
GC_fullCollect()
GC_disable()
@ -893,7 +885,7 @@ proc registerFrameCallback*(cb: proc () {.closure.}) =
proc godot_nativescript_frame() {.cdecl, exportc, dynlib.} =
var stackBottom {.volatile.}: pointer
{.emit: """
setStackBottom((void*)(&`stackBottom`));
nimGC_setStackBottom((void*)(&`stackBottom`));
""".}
for cb in idleCallbacks:
cb()