From db4bb91765b5502d9f660eaef8c59583c6b3756f Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Tue, 9 Jul 2019 13:48:54 +0700 Subject: [PATCH 01/24] Fix editor crash in multithreaded mode --- godot.nimble | 2 +- godot/nim/godotnim.nim | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/godot.nimble b/godot.nimble index 8e4c8c0..6964c83 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.18" +version = "0.7.19" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index 665b715..979613f 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -867,7 +867,8 @@ proc godot_gdnative_init(options: ptr GDNativeInitOptions) {. proc godot_gdnative_terminate(options: ptr GDNativeTerminateOptions) {. cdecl, exportc, dynlib.} = - deallocHeap(runFinalizers = not options[].inEditor, allowGcAfterwards = false) + if not options[].inEditor or not compileOption("threads"): + deallocHeap(runFinalizers = not options[].inEditor, allowGcAfterwards = false) const nimGcStepLengthUs {.intdefine.} = 2000 From f45281f5a0cdb9e1de482a047aa49156fbc8f92f Mon Sep 17 00:00:00 2001 From: Konstantin Zaitsev Date: Thu, 12 Sep 2019 14:50:02 +0700 Subject: [PATCH 02/24] Fix possible double free memory on exit --- godot.nimble | 2 +- godot/nim/godotnim.nim | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/godot.nimble b/godot.nimble index 6964c83..66794fc 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.19" +version = "0.7.20" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index 979613f..d3fa9cf 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -189,8 +189,8 @@ proc nimGodotObjectFinalizer*[T: NimGodotObject](obj: T) = if obj.godotObject.isNil or obj.isNative: return # important to set it before so that ``unreference`` is aware obj.isFinalized = true - if obj.isRef and obj.godotObject.unreference() or - not obj.linkedObject.isNil: + if (obj.isRef or not obj.linkedObject.isNil and obj.linkedObject.isRef) and + obj.godotObject.unreference(): obj.deinit() macro baseNativeType(T: typedesc): cstring = From 3a935b93087682867f9e5278fbd32c781bbda923 Mon Sep 17 00:00:00 2001 From: Fabian Keller Date: Sun, 30 Dec 2018 12:40:10 +0100 Subject: [PATCH 03/24] 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 --- docs/docbuild.nim | 4 +- godot/core/variants.nim | 9 ++-- godot/godotapigen.nim | 95 ++++++++++++++++++--------------- godot/internal/godotstrings.nim | 5 +- godot/nim/godotmacros.nim | 41 +++++++------- godot/nim/godotnim.nim | 40 ++++++-------- 6 files changed, 94 insertions(+), 100 deletions(-) diff --git a/docs/docbuild.nim b/docs/docbuild.nim index 10823a5..477c45b 100644 --- a/docs/docbuild.nim +++ b/docs/docbuild.nim @@ -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") diff --git a/godot/core/variants.nim b/godot/core/variants.nim index ace8aac..8c2488d 100644 --- a/godot/core/variants.nim +++ b/godot/core/variants.nim @@ -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 diff --git a/godot/godotapigen.nim b/godot/godotapigen.nim index 876e770..5ec1c73 100644 --- a/godot/godotapigen.nim +++ b/godot/godotapigen.nim @@ -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: diff --git a/godot/internal/godotstrings.nim b/godot/internal/godotstrings.nim index be18df0..18bcf63 100644 --- a/godot/internal/godotstrings.nim +++ b/godot/internal/godotstrings.nim @@ -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`` diff --git a/godot/nim/godotmacros.nim b/godot/nim/godotmacros.nim index 352925a..052b2fc 100644 --- a/godot/nim/godotmacros.nim +++ b/godot/nim/godotmacros.nim @@ -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 diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index d3fa9cf..41ef51e 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -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() From 34fda99def2cdae837b4bccc153c17e9a86de98e Mon Sep 17 00:00:00 2001 From: zetashift Date: Fri, 1 Mar 2019 02:18:00 +0100 Subject: [PATCH 04/24] Small changes to add 0.18.0 compatibility Change toGodotName back to macro because that got fixed in devel change isSome to isNone in godotapigen --- godot/godotapigen.nim | 2 +- godot/nim/godotmacros.nim | 16 +++++++++++----- godot/nim/godotnim.nim | 30 +++++++++++++++++++++--------- 3 files changed, 33 insertions(+), 15 deletions(-) diff --git a/godot/godotapigen.nim b/godot/godotapigen.nim index 5ec1c73..71a52ff 100644 --- a/godot/godotapigen.nim +++ b/godot/godotapigen.nim @@ -456,7 +456,7 @@ 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.isSome: meth.args.len + staticArgsLen = if varargsName.isNone: meth.args.len else: meth.args.len - 1 if varargsName.isSome: argLenNode = newCall("cint", diff --git a/godot/nim/godotmacros.nim b/godot/nim/godotmacros.nim index 052b2fc..4389859 100644 --- a/godot/nim/godotmacros.nim +++ b/godot/nim/godotmacros.nim @@ -197,7 +197,7 @@ proc parseType(definition, callSite: NimNode): ObjectDecl = parseError(option, "valid type specifier expected") result.isTool = isTool - if result.parentName == "": result.parentName = "Object" + if result.parentName.len == 0: result.parentName = "Object" for statement in body: case statement.kind: of nnkVarSection: @@ -444,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 == "": + if obj.parentName.len == 0: objTy.add(newEmptyNode()) else: objTy.add(newNimNode(nnkOfInherit).add(ident(obj.parentName))) @@ -503,11 +503,11 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} = result.add(meth.nimNode) # Register Godot object - let parentName = if obj.parentName == "": newStrLitNode("Object") + let parentName = if obj.parentName.len == 0: newStrLitNode("Object") else: newStrLitNode(obj.parentName) let classNameLit = newStrLitNode(obj.name) let classNameIdent = ident(obj.name) - let isRef: bool = if obj.parentName == "": false + let isRef: bool = if obj.parentName.len == 0: 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 @@ -544,9 +544,15 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} = template registerGodotMethod(classNameLit, classNameIdent, methodNameIdent, methodNameLit, minArgs, maxArgs, argTypes, methFuncIdent, hasReturnValue) = - {.emit: """/*TYPESECTION*/ + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): + {.emit: """/*TYPESECTION*/ +N_NOINLINE(void, setStackBottom)(void* thestackbottom); +""".} + else: + {.emit: """ N_NOINLINE(void, nimGC_setStackBottom)(void* thestackbottom); """.} + proc methFuncIdent(obj: ptr GodotObject, methodData: pointer, userData: pointer, numArgs: cint, args: var array[MAX_ARG_COUNT, ptr GodotVariant]): diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index 41ef51e..e58c330 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -202,7 +202,7 @@ macro baseNativeType(T: typedesc): cstring = if typeName == "NimGodotObject": break t = getType(t[1][1]) - if baseT == "": + if baseT.len == 0: result = newNilLit() else: let rStr = newNimNode(nnkRStrLit) @@ -343,7 +343,7 @@ proc newRStrLit(s: string): NimNode {.compileTime.} = result = newNimNode(nnkRStrLit) result.strVal = s -proc toGodotName(T: typedesc): string = +macro toGodotName(T: typedesc): string = if T is GodotString or T is string: "String" elif T is SomeFloat: @@ -708,10 +708,16 @@ proc toVariant*(s: string): Variant {.inline.} = proc fromVariant*(s: var string, val: Variant): ConversionResult = if val.getType() == VariantType.String: s = val.asString() - elif val.getType() == VariantType.Nil: - s = "" + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): + if val.getType() == VariantType.Nil: + s = nil + else: + result = ConversionResult.TypeError else: - result = ConversionResult.TypeError + if val.getType() == VariantType.Nil: + s = "" + else: + result = ConversionResult.TypeError template arrTypeInfo(T) = result.variantType = VariantType.Array @@ -829,10 +835,16 @@ proc fromVariant*[T: Table or TableRef or OrderedTable or OrderedTableRef](t: va else: result = ConversionResult.TypeError -{.emit: """/*TYPESECTION*/ -N_LIB_EXPORT N_CDECL(void, NimMain)(void); -N_NOINLINE(void, nimGC_setStackBottom)(void* thestackbottom); -""".} +when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): + {.emit: """/*TYPESECTION*/ + N_LIB_EXPORT N_CDECL(void, NimMain)(void); + N_NOINLINE(void, setStackBottom)(void* thestackbottom); + """.} +else: + {.emit: """/*TYPESECTION*/ + N_LIB_EXPORT N_CDECL(void, NimMain)(void); + N_NOINLINE(void, nimGC_setStackBottom)(void* thestackbottom); + """.} var nativeLibHandle: pointer proc getNativeLibHandle*(): pointer = From 0fecfdb3b85922f7a0be0e132be48ca430ba0ad1 Mon Sep 17 00:00:00 2001 From: Dwana Games Date: Fri, 21 Jun 2019 20:11:29 -0500 Subject: [PATCH 05/24] 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 --- godot/core/aabb.nim | 2 +- godot/core/arrays.nim | 2 +- godot/core/dictionaries.nim | 4 +- godot/core/nodepaths.nim | 4 +- godot/core/planes.nim | 2 +- godot/core/poolarrays.nim | 4 +- godot/core/quats.nim | 2 +- godot/core/rect2.nim | 2 +- godot/core/rids.nim | 2 +- godot/core/transform2d.nim | 2 +- godot/core/transforms.nim | 2 +- godot/core/variants.nim | 6 +- godot/core/vector2.nim | 2 +- godot/gdnativeapi.nim | 4 +- godot/godot.nim | 16 +- godot/godotapigen.nim | 262 +++++++++++++++-------------- godot/godotinternal.nim | 6 +- godot/internal/godotarrays.nim | 2 +- godot/internal/godotpoolarrays.nim | 2 +- godot/internal/godotvariants.nim | 2 +- godot/nim/godotmacros.nim | 144 ++++++++++++---- godot/nim/godotnim.nim | 28 +-- godot/nim/nim.cfg | 3 +- 23 files changed, 294 insertions(+), 211 deletions(-) diff --git a/godot/core/aabb.nim b/godot/core/aabb.nim index 66425a2..2d816da 100644 --- a/godot/core/aabb.nim +++ b/godot/core/aabb.nim @@ -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.} = diff --git a/godot/core/arrays.nim b/godot/core/arrays.nim index afe8131..fcbafb2 100644 --- a/godot/core/arrays.nim +++ b/godot/core/arrays.nim @@ -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 diff --git a/godot/core/dictionaries.nim b/godot/core/dictionaries.nim index 4a160f2..3aea17a 100644 --- a/godot/core/dictionaries.nim +++ b/godot/core/dictionaries.nim @@ -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 diff --git a/godot/core/nodepaths.nim b/godot/core/nodepaths.nim index 831c855..bf690d7 100644 --- a/godot/core/nodepaths.nim +++ b/godot/core/nodepaths.nim @@ -2,8 +2,8 @@ import hashes -import internal.godotinternaltypes, internal.godotnodepaths, - internal.godotstrings +import internal/godotinternaltypes, internal/godotnodepaths, + internal/godotstrings type NodePath* = ref object diff --git a/godot/core/planes.nim b/godot/core/planes.nim index 815a5c6..2d15c79 100644 --- a/godot/core/planes.nim +++ b/godot/core/planes.nim @@ -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.} = diff --git a/godot/core/poolarrays.nim b/godot/core/poolarrays.nim index 29aca98..eac4cf4 100644 --- a/godot/core/poolarrays.nim +++ b/godot/core/poolarrays.nim @@ -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, diff --git a/godot/core/quats.nim b/godot/core/quats.nim index 1a8da82..db88b10 100644 --- a/godot/core/quats.nim +++ b/godot/core/quats.nim @@ -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.} = diff --git a/godot/core/rect2.nim b/godot/core/rect2.nim index 8a0a1c8..19b8cbf 100644 --- a/godot/core/rect2.nim +++ b/godot/core/rect2.nim @@ -3,7 +3,7 @@ import hashes import vector2 -import internal.godotinternaltypes, internal.godotstrings +import internal/godotinternaltypes, internal/godotstrings import godotcoretypes, gdnativeapi {.push stackTrace: off.} diff --git a/godot/core/rids.nim b/godot/core/rids.nim index 800207f..a64137d 100644 --- a/godot/core/rids.nim +++ b/godot/core/rids.nim @@ -2,7 +2,7 @@ import hashes -import godotcoretypes, internal.godotinternaltypes, gdnativeapi +import godotcoretypes, internal/godotinternaltypes, gdnativeapi proc initRID*(): RID {.inline.} = getGDNativeAPI().ridNew(result) diff --git a/godot/core/transform2d.nim b/godot/core/transform2d.nim index 16f62bd..a8db09e 100644 --- a/godot/core/transform2d.nim +++ b/godot/core/transform2d.nim @@ -2,7 +2,7 @@ import hashes, vector2 -import internal.godotinternaltypes, internal.godotstrings +import internal/godotinternaltypes, internal/godotstrings import godotcoretypes, gdnativeapi proc initTransform2D*(): Transform2D {.inline.} = diff --git a/godot/core/transforms.nim b/godot/core/transforms.nim index 4a21466..501f743 100644 --- a/godot/core/transforms.nim +++ b/godot/core/transforms.nim @@ -2,7 +2,7 @@ import hashes -import internal.godotinternaltypes, internal.godotstrings +import internal/godotinternaltypes, internal/godotstrings import godotcoretypes, gdnativeapi import basis, vector3 diff --git a/godot/core/variants.nim b/godot/core/variants.nim index 8c2488d..ce1d945 100644 --- a/godot/core/variants.nim +++ b/godot/core/variants.nim @@ -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 diff --git a/godot/core/vector2.nim b/godot/core/vector2.nim index 1c8aa5e..01c0312 100644 --- a/godot/core/vector2.nim +++ b/godot/core/vector2.nim @@ -2,7 +2,7 @@ import math, godotbase, hashes -import internal.godotinternaltypes, internal.godotstrings +import internal/godotinternaltypes, internal/godotstrings import godotcoretypes, gdnativeapi {.push stackTrace: off.} diff --git a/godot/gdnativeapi.nim b/godot/gdnativeapi.nim index 591d45e..bb05425 100644 --- a/godot/gdnativeapi.nim +++ b/godot/gdnativeapi.nim @@ -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) diff --git a/godot/godot.nim b/godot/godot.nim index f4a9bf8..809f58f 100644 --- a/godot/godot.nim +++ b/godot/godot.nim @@ -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, diff --git a/godot/godotapigen.nim b/godot/godotapigen.nim index 71a52ff..a53ee6f 100644 --- a/godot/godotapigen.nim +++ b/godot/godotapigen.nim @@ -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() \ No newline at end of file diff --git a/godot/godotinternal.nim b/godot/godotinternal.nim index ce83428..207d76f 100644 --- a/godot/godotinternal.nim +++ b/godot/godotinternal.nim @@ -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, diff --git a/godot/internal/godotarrays.nim b/godot/internal/godotarrays.nim index c0736b5..c7e451d 100644 --- a/godot/internal/godotarrays.nim +++ b/godot/internal/godotarrays.nim @@ -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) diff --git a/godot/internal/godotpoolarrays.nim b/godot/internal/godotpoolarrays.nim index 5fe9419..119848f 100644 --- a/godot/internal/godotpoolarrays.nim +++ b/godot/internal/godotpoolarrays.nim @@ -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, diff --git a/godot/internal/godotvariants.nim b/godot/internal/godotvariants.nim index fec75cd..0a0980f 100644 --- a/godot/internal/godotvariants.nim +++ b/godot/internal/godotvariants.nim @@ -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) diff --git a/godot/nim/godotmacros.nim b/godot/nim/godotmacros.nim index 4389859..f6a613a 100644 --- a/godot/nim/godotmacros.nim +++ b/godot/nim/godotmacros.nim @@ -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 `_ or by using ## `load `_ or any other way ## that you can find in `Godot API `_. - let typeDef = parseType(definition, callsite()) + let typeDef = parseType(ast) result = genType(typeDef) -{.push warning[Deprecated]: on.} + diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index e58c330..1361450 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -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( diff --git a/godot/nim/nim.cfg b/godot/nim/nim.cfg index f1fb6a7..1f12860 100644 --- a/godot/nim/nim.cfg +++ b/godot/nim/nim.cfg @@ -1 +1,2 @@ ---path:"$projectdir/../" \ No newline at end of file +--path:"$projectdir/../" +-d:userealtimeGC \ No newline at end of file From 19b0c23d6223e448d512d6637531b53e943f76e7 Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Sun, 15 Sep 2019 15:39:10 +0700 Subject: [PATCH 06/24] Finalize support for Nim 0.20 Closes #32, closes #41. --- godot.nimble | 2 +- godot/core/godotbase.nim | 15 ++-- godot/godotapigen.nim | 18 ++-- godot/internal/backwardcompat.inc.nim | 19 +++++ godot/internal/godotstrings.nim | 8 +- godot/nim/godotmacros.nim | 116 ++++---------------------- godot/nim/godotnim.nim | 42 +++++----- godot/nim/nim.cfg | 2 +- 8 files changed, 91 insertions(+), 131 deletions(-) create mode 100644 godot/internal/backwardcompat.inc.nim diff --git a/godot.nimble b/godot.nimble index 66794fc..c5472c9 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.20" +version = "0.7.21" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/core/godotbase.nim b/godot/core/godotbase.nim index d76f544..7b5b804 100644 --- a/godot/core/godotbase.nim +++ b/godot/core/godotbase.nim @@ -30,14 +30,17 @@ proc stepify*(value, step: float32): float32 {.inline, noinit.} = else: value -proc min*(x, y: float32): float32 {.inline, noinit.} = - if x <= y: x else: y +when (NimMajor, NimMinor, NimPatch) < (0, 20, 4): + # Newer Nim has these procs in system module -proc abs*(x: float32): float32 {.inline, noinit.} = - if x < 0.0: -x else: x + proc min*(x, y: float32): float32 {.inline, noinit.} = + if x <= y: x else: y -proc max*(x, y: float32): float32 {.inline, noinit.} = - if y <= x: x else: y + proc abs*(x: float32): float32 {.inline, noinit.} = + if x < 0.0: -x else: x + + proc max*(x, y: float32): float32 {.inline, noinit.} = + if y <= x: x else: y {.pop.} # stackTrace: off diff --git a/godot/godotapigen.nim b/godot/godotapigen.nim index a53ee6f..ca0dfaf 100644 --- a/godot/godotapigen.nim +++ b/godot/godotapigen.nim @@ -2,7 +2,12 @@ import streams, json, os, strutils, times, sets, tables, options import sequtils, algorithm -import compiler/ast, compiler/renderer, compiler/idents, compiler/astalgo, compiler/lineinfos +import compiler/ast, compiler/renderer, compiler/idents, compiler/astalgo + +include "internal/backwardcompat.inc.nim" + +when (NimMajor, NimMinor, NimPatch) >= (0, 19, 0): + import compiler/lineinfos when (NimMajor, NimMinor, NimPatch) >= (0, 19, 0): var gic = newIdentCache() @@ -14,10 +19,13 @@ proc ident(ident: string): PNode = 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) + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): + result = newNode(kind) + else: + 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: diff --git a/godot/internal/backwardcompat.inc.nim b/godot/internal/backwardcompat.inc.nim new file mode 100644 index 0000000..9d31844 --- /dev/null +++ b/godot/internal/backwardcompat.inc.nim @@ -0,0 +1,19 @@ +# Copyright 2019 Xored Software, Inc. + +when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): + import macros, sets + + proc strVal(n: NimNode): string {.used.} = + case n.kind + of nnkIdent: + $n.ident + of nnkSym: + $n.symbol + else: + macros.strVal(n) + + proc toHashSet[A](keys: openArray[A]): HashSet[A] {.inline, used.} = + toSet(keys) + + proc initHashSet[A](): HashSet[A] {.inline, used.} = + initSet[A]() diff --git a/godot/internal/godotstrings.nim b/godot/internal/godotstrings.nim index 18bcf63..e67acfd 100644 --- a/godot/internal/godotstrings.nim +++ b/godot/internal/godotstrings.nim @@ -38,7 +38,13 @@ proc `$`*(self: GodotString): string = proc toGodotString*(s: string): GodotString {.inline.} = ## Converts the Nim string into ``GodotString`` - initGodotString(result, cstring(s), cint(s.len + 1)) + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): + if s.isNil: + initGodotString(result) + else: + initGodotString(result, cstring(s), cint(s.len + 1)) + else: + initGodotString(result, cstring(s), cint(s.len + 1)) proc toGodotString*(s: cstring): GodotString {.inline.} = ## Converts the cstring into ``GodotString`` diff --git a/godot/nim/godotmacros.nim b/godot/nim/godotmacros.nim index f6a613a..90e9ea7 100644 --- a/godot/nim/godotmacros.nim +++ b/godot/nim/godotmacros.nim @@ -32,6 +32,8 @@ type ParseError = object of Exception +include "internal/backwardcompat.inc.nim" + proc godotToNim[T](val: Variant): (T, ConversionResult) = mixin fromVariant result[1] = fromVariant(result[0], val) @@ -432,73 +434,6 @@ 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) @@ -546,6 +481,12 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} = else: initMethod.body.insert(0, initBody) + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): + # {.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: @@ -600,25 +541,6 @@ 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, @@ -627,10 +549,6 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} = when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): {.emit: """/*TYPESECTION*/ N_NOINLINE(void, setStackBottom)(void* thestackbottom); -""".} - else: - {.emit: """ -N_NOINLINE(void, nimGC_setStackBottom)(void* thestackbottom); """.} proc methFuncIdent(obj: ptr GodotObject, methodData: pointer, @@ -638,9 +556,13 @@ N_NOINLINE(void, nimGC_setStackBottom)(void* thestackbottom); args: var array[MAX_ARG_COUNT, ptr GodotVariant]): GodotVariant {.noconv.} = var stackBottom {.volatile.}: pointer - {.emit: """ - nimGC_setStackBottom((void*)(&`stackBottom`)); - """.} + stackBottom = addr(stackBottom) + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): + {.emit: """ + setStackBottom((void*)(&`stackBottom`)); + """.} + else: + nimGC_setStackBottom(stackBottom) let self = cast[classNameIdent](userData) const isStaticCall = methodNameLit == cstring"_ready" or methodNameLit == cstring"_process" or @@ -718,7 +640,7 @@ macro gdobj*(ast: varargs[untyped]): untyped = ## ## gdobj MyObj of Node: ## var myField: int - ## ## Not exported to Godot (i.e. editor will not see this field). + ## ## Not exported to Godot (i.e. editor and scripts will not see this field). ## ## var myString* {.gdExport, hint: Length, hintStr: "20".}: string ## ## Exported to Godot as ``my_string``. @@ -731,12 +653,12 @@ macro gdobj*(ast: varargs[untyped]): untyped = ## ## Exported methods are exported to Godot by default, ## ## and their Godot names are prefixed with ``_`` ## ## (in this case ``_ready``) - ## print("I am ready! myString is: " & myString) + ## print("I am ready! myString is: " & self.myString) ## ## proc myProc*() {.gdExport.} = ## ## Exported to Godot as ``my_proc`` ## print("myProc is called! Incrementing myField.") - ## inc myField + ## inc self.myField ## ## If parent type is omitted, the type is inherited from ``Object``. ## @@ -756,5 +678,3 @@ macro gdobj*(ast: varargs[untyped]): untyped = ## that you can find in `Godot API `_. let typeDef = parseType(ast) result = genType(typeDef) - - diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index 1361450..bba8b98 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -91,6 +91,8 @@ type FNV1Hash = uint32 +include "internal/backwardcompat.inc.nim" + proc isFinalized*(obj: NimGodotObject): bool {.inline.} = obj.isFinalized @@ -110,13 +112,13 @@ template initFNV1Hash(hash: var FNV1Hash) = template appendFNV1Hash(hash: var FNV1Hash, val: uint8) = block: let u64hash = hash.uint64 - hash = ( + hash = (( u64hash + (u64hash shl 1'u64) + (u64hash shl 4'u64) + (u64hash shl 7'u64) + (u64hash shl 8'u64) + - (u64hash shl 24'u64)).uint32 xor val + (u64hash shl 24'u64)) and 0xFFFFFFFF'u32).uint32 xor val {.push stackTrace:off.} proc lsb(c: ptr cwchar_t): char {.noinit, inline.} = @@ -187,7 +189,7 @@ proc nimGodotObjectFinalizer*[T: NimGodotObject](obj: T) = if obj.godotObject.isNil or obj.isNative: return # important to set it before so that ``unreference`` is aware obj.isFinalized = true - if (obj.isRef or not obj.linkedObject.isNil and obj.linkedObject.isRef) and + if (obj.isRef or not obj.linkedObject.isNil and obj.linkedObject.isRef) and obj.godotObject.unreference(): obj.deinit() @@ -708,16 +710,13 @@ proc toVariant*(s: string): Variant {.inline.} = proc fromVariant*(s: var string, val: Variant): ConversionResult = if val.getType() == VariantType.String: s = val.asString() - when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): - if val.getType() == VariantType.Nil: + elif val.getType() == VariantType.Nil: + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): s = nil else: - result = ConversionResult.TypeError - else: - if val.getType() == VariantType.Nil: s = "" - else: - result = ConversionResult.TypeError + else: + result = ConversionResult.TypeError template arrTypeInfo(T) = result.variantType = VariantType.Array @@ -840,11 +839,6 @@ when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): N_LIB_EXPORT N_CDECL(void, NimMain)(void); N_NOINLINE(void, setStackBottom)(void* thestackbottom); """.} -else: - {.emit: """/*TYPESECTION*/ - N_LIB_EXPORT N_CDECL(void, NimMain)(void); - N_NOINLINE(void, nimGC_setStackBottom)(void* thestackbottom); - """.} var nativeLibHandle: pointer proc getNativeLibHandle*(): pointer = @@ -857,10 +851,16 @@ proc godot_nativescript_init(handle: pointer) {. nativeLibHandle = handle var stackBottom {.volatile.}: pointer + stackBottom = addr(stackBottom) {.emit: """ NimMain(); - nimGC_setStackBottom((void*)(&`stackBottom`)); """.} + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): + {.emit: """ + setStackBottom((void*)(&`stackBottom`)); + """.} + else: + nimGC_setStackBottom(stackBottom) GC_fullCollect() GC_disable() @@ -896,9 +896,13 @@ proc registerFrameCallback*(cb: proc () {.closure.}) = proc godot_nativescript_frame() {.cdecl, exportc, dynlib.} = var stackBottom {.volatile.}: pointer - {.emit: """ - nimGC_setStackBottom((void*)(&`stackBottom`)); - """.} + stackBottom = addr(stackBottom) + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): + {.emit: """ + setStackBottom((void*)(&`stackBottom`)); + """.} + else: + nimGC_setStackBottom(stackBottom) for cb in idleCallbacks: cb() GC_step(nimGcStepLengthUs, true, 0) diff --git a/godot/nim/nim.cfg b/godot/nim/nim.cfg index 1f12860..add9a4d 100644 --- a/godot/nim/nim.cfg +++ b/godot/nim/nim.cfg @@ -1,2 +1,2 @@ --path:"$projectdir/../" --d:userealtimeGC \ No newline at end of file +-d:useRealtimeGc \ No newline at end of file From 2f3f4034cfd8d532efea88d15b62e39af67419e2 Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Wed, 18 Sep 2019 13:27:31 +0700 Subject: [PATCH 07/24] Fix newVariant for nil strings and older Nim --- godot.nimble | 2 +- godot/core/variants.nim | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/godot.nimble b/godot.nimble index c5472c9..71cfda5 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.21" +version = "0.7.22" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/core/variants.nim b/godot/core/variants.nim index ce1d945..fcb2b04 100644 --- a/godot/core/variants.nim +++ b/godot/core/variants.nim @@ -73,6 +73,10 @@ proc newVariant*(r: cdouble): Variant {.inline.} = proc newVariant*(s: string): Variant {.inline.} = new(result, variantFinalizer) + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): + if s.isNil: + initGodotVariant(result.godotVariant) + return var godotStr = s.toGodotString() initGodotVariant(result.godotVariant, godotStr) godotStr.deinit() From 7dd1b1ed5f0c2fedfc23b31ed7593c57515c8c66 Mon Sep 17 00:00:00 2001 From: Dwana Games Date: Thu, 19 Sep 2019 14:14:58 -0500 Subject: [PATCH 08/24] Add self to field initialization --- godot/nim/godotmacros.nim | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/godot/nim/godotmacros.nim b/godot/nim/godotmacros.nim index 90e9ea7..c0a23cc 100644 --- a/godot/nim/godotmacros.nim +++ b/godot/nim/godotmacros.nim @@ -455,7 +455,7 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} = let initBody = newStmtList() for decl in obj.fields: if not decl.defaultValue.isNil and decl.defaultValue.kind != nnkEmpty: - initBody.add(newNimNode(nnkAsgn).add(decl.name, decl.defaultValue)) + initBody.add(newNimNode(nnkAsgn).add(newDotExpr(ident("self"), decl.name), decl.defaultValue)) let name = if not decl.isExported: decl.name else: postfix(decl.name, "*") recList.add(newIdentDefs(name, decl.typ)) From c2db807da4bbc68fb7a70d4feb77b1575e869e53 Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Fri, 20 Sep 2019 09:20:50 +0700 Subject: [PATCH 09/24] Up version to 0.7.23 --- godot.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/godot.nimble b/godot.nimble index 71cfda5..1fdeeeb 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.22" +version = "0.7.23" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" From 1b8e7ccd983e26f0838696ca7c7fe4df2282ae3d Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Wed, 2 Oct 2019 15:26:41 +0700 Subject: [PATCH 10/24] Add variant conversion for Option[T] --- godot.nimble | 2 +- godot/nim/godotnim.nim | 23 ++++++++++++++++++++++- 2 files changed, 23 insertions(+), 2 deletions(-) diff --git a/godot.nimble b/godot.nimble index 1fdeeeb..6b77ece 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.23" +version = "0.7.24" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index bba8b98..cf989dc 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -1,6 +1,6 @@ # Copyright 2018 Xored Software, Inc. -import tables, typetraits, macros, unicode, strutils, sets +import tables, typetraits, macros, unicode, strutils, sets, options import gdnativeapi import core/godotcoretypes, core/godotbase import core/vector2, core/rect2, @@ -788,6 +788,27 @@ proc fromVariant*[T: array](s: var T, val: Variant): ConversionResult = else: result = ConversionResult.TypeError +proc godotTypeInfo*[T](OptT: typedesc[Option[T]]): GodotTypeInfo = + when compiles(godotTypeInfo(T)): + result.variantType = godotTypeInfo(T) + else: + result.variantType = VariantType.Nil + +proc toVariant*[T](option: Option[T]): Variant = + if option.isSome(): + result = toVariant(option.unsafeGet()) + else: + result = newVariant() + +proc fromVariant*[T](option: var Option[T], val: Variant): ConversionResult = + if val.getType() == VariantType.Nil: + option = none(T) + else: + var v: T + result = fromVariant(v, val) + if result == ConversionResult.OK: + option = some(result) + proc godotTypeInfo*(T: typedesc[Table|TableRef|OrderedTable|OrderedTableRef]): GodotTypeInfo {.inline.} = result.variantType = VariantType.Dictionary From 78d3626fa36c5749e098fa32086c34a39a6ad81e Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Wed, 4 Dec 2019 23:58:13 +0700 Subject: [PATCH 11/24] Do not log error when casting fails This allows not to perform unnecessary 'of' check before casting, if cast failure is expected. --- godot.nimble | 2 +- godot/nim/godotnim.nim | 3 --- 2 files changed, 1 insertion(+), 4 deletions(-) diff --git a/godot.nimble b/godot.nimble index 6b77ece..1ad646b 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.24" +version = "0.7.25" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index cf989dc..4d577cc 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -332,9 +332,6 @@ proc `as`*[T: NimGodotObject](obj: NimGodotObject, t: typedesc[T]): T = elif not obj.linkedObject.isNil and system.`of`(obj.linkedObject, T): result = T(obj.linkedObject) else: - when not defined(release): - printError("Failed to cast object to " & - T.name & "\n" & getStackTrace()) result = nil proc `of`*[T1, T2: NimGodotObject](obj: T1, t: typedesc[T2]): bool {.inline.} = From d1b82d351c81243670694e6f79d584ac7b837106 Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Mon, 23 Dec 2019 20:53:13 +0700 Subject: [PATCH 12/24] Fix unsigned int conversion to/from Variant --- godot.nimble | 2 +- godot/nim/godotnim.nim | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) diff --git a/godot.nimble b/godot.nimble index 1ad646b..7115536 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.25" +version = "0.7.26" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index 4d577cc..7b0a832 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -604,7 +604,11 @@ proc fromVariant*[T: SomeSignedInt or SomeUnsignedInt]( else: uint64) intVal = when T is SomeSignedInt: val.asInt() else: val.asUint() - if intVal > high(T) or intVal < low(T): + const highT = when T is SomeSignedInt: high(T).int64 + else: high(T).uint64 + const lowT = when T is SomeSignedInt: low(T).int64 + else: low(T).uint64 + if intVal > highT or intVal < lowT: result = ConversionResult.RangeError else: self = T(intVal) From 157a90e4a0bd82a91f8ab34cd1154e0b9869ae48 Mon Sep 17 00:00:00 2001 From: zetashift Date: Wed, 5 Feb 2020 05:35:50 +0100 Subject: [PATCH 13/24] add gensym in hygienic template fix thanks to demotohiro (#55) Add gensym in hygienic template fix thanks to demotohiro --- godot/nim/godotmacros.nim | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/godot/nim/godotmacros.nim b/godot/nim/godotmacros.nim index c0a23cc..c4715c3 100644 --- a/godot/nim/godotmacros.nim +++ b/godot/nim/godotmacros.nim @@ -396,10 +396,9 @@ template registerGodotField(classNameLit, classNameIdent, propNameLit, getFunc: getFuncIdent ) mixin godotTypeInfo - static: - var typeInfo: GodotTypeInfo - when compiles(godotTypeInfo(propTypeIdent)): - typeInfo = godotTypeInfo(propTypeIdent) + const typeInfo = when compiles(godotTypeInfo(propTypeIdent)): + godotTypeInfo(propTypeIdent) + else: GodotTypeInfo() const hintStr = when hintStrLit != "NIM": hintStrLit else: @@ -455,7 +454,8 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} = let initBody = newStmtList() for decl in obj.fields: if not decl.defaultValue.isNil and decl.defaultValue.kind != nnkEmpty: - initBody.add(newNimNode(nnkAsgn).add(newDotExpr(ident("self"), decl.name), decl.defaultValue)) + initBody.add(newNimNode(nnkAsgn).add(newDotExpr(ident("self"), decl.name), + decl.defaultValue)) let name = if not decl.isExported: decl.name else: postfix(decl.name, "*") recList.add(newIdentDefs(name, decl.typ)) @@ -605,7 +605,7 @@ N_NOINLINE(void, setStackBottom)(void* thestackbottom); else: toGodotStyle(meth.name) let hasReturnValueBool = not (meth.returnType.isNil or meth.returnType.kind == nnkEmpty or - (meth.returnType.kind == nnkIdent and + (meth.returnType.kind == nnkIdent and meth.returnType.strVal == "void")) let hasReturnValue = if hasReturnValueBool: ident("true") else: ident("false") From a49fcbdac7da28bb9af40f1a12ff87ca656102ed Mon Sep 17 00:00:00 2001 From: Konstantin Zaitsev Date: Wed, 5 Feb 2020 10:30:04 +0700 Subject: [PATCH 14/24] Fix variant size for 32bit platform with memory alignment --- godot/internal/godotinternaltypes.nim | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/godot/internal/godotinternaltypes.nim b/godot/internal/godotinternaltypes.nim index 8474af8..a2910c9 100644 --- a/godot/internal/godotinternaltypes.nim +++ b/godot/internal/godotinternaltypes.nim @@ -116,7 +116,8 @@ type expected*: VariantType GodotVariant* {.byref.} = object - data: array[4 + sizeof(int) div 4, float32] + data: array[2, int64] + data2: int type GodotMethodBind* = object From ed9ede5cb357022d18bd6fdb326c76aa3eb3b92d Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Wed, 5 Feb 2020 12:34:44 +0700 Subject: [PATCH 15/24] Up version to 0.7.27 --- godot.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/godot.nimble b/godot.nimble index 7115536..6d35312 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.26" +version = "0.7.27" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" From 031774f54f1ee88d9a88e8be0a255c3a590c58fd Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Wed, 3 Jun 2020 15:52:11 +0700 Subject: [PATCH 16/24] More efficient and GC-safe conversions in API generator --- godot.nimble | 2 +- godot/godotapigen.nim | 66 ++++++++++++++++++++++++++++++++------- godot/nim/godotmacros.nim | 6 +++- 3 files changed, 61 insertions(+), 13 deletions(-) diff --git a/godot.nimble b/godot.nimble index 6d35312..f511b3f 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.27" +version = "0.7.28" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/godotapigen.nim b/godot/godotapigen.nim index ca0dfaf..432814e 100644 --- a/godot/godotapigen.nim +++ b/godot/godotapigen.nim @@ -308,6 +308,13 @@ const standardTypes = toHashSet( "PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray", "PoolVector2Array", "PoolVector3Array", "PoolColorArray"]) +const variantPrimitives = [ + "bool", "cint", "int", "uint8", "int8", "uint16", "int16", "uint32", "int32", + "uint64", "Error", + "int64", "float32", "cfloat", "float64", "GodotString", "Vector2", "Rect2", + "Vector3", "Transform2D", "Plane", "Quat", "AABB", "Basis", "Transform", + "Color", "RID"] + const smallIntTypes = toHashSet(["uint8", "int8", "uint16", "int16", "uint32", "int32", "cint", "int", "Error"]) const int64Types = toHashSet(["uint64", "int64"]) @@ -322,7 +329,7 @@ const wrapperTypes = union(arrayTypes, toHashSet(["NodePath", "Dictionary", "Variant"])) proc getInternalPtr(varName: PNode, typ: string): PNode = - assert(typ in wrapperTypes) + assert(typ in wrapperTypes or typ == "Object") result = newDotExpr(varName, ident("godot" & typ)) proc newNilCheck(ident, toAssign: PNode): PNode = @@ -479,7 +486,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], ident("+"), newDotExpr(ident(varargsName.get), ident("len")))) argsAlloc.add(newCall("godotAlloc", newCall("cint", infix( - newCall("sizeof", ident("Variant")), ident("*"), + newCall("sizeof", newPNode(nkPtrTy).addChain(ident("GodotVariant"))), ident("*"), newPNode(nkPar).addChain(argLenNode)))) ) else: @@ -493,6 +500,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], vars.add(newIdentDefs(argsName, newPNode(nkEmpty), argsAlloc)) let argConversions = newPNode(nkStmtList) + let destructors = newPNode(nkStmtList) for idx, arg in meth.args: var argName = if arg.kind == ArgKind.Bound: ident(boundArgName(idx)) else: ident(arg.name) @@ -503,13 +511,48 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], 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 varargsName.isSome: - getInternalPtr(newCall("toVariant", argName), "Variant") - elif isWrappedType: getInternalPtr(argName, arg.typ) - elif isStandardType: newCall("unsafeAddr", argName) - elif arg.typ == "string": newCall("unsafeAddr", - ident("argToPassToGodot" & $idx)) - else: ident("argToPassToGodot" & $idx) # object + let convArg = + if varargsName.isSome: + let isAlreadyVariant = arg.typ == "Variant" + let variantIdent = if isAlreadyVariant: getInternalPtr(argName, "Variant") + else: ident("variant" & $idx) + if not isAlreadyVariant: + argConversions.add(newPNode(nkVarSection).addChain( + newIdentDefs(variantIdent, ident("GodotVariant"), newEmptyNode()) + )) + destructors.add( + newCall("deinit", variantIdent) + ) + if arg.typ in variantPrimitives: + argConversions.add( + newCall("initGodotVariant", variantIdent, argName) + ) + elif arg.typ in wrapperTypes or arg.typ == "Object": + argConversions.add( + newCall("initGodotVariant", variantIdent, getInternalPtr(argName, arg.typ)) + ) + elif arg.typ == "string": + let stringIdent = ident("variantString" & $idx) + argConversions.addChain( + newPNode(nkVarSection).addChain( + newIdentDefs(stringIdent, ident("GodotString"), newCall("toGodotString", argName)) + ) + ).addChain( + newCall("initGodotVariant", variantIdent, stringIdent) + ) + destructors.add(newCall("deinit", stringIdent)) + else: + raise newException(ValueError, + "Non-standard type $# for varargs params of method $# of type $#" % + [arg.typ, meth.godotName, meth.typ.godotName]) + + if isAlreadyVariant: variantIdent + else: newCall("addr", variantIdent) + elif isWrappedType: getInternalPtr(argName, arg.typ) + elif isStandardType: newCall("unsafeAddr", argName) + elif arg.typ == "string": newCall("unsafeAddr", + ident("argToPassToGodot" & $idx)) + else: ident("argToPassToGodot" & $idx) # object if not isStandardType and arg.kind == ArgKind.VarArgs: raise newException(ValueError, "Non-standard type $# for varargs params of method $# of type $#" % @@ -630,9 +673,10 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], if arg.typ == "string": body.add(newCall("deinit", ident("argToPassToGodot" & $idx))) - if meth.args.len > 0 and varargsName.isSome: - body.add(freeCall) if varargsName.isSome: + if meth.args.len > 0: + body.add(freeCall) + body.add(destructors) let errCheck = newIfStmt( infix(newDotExpr(ident("callError"), ident("error")), ident("!="), newDotExpr(ident("VariantCallErrorType"), ident("OK"))), diff --git a/godot/nim/godotmacros.nim b/godot/nim/godotmacros.nim index c4715c3..d6efa6d 100644 --- a/godot/nim/godotmacros.nim +++ b/godot/nim/godotmacros.nim @@ -272,8 +272,12 @@ macro invokeVarArgs(procIdent, objIdent; invocation = newNimNode(nnkCall).add(ident("procCall"), invocation) if hasReturnValue: + let resultVariant = genSym(nskLet, "ret") + branchBody.add( + newNimNode(nnkLetSection).add( + newIdentDefs(resultVariant, ident("Variant"), newCall("toVariant", invocation)))) let theCall = newNimNode(nnkBracketExpr).add(newNimNode(nnkDotExpr).add( - newCall("toVariant", invocation), ident("godotVariant"))) + resultVariant, ident("godotVariant"))) branchBody.add(getAst(initGodotVariantCall(ident("result"), theCall))) else: branchBody.add(invocation) From 87707a86b437371db4534884291d0e12c12036fa Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Wed, 3 Jun 2020 18:06:18 +0700 Subject: [PATCH 17/24] Remove Travis badge from README Need to fix the CI script. --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 891a920..db27270 100644 --- a/README.md +++ b/README.md @@ -1,4 +1,4 @@ -# Nim bindings for Godot Engine [![Build Status](https://travis-ci.org/pragmagic/godot-nim.svg?branch=master)](https://travis-ci.org/pragmagic/godot-nim) +# Nim bindings for Godot Engine Nim bindings for Godot 3.0 based on [GDNative](https://godotengine.org/article/dlscript-here). From 3f46e3c6481e9f18041f3b4b7d018635ae36b819 Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Fri, 5 Jun 2020 16:53:34 +0700 Subject: [PATCH 18/24] Break reference cycle in NimGodotObject --- godot.nimble | 2 +- godot/nim/godotnim.nim | 14 +++++++++++--- 2 files changed, 12 insertions(+), 4 deletions(-) diff --git a/godot.nimble b/godot.nimble index f511b3f..817406d 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.7.28" +version = "0.8.0" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index 7b0a832..7f3ed96 100644 --- a/godot/nim/godotnim.nim +++ b/godot/nim/godotnim.nim @@ -31,7 +31,7 @@ type ## The base type all Godot types inherit from. ## Manages lifecycle of the wrapped ``GodotObject``. godotObject: ptr GodotObject - linkedObject: NimGodotObject + linkedObjectPtr: pointer ## Wrapper around native object that is the container of the Nim "script" ## This is needed for `of` checks and `as` conversions to work as ## expected. For example, Nim type may inherit from ``Spatial``, but the @@ -39,6 +39,8 @@ type ## ``Particles`` is valid, but Nim type system is not aware of that. ## This works in both directions - for linked native object this ## reference points to Nim object. + ## This is stored as a raw pointer to avoid reference cycles and therefore + ## improve GC performance. isRef*: bool isFinalized: bool isNative: bool @@ -185,6 +187,9 @@ proc deinit*(obj: NimGodotObject) = obj.godotObject.deinit() obj.godotObject = nil +proc linkedObject(obj: NimGodotObject): NimGodotObject {.inline.} = + cast[NimGodotObject](obj.linkedObjectPtr) + proc nimGodotObjectFinalizer*[T: NimGodotObject](obj: T) = if obj.godotObject.isNil or obj.isNative: return # important to set it before so that ``unreference`` is aware @@ -465,14 +470,17 @@ proc setGodotObject*(nimObj: NimGodotObject, obj: ptr GodotObject) {.inline.} = proc setNativeObject*(nimObj: NimGodotObject, nativeObj: NimGodotObject) {.inline.} = ## Used from Godot constructor produced by ``gdobj`` macro. Do not call. - nimObj.linkedObject = nativeObj - nativeObj.linkedObject = nimObj + GC_ref(nativeObj) + nimObj.linkedObjectPtr = cast[pointer](nativeObj) + nativeObj.linkedObjectPtr = cast[pointer](nimObj) nativeObj.isNative = true proc removeGodotObject*(nimObj: NimGodotObject) {.inline.} = ## Used from Godot destructor produced by ``gdobj`` macro. Do not call. + GC_unref(nimObj.linkedObject) nimObj.godotObject = nil nimObj.linkedObject.godotObject = nil + nimObj.linkedObjectPtr = nil proc `==`*(self, other: NimGodotObject): bool {.inline.} = ## Compares objects by referential equality. From d3e5f91b403cb1cabc3d2f298b2c6ffc994493e4 Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Fri, 14 Aug 2020 01:44:48 +0700 Subject: [PATCH 19/24] Fix wrapping methods with Array return types --- godot.nimble | 2 +- godot/godotapigen.nim | 2 ++ 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/godot.nimble b/godot.nimble index 817406d..a296063 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.8.0" +version = "0.8.1" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/godotapigen.nim b/godot/godotapigen.nim index 432814e..ccbcc6c 100644 --- a/godot/godotapigen.nim +++ b/godot/godotapigen.nim @@ -642,6 +642,8 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], body.add(newPNode(nkVarSection).addChain(newIdentDefs( retValIdent, ident("Godot" & returnType), ))) + if returnType != "NodePath": + body.add(newCall("initGodot" & returnType, retValIdent)) elif returnType in standardTypes: addrToAssign = newCall("addr", ident("result")) elif returnType == "string": From f25c3c7a5dbe2b6ac8e4a3407e5c03751658e401 Mon Sep 17 00:00:00 2001 From: ShalokShalom Date: Sun, 11 Oct 2020 23:17:11 +0200 Subject: [PATCH 20/24] Clarify version compability One guy in the chat just asked me, if this binding is for 3.0 only, or also for 3.2.3 --- README.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/README.md b/README.md index db27270..62e28d3 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # Nim bindings for Godot Engine -Nim bindings for Godot 3.0 based on [GDNative](https://godotengine.org/article/dlscript-here). +Nim bindings for Godot 3 based on [GDNative](https://godotengine.org/article/dlscript-here). Documentation: https://pragmagic.github.io/godot-nim/ @@ -13,4 +13,4 @@ Documentation: https://pragmagic.github.io/godot-nim/ This project is licensed under the MIT license. Read [LICENSE](LICENSE) file for details. -Copyright (c) 2018 Xored Software, Inc. \ No newline at end of file +Copyright (c) 2018 Xored Software, Inc. From 388bea92053593646518946f6abc1001aea77702 Mon Sep 17 00:00:00 2001 From: Arun Dilipan Date: Mon, 23 Nov 2020 11:29:03 -0500 Subject: [PATCH 21/24] Added moveToward for vectors. --- godot/core/vector2.nim | 12 ++++++++++++ godot/core/vector3.nim | 12 ++++++++++++ 2 files changed, 24 insertions(+) diff --git a/godot/core/vector2.nim b/godot/core/vector2.nim index 01c0312..390f1f6 100644 --- a/godot/core/vector2.nim +++ b/godot/core/vector2.nim @@ -5,6 +5,8 @@ import math, godotbase, hashes import internal/godotinternaltypes, internal/godotstrings import godotcoretypes, gdnativeapi +const EPSILON = 0.00001'f32 + {.push stackTrace: off.} proc vec2*(): Vector2 {.inline, noinit.} = @@ -199,4 +201,14 @@ proc clamped*(self: Vector2; length: float32): Vector2 {.noinit.} = result /= len result *= length +proc moveToward*(vFrom, to: Vector2, delta: float32): Vector2 = + let + vd = to - vFrom + vLen = vd.length + + if vLen <= delta or vLen < EPSILON: + result = to + else: + result = vFrom + (vd / vLen) * delta + {.pop.} # stackTrace: off diff --git a/godot/core/vector3.nim b/godot/core/vector3.nim index 16f2f04..ed2903a 100644 --- a/godot/core/vector3.nim +++ b/godot/core/vector3.nim @@ -3,6 +3,8 @@ import math, hashes import godotbase, godotcoretypes +const EPSILON = 0.00001'f32 + {.push stackTrace: off.} proc vec3*(): Vector3 {.inline.} = @@ -239,4 +241,14 @@ proc cubicInterpolate*(self, b, preA, postB: Vector3; (2.0 * p0 - 5.0 * p1 + 4 * p2 - p3) * t2 + (-p0 + 3.0 * p1 - 3.0 * p2 + p3) * t3) +proc moveToward*(vFrom, to: Vector3, delta: float32): Vector3 = + let + vd = to - vFrom + vLen = vd.length + + if vLen <= delta or vLen < EPSILON: + result = to + else: + result = vFrom + (vd / vLen) * delta + {.pop.} # stackTrace: off \ No newline at end of file From 00d8ac2691140edc610245fa56f28abea6572ec5 Mon Sep 17 00:00:00 2001 From: Jason Date: Tue, 9 Mar 2021 01:57:51 -0700 Subject: [PATCH 22/24] Support nim case insensitivy in pragmas --- godot/nim/godotmacros.nim | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/godot/nim/godotmacros.nim b/godot/nim/godotmacros.nim index d6efa6d..6b81f7e 100644 --- a/godot/nim/godotmacros.nim +++ b/godot/nim/godotmacros.nim @@ -94,7 +94,7 @@ proc removePragmaNode(statement: NimNode, var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma() else: statement[1] for ident, val, i in pragmas(pragmas): - if ident == pname: + if ident.eqIdent(pname): pragmas.del(i) return val @@ -106,7 +106,7 @@ proc removePragma(statement: NimNode, pname: string): bool = var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma() else: statement[1] for ident, val, i in pragmas(pragmas): - if ident == pname: + if ident.eqIdent(pname): pragmas.del(i) return true From 7eadb07820a424c14a9474113ad3c0ee019c7334 Mon Sep 17 00:00:00 2001 From: Joey Date: Mon, 3 May 2021 10:01:38 -0600 Subject: [PATCH 23/24] Move template below arrays import Fixes #81 Alternate workaround for https://github.com/nim-lang/Nim/issues/16462 without changing VariantType. --- godot/core/poolarrays.nim | 48 +++++++++++++++++++-------------------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/godot/core/poolarrays.nim b/godot/core/poolarrays.nim index eac4cf4..29fda96 100644 --- a/godot/core/poolarrays.nim +++ b/godot/core/poolarrays.nim @@ -35,6 +35,30 @@ template definePoolArrayBase(T, GodotT, DataT, fieldName, newProcName, (when type(item) is GodotString: ($item).hash() else: item.hash()) result = !$result +definePoolArrayBase(PoolByteArray, GodotPoolByteArray, uint8, + godotPoolByteArray, newPoolByteArray, + initGodotPoolByteArray) +definePoolArrayBase(PoolIntArray, GodotPoolIntArray, cint, + godotPoolIntArray, newPoolIntArray, + initGodotPoolIntArray) +definePoolArrayBase(PoolRealArray, GodotPoolRealArray, float32, + godotPoolRealArray, newPoolRealArray, + initGodotPoolRealArray) +definePoolArrayBase(PoolVector2Array, GodotPoolVector2Array, Vector2, + godotPoolVector2Array, newPoolVector2Array, + initGodotPoolVector2Array) +definePoolArrayBase(PoolVector3Array, GodotPoolVector3Array, Vector3, + godotPoolVector3Array, newPoolVector3Array, + initGodotPoolVector3Array) +definePoolArrayBase(PoolColorArray, GodotPoolColorArray, Color, + godotPoolColorArray, newPoolColorArray, + initGodotPoolColorArray) +definePoolArrayBase(PoolStringArray, GodotPoolStringArray, string, + godotPoolStringArray, newPoolStringArray, + initGodotPoolStringArray) + +import arrays + template definePoolArray(T, GodotT, DataT, fieldName, newProcName, initProcName; noData = false) = @@ -92,30 +116,6 @@ template definePoolArray(T, GodotT, DataT, fieldName, newProcName, initProcName; for pair in arr.fieldName.mpairs: yield (pair[0].int, pair[1]) -definePoolArrayBase(PoolByteArray, GodotPoolByteArray, uint8, - godotPoolByteArray, newPoolByteArray, - initGodotPoolByteArray) -definePoolArrayBase(PoolIntArray, GodotPoolIntArray, cint, - godotPoolIntArray, newPoolIntArray, - initGodotPoolIntArray) -definePoolArrayBase(PoolRealArray, GodotPoolRealArray, float32, - godotPoolRealArray, newPoolRealArray, - initGodotPoolRealArray) -definePoolArrayBase(PoolVector2Array, GodotPoolVector2Array, Vector2, - godotPoolVector2Array, newPoolVector2Array, - initGodotPoolVector2Array) -definePoolArrayBase(PoolVector3Array, GodotPoolVector3Array, Vector3, - godotPoolVector3Array, newPoolVector3Array, - initGodotPoolVector3Array) -definePoolArrayBase(PoolColorArray, GodotPoolColorArray, Color, - godotPoolColorArray, newPoolColorArray, - initGodotPoolColorArray) -definePoolArrayBase(PoolStringArray, GodotPoolStringArray, string, - godotPoolStringArray, newPoolStringArray, - initGodotPoolStringArray) - -import arrays - definePoolArray(PoolByteArray, GodotPoolByteArray, uint8, godotPoolByteArray, newPoolByteArray, initGodotPoolByteArray) From 4175dbb3e50d09341ae61cfa55907f40e9eb388b Mon Sep 17 00:00:00 2001 From: Ruslan Mustakov Date: Mon, 3 May 2021 23:18:50 +0700 Subject: [PATCH 24/24] Bump version to 0.8.2 --- godot.nimble | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/godot.nimble b/godot.nimble index a296063..d7ca12b 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.8.1" +version = "0.8.2" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT"