diff --git a/README.md b/README.md index 62e28d3..891a920 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ -# Nim bindings for Godot Engine +# 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 3 based on [GDNative](https://godotengine.org/article/dlscript-here). +Nim bindings for Godot 3.0 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. +Copyright (c) 2018 Xored Software, Inc. \ No newline at end of file diff --git a/godot.nimble b/godot.nimble index d7ca12b..8e4c8c0 100644 --- a/godot.nimble +++ b/godot.nimble @@ -1,4 +1,4 @@ -version = "0.8.2" +version = "0.7.18" author = "Xored Software, Inc." description = "Godot Engine bindings" license = "MIT" diff --git a/godot/core/godotbase.nim b/godot/core/godotbase.nim index 7b5b804..d76f544 100644 --- a/godot/core/godotbase.nim +++ b/godot/core/godotbase.nim @@ -30,17 +30,14 @@ proc stepify*(value, step: float32): float32 {.inline, noinit.} = else: value -when (NimMajor, NimMinor, NimPatch) < (0, 20, 4): - # Newer Nim has these procs in system module +proc min*(x, y: float32): float32 {.inline, noinit.} = + if x <= y: x else: y - proc min*(x, y: float32): float32 {.inline, noinit.} = - if x <= y: x else: y +proc abs*(x: float32): float32 {.inline, noinit.} = + if x < 0.0: -x else: x - 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 +proc max*(x, y: float32): float32 {.inline, noinit.} = + if y <= x: x else: y {.pop.} # stackTrace: off diff --git a/godot/core/poolarrays.nim b/godot/core/poolarrays.nim index 29fda96..eac4cf4 100644 --- a/godot/core/poolarrays.nim +++ b/godot/core/poolarrays.nim @@ -35,30 +35,6 @@ 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) = @@ -116,6 +92,30 @@ 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) diff --git a/godot/core/rect2.nim b/godot/core/rect2.nim index 19b8cbf..a152e14 100644 --- a/godot/core/rect2.nim +++ b/godot/core/rect2.nim @@ -150,4 +150,4 @@ proc abs*(self: Rect2): Rect2 {.inline, noinit.} = proc `==`*(a, b: Rect2): bool {.inline, noinit.} = a.position == b.position and a.size == b.size -{.pop.} # stackTrace: off \ No newline at end of file +{.pop.} # stackTrace: off diff --git a/godot/core/variants.nim b/godot/core/variants.nim index fcb2b04..ce1d945 100644 --- a/godot/core/variants.nim +++ b/godot/core/variants.nim @@ -73,10 +73,6 @@ 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() diff --git a/godot/core/vector2.nim b/godot/core/vector2.nim index 390f1f6..01c0312 100644 --- a/godot/core/vector2.nim +++ b/godot/core/vector2.nim @@ -5,8 +5,6 @@ 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.} = @@ -201,14 +199,4 @@ 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 ed2903a..16f2f04 100644 --- a/godot/core/vector3.nim +++ b/godot/core/vector3.nim @@ -3,8 +3,6 @@ import math, hashes import godotbase, godotcoretypes -const EPSILON = 0.00001'f32 - {.push stackTrace: off.} proc vec3*(): Vector3 {.inline.} = @@ -241,14 +239,4 @@ 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 diff --git a/godot/gdnativeapi.nim b/godot/gdnativeapi.nim index bb05425..c9c2001 100644 --- a/godot/gdnativeapi.nim +++ b/godot/gdnativeapi.nim @@ -3593,7 +3593,7 @@ proc setGDNativeAPIInternal(apiStruct: pointer, initOptions: ptr GDNativeInitOpt # Not used discard - if not header.next.isNil and header != header.next: + if not header.next.isNil: setGDNativeAPIInternal(header.next, initOptions, foundCoreApi, foundNativeScriptApi) diff --git a/godot/godot.nim b/godot/godot.nim index 809f58f..fd0add1 100644 --- a/godot/godot.nim +++ b/godot/godot.nim @@ -15,4 +15,4 @@ export godotbase, godotcoretypes, vector2, rect2, vector3, transform2d, planes, arrays, poolarrays, variants export godotmacros, godotnim -export GodotPropertyHint, GodotPropertyUsage \ No newline at end of file +export GodotPropertyHint, GodotPropertyUsage diff --git a/godot/godotapigen.nim b/godot/godotapigen.nim index ccbcc6c..c8bf60a 100644 --- a/godot/godotapigen.nim +++ b/godot/godotapigen.nim @@ -4,28 +4,15 @@ import streams, json, os, strutils, times, sets, tables, options import sequtils, algorithm 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() + var gic* = newIdentCache() proc getIdent(ident: string): PIdent = getIdent(gic, ident) proc ident(ident: string): PNode = - result = PNode(kind: nkIdent, ident: getIdent(ident)) - -proc newPNode(kind: TNodeKind): PNode = - 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) + result = newNode(nkIdent) + result.ident = getIdent(ident) proc addChain(node: PNode, others: varargs[PNode]): PNode {.discardable.} = for other in others: @@ -34,37 +21,37 @@ proc addChain(node: PNode, others: varargs[PNode]): PNode {.discardable.} = proc newIdentDefs(name, typ: PNode, defaultVal: PNode = nil): PNode = - result = newPNode(nkIdentDefs) + result = newNode(nkIdentDefs) result.add(name) result.add(typ) if defaultVal.isNil: - result.add(newPNode(nkEmpty)) + result.add(newNode(nkEmpty)) else: result.add(defaultVal) -proc newProc(name: PNode, params: openArray[PNode], body = newPNode(nkEmpty), +proc newProc(name: PNode, params: openArray[PNode], body = newNode(nkEmpty), procType = nkProcDef): PNode = - result = newPNode(procType) + result = newNode(procType) result.add(name) - result.add(newPNode(nkEmpty)) - result.add(newPNode(nkEmpty)) - let formalParams = newPNode(nkFormalParams) + result.add(newNode(nkEmpty)) + result.add(newNode(nkEmpty)) + let formalParams = newNode(nkFormalParams) for param in params: formalParams.add(param) result.add(formalParams) - result.add(newPNode(nkEmpty)) - result.add(newPNode(nkEmpty)) + result.add(newNode(nkEmpty)) + result.add(newNode(nkEmpty)) result.add(body) proc newIfStmt(condition, body: PNode): PNode = - result = newPNode(nkIfStmt) - let branch = newPNode(nkElifBranch) + result = newNode(nkIfStmt) + let branch = newNode(nkElifBranch) result.add(branch) branch.add(condition) branch.add(body) proc newCall(theProc: PNode, args: varargs[PNode]): PNode = - result = newPNode(nkCall) + result = newNode(nkCall) result.add(theProc) for arg in args: result.add(arg) @@ -73,66 +60,66 @@ proc newCall(theProc: string, args: varargs[PNode]): PNode = newCall(ident(theProc), args) proc newStrLit(s: string): PNode = - result = newPNode(nkStrLit) + result = newNode(nkStrLit) result.strVal = s proc newRStrLit(s: string): PNode = - result = newPNode(nkRStrLit) + result = newNode(nkRStrLit) result.strVal = s proc newCStringLit(s: string): PNode = - newPNode(nkCallStrLit).addChain(ident("cstring"), newRStrLit(s)) + newNode(nkCallStrLit).addChain(ident("cstring"), newRStrLit(s)) proc newIntLit(val: BiggestInt): PNode = - result = newPNode(nkIntLit) + result = newNode(nkIntLit) result.intVal = val proc newInt64Lit(val: BiggestInt): PNode = - result = newPNode(nkInt64Lit) + result = newNode(nkInt64Lit) result.intVal = val proc newFloatLit(val: BiggestFloat): PNode = - result = newPNode(nkFloatLit) + result = newNode(nkFloatLit) result.floatVal = val proc newFloat64Lit(val: BiggestFloat): PNode = - result = newPNode(nkFloat64Lit) + result = newNode(nkFloat64Lit) result.floatVal = val proc newNilLit(): PNode = - result = newPNode(nkNilLit) + result = newNode(nkNilLit) proc newDotExpr(left, right: PNode): PNode = - result = newPNode(nkDotExpr) + result = newNode(nkDotExpr) result.add(left) result.add(right) proc newCommand(left, right: PNode): PNode = - result = newPNode(nkCommand) + result = newNode(nkCommand) result.add(left) result.add(right) proc infix(left, op, right: PNode): PNode = - result = newPNode(nkInfix) + result = newNode(nkInfix) result.add(op) result.add(left) result.add(right) proc postfix(left: PNode, op: string): PNode = - result = newPNode(nkPostfix) + result = newNode(nkPostfix) result.add(ident(op)) result.add(left) proc prefix(op: string, right: PNode): PNode = - result = newPNode(nkPrefix) + result = newNode(nkPrefix) result.add(ident(op)) result.add(right) proc newBracketExpr(first, bracket: PNode): PNode = - newPNode(nkBracketExpr).addChain(first, bracket) + newNode(nkBracketExpr).addChain(first, bracket) proc newEmptyNode(): PNode = - newPNode(nkEmpty) + newNode(nkEmpty) type GodotType = ref object name: string @@ -225,42 +212,42 @@ proc toNimStyle(name: string): string = proc newRefTypeNode(typeSection: PNode, typ, base, doc: string, isExported = true) = - let typeDef = newPNode(nkTypeDef) + let typeDef = newNode(nkTypeDef) typeSection.add(typeDef) if isExported: typeDef.add(postfix(ident(typ), "*")) else: typeDef.add(ident(typ)) - typeDef.add(newPNode(nkEmpty)) # generic - let objTy = newPNode(nkObjectTy) - let refTy = newPNode(nkRefTy) + typeDef.add(newNode(nkEmpty)) # generic + let objTy = newNode(nkObjectTy) + let refTy = newNode(nkRefTy) refTy.add(objTy) typeDef.add(refTy) - objTy.add(newPNode(nkEmpty)) - let inherit = newPNode(nkOfInherit) + objTy.add(newNode(nkEmpty)) + let inherit = newNode(nkOfInherit) inherit.add(ident(base)) objTy.add(inherit) if doc.len > 0: - let recList = newPNode(nkRecList) - let docNode = newPNode(nkCommentStmt) + let recList = newNode(nkRecList) + let docNode = newNode(nkCommentStmt) docNode.comment = doc recList.add(docNode) objTy.add(recList) else: - objTy.add(newPNode(nkEmpty)) + objTy.add(newNode(nkEmpty)) proc makeConstSection(constObj: JsonNode): PNode = if constObj.len == 0: - return newPNode(nkEmpty) + return newNode(nkEmpty) - result = newPNode(nkConstSection) + result = newNode(nkConstSection) for field, val in constObj: - let def = newPNode(nkConstDef) + let def = newNode(nkConstDef) def.add(postfix(ident(field), "*")) - def.add(newPNode(nkEmpty)) # infer type + def.add(newNode(nkEmpty)) # infer type var valNode: PNode if val.kind == JInt: valNode = newInt64Lit(val.num) @@ -270,7 +257,7 @@ proc makeConstSection(constObj: JsonNode): PNode = elif val.kind == JBool: valNode = ident($val.bval) elif val.kind == JString: - valNode = newPNode(nkStrLit) + valNode = newNode(nkStrLit) valNode.strVal = val.str else: raise newException(ValueError, "Unexpected constant kind: " & $val.kind) @@ -299,7 +286,7 @@ type isBase: bool isDiscardable: bool -const standardTypes = toHashSet( +const standardTypes = toSet( ["bool", "cint", "int", "uint8", "int8", "uint16", "int16", "uint32", "int32", "uint64", "Error", "int64", "float32", "cfloat", "float64", "GodotString", "Vector2", "Rect2", @@ -308,33 +295,26 @@ 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"]) +const smallIntTypes = toSet(["uint8", "int8", "uint16", "int16", "uint32", + "int32", "cint", "int", "Error"]) +const int64Types = toSet(["uint64", "int64"]) const intTypes = union(smallIntTypes, int64Types) -const float64Types = toHashSet(["float64", "cdouble"]) -const float32Types = toHashSet(["float32", "cfloat"]) +const float64Types = toSet(["float64", "cdouble"]) +const float32Types = toSet(["float32", "cfloat"]) const floatTypes = union(float64Types, float32Types) -const arrayTypes = toHashSet(["Array", "PoolByteArray", +const arrayTypes = toSet(["Array", "PoolByteArray", "PoolIntArray", "PoolRealArray", "PoolStringArray", "PoolVector2Array", "PoolVector3Array", "PoolColorArray"]) const wrapperTypes = union(arrayTypes, - toHashSet(["NodePath", "Dictionary", "Variant"])) + toSet(["NodePath", "Dictionary", "Variant"])) proc getInternalPtr(varName: PNode, typ: string): PNode = - assert(typ in wrapperTypes or typ == "Object") + assert(typ in wrapperTypes) result = newDotExpr(varName, ident("godot" & typ)) proc newNilCheck(ident, toAssign: PNode): PNode = newIfStmt(newCall("isNil", ident), - newPNode(nkAsgn).addChain(ident).addChain( + newNode(nkAsgn).addChain(ident).addChain( toAssign ) ) @@ -407,8 +387,6 @@ proc makeDefaultValue(arg: MethodArg): PNode = result = newCall("newVariant") else: failed = true - elif arg.typ == "Dictionary": - result = newCall("newDictionary") else: failed = true @@ -425,12 +403,12 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], meth: MethodInfo, withImplementation: bool) = var body: PNode if not withImplementation: - body = newPNode(nkEmpty) + body = newNode(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 = newPNode(nkStmtList).addChain( - newPNode(nkDiscardStmt).addChain(newPNode(nkEmpty))) + body = newNode(nkStmtList).addChain( + newNode(nkDiscardStmt).addChain(newNode(nkEmpty))) else: let methGodotName = if meth.godotName.startsWith('_'): "underscore" & meth.godotName[1..^1] @@ -441,12 +419,12 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], if methodBindName[0].isUpperAscii(): methodBindName[0] = methodBindName[0].toLowerAscii() if methodBindName notin methodBindRegistry: - let methodBindDecl = newPNode(nkVarSection).addChain( + let methodBindDecl = newNode(nkVarSection).addChain( newIdentDefs( - newPNode(nkPragmaExpr).addChain( + newNode(nkPragmaExpr).addChain( ident(methodBindName)).addChain( - newPNode(nkPragma).addChain(ident("threadvar"))), - newPNode(nkPtrTy).addChain(ident("GodotMethodBind")) + newNode(nkPragma).addChain(ident("threadvar"))), + newNode(nkPtrTy).addChain(ident("GodotMethodBind")) )) tree.add(methodBindDecl) methodBindRegistry.incl(methodBindName) @@ -455,7 +433,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], newCall("getMethod", newCStringLit(meth.typ.godotName), newCStringLit(meth.godotName)) ) - let vars = newPNode(nkVarSection) + let vars = newNode(nkVarSection) var varargsName = none(string) var isVarargs: bool var staticArgsLen: int @@ -470,15 +448,15 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], elif arg.kind == ArgKind.Bound: let argName = boundArgName(idx) vars.add(newIdentDefs( - ident(argName), newPNode(nkEmpty), arg.makeDefaultValue())) + ident(argName), newNode(nkEmpty), arg.makeDefaultValue())) - let argsAlloc = newPNode(nkCast).addChain( - newPNode(nkPtrTy).addChain( - newPNode(nkBracketExpr).addChain( + let argsAlloc = newNode(nkCast).addChain( + newNode(nkPtrTy).addChain( + newNode(nkBracketExpr).addChain( ident("array"), ident("MAX_ARG_COUNT"), - if isVarargs: newPNode(nkPtrTy).addChain(ident("GodotVariant")) + if isVarargs: newNode(nkPtrTy).addChain(ident("GodotVariant")) else: ident("pointer")))) - staticArgsLen = if varargsName.isNone: meth.args.len + staticArgsLen = if varargsName.isSome: meth.args.len else: meth.args.len - 1 if varargsName.isSome: argLenNode = newCall("cint", @@ -486,92 +464,56 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], ident("+"), newDotExpr(ident(varargsName.get), ident("len")))) argsAlloc.add(newCall("godotAlloc", newCall("cint", infix( - newCall("sizeof", newPNode(nkPtrTy).addChain(ident("GodotVariant"))), ident("*"), - newPNode(nkPar).addChain(argLenNode)))) + newCall("sizeof", ident("Variant")), ident("*"), + newNode(nkPar).addChain(argLenNode)))) ) else: argLenNode = newCall("cint", newIntLit(staticArgsLen)) vars.add(newIdentDefs( ident("argsStatic"), - newPNode(nkBracketExpr).addChain( + newNode(nkBracketExpr).addChain( ident("array"), newIntLit(staticArgsLen), ident("pointer")), - newPNode(nkEmpty))) - argsAlloc.add(newCommand(ident("addr"), ident("argsStatic"))) - vars.add(newIdentDefs(argsName, newPNode(nkEmpty), argsAlloc)) + newNode(nkEmpty))) + argsAlloc.add(newDotExpr(ident("argsStatic"), ident("addr"))) + vars.add(newIdentDefs(argsName, newNode(nkEmpty), argsAlloc)) - let argConversions = newPNode(nkStmtList) - let destructors = newPNode(nkStmtList) + let argConversions = newNode(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 = newPNode(nkBracketExpr).addChain( + argName = newNode(nkBracketExpr).addChain( 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 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 + 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 if not isStandardType and arg.kind == ArgKind.VarArgs: 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.isNone: if arg.typ == "string": - argConversions.add(newPNode(nkVarSection).addChain( + argConversions.add(newNode(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(newPNode(nkElse).addChain(newNilLit())) - argConversions.add(newPNode(nkLetSection).addChain( + ).addChain(newNode(nkElse).addChain(newNilLit())) + argConversions.add(newNode(nkLetSection).addChain( newIdentDefs(ident("argToPassToGodot" & $idx), newEmptyNode(), objVal))) - let argAsgn = newPNode(nkAsgn).addChain( - newPNode(nkBracketExpr).addChain( - newPNode(nkBracketExpr).addChain(argsName), argIdx), + let argAsgn = newNode(nkAsgn).addChain( + newNode(nkBracketExpr).addChain( + newNode(nkBracketExpr).addChain(argsName), argIdx), convArg ) if arg.kind != ArgKind.VarArgs: @@ -579,14 +521,14 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], argAsgn ) else: - argConversions.add(newPNode(nkVarSection).addChain( - newIdentDefs(ident("idx"), newPNode(nkEmpty), + argConversions.add(newNode(nkVarSection).addChain( + newIdentDefs(ident("idx"), newNode(nkEmpty), newIntLit(staticArgsLen)))) - let argLoop = newPNode(nkWhileStmt) + let argLoop = newNode(nkWhileStmt) argConversions.add(argLoop) argLoop.add(infix(ident("idx"), ident("<"), argLenNode) ) - argLoop.add(newPNode(nkStmtList).addChain( + argLoop.add(newNode(nkStmtList).addChain( argAsgn, newCommand(ident("inc"), ident("idx")))) @@ -595,26 +537,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: newPNode(nkNilLit), + if meth.args.len > 0: argsName else: newNode(nkNilLit), argLenNode, if not isVarargs: ident(retName) else: ident("callError") ) if not isVarargs: theCall.sons.delete(3) let freeCall = newCall("godotFree", argsName) - body = newPNode(nkStmtList) + body = newNode(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(newPNode(nkLetSection).addChain(newIdentDefs( - ident("self"), newPNode(nkEmpty), varName + body.add(newNode(nkLetSection).addChain(newIdentDefs( + ident("self"), newNode(nkEmpty), varName ))) body.add(nilCheck) body.add(vars) body.add(argConversions) if not isVarargs: - let retPtrDecl = newPNode(nkVarSection).addChain( + let retPtrDecl = newNode(nkVarSection).addChain( newIdentDefs(ident(retName), ident("pointer"), newEmptyNode()) ) body.add(retPtrDecl) @@ -629,45 +571,43 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], var addrToAssign = newCall("addr", retValIdent) if returnType in smallIntTypes: isConversionRet = true - body.add(newPNode(nkVarSection).addChain(newIdentDefs( + body.add(newNode(nkVarSection).addChain(newIdentDefs( retValIdent, ident("int64"), ))) elif returnType in float32Types: isConversionRet = true - body.add(newPNode(nkVarSection).addChain(newIdentDefs( + body.add(newNode(nkVarSection).addChain(newIdentDefs( retValIdent, ident("float64"), ))) elif returnType in wrapperTypes: isWrapperRet = true - body.add(newPNode(nkVarSection).addChain(newIdentDefs( + body.add(newNode(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": isStringRet = true - body.add(newPNode(nkVarSection).addChain(newIdentDefs( + body.add(newNode(nkVarSection).addChain(newIdentDefs( retValIdent, ident("GodotString"), ))) elif returnType != "void": isObjRet = true - body.add(newPNode(nkVarSection).addChain(newIdentDefs( - retValIdent, newPNode(nkPtrTy).addChain(ident("GodotObject")), + body.add(newNode(nkVarSection).addChain(newIdentDefs( + retValIdent, newNode(nkPtrTy).addChain(ident("GodotObject")), ))) - body.add(newPNode(nkAsgn).addChain(ident(retName), addrToAssign)) + body.add(newNode(nkAsgn).addChain(ident(retName), addrToAssign)) if not isVarargs: body.add(theCall) else: if meth.returnType.isSome: isVariantRet = true - let callStmt = newPNode(nkLetSection).addChain( + let callStmt = newNode(nkLetSection).addChain( newIdentDefs( - newPNode(nkPragmaExpr).addChain( - ident(retName), newPNode(nkPragma).addChain(ident("used"))), - newPNode(nkEmpty), theCall)) + newNode(nkPragmaExpr).addChain( + ident(retName), newNode(nkPragma).addChain(ident("used"))), + newNode(nkEmpty), theCall)) body.add(callStmt) if varargsName.isNone: @@ -675,49 +615,48 @@ 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"))), - newPNode(nkRaiseStmt).addChain( + newNode(nkRaiseStmt).addChain( newCall("newCallError", ident("callError"))) ) body.add(errCheck) if isVariantRet: - let convErrDef = newPNode(nkLetSection).addChain( - newIdentDefs(ident("convErr"), newPNode(nkEmpty), + let convErrDef = newNode(nkLetSection).addChain( + newIdentDefs(ident("convErr"), newNode(nkEmpty), newCall("fromVariant", ident("result"), newCall("newVariant", retValIdent)))) let convCheck = newIfStmt( infix(ident("convErr"), ident("!="), newDotExpr(ident("ConversionResult"), ident("OK"))), - newPNode(nkRaiseStmt).addChain( + newNode(nkRaiseStmt).addChain( newCall("newConversionError", ident("convErr"))) ) body.add(convErrDef) body.add(convCheck) if isStringRet: - body.add(newPNode(nkAsgn).addChain( + body.add(newNode(nkAsgn).addChain( ident("result"), prefix("$", retValIdent))) body.add(newCall("deinit", retValIdent)) elif isConversionRet: - body.add(newPNode(nkAsgn).addChain( + body.add(newNode(nkAsgn).addChain( ident("result"), newCall(meth.returnType.get, retValIdent))) elif isWrapperRet: - body.add(newPNode(nkAsgn).addChain( + body.add(newNode(nkAsgn).addChain( ident("result"), newCall("new" & meth.returnType.get, retValIdent))) elif isObjRet: - body.add(newPNode(nkAsgn).addChain(ident("result"), + body.add(newNode(nkAsgn).addChain(ident("result"), newCall(newBracketExpr(ident("asNimGodotObject"), newCall("type", ident("result"))), retValIdent, ident("false"), ident("true")))) elif isStringRet: - body.add(newPNode(nkAsgn).addChain(ident("result"), + body.add(newNode(nkAsgn).addChain(ident("result"), newCall("$", retValIdent))) let procType = if meth.isVirtual: nkMethodDef @@ -726,7 +665,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], if meth.returnType.isSome: params.add(ident(meth.returnType.get)) else: - params.add(newPNode(nkEmpty)) + params.add(newNode(nkEmpty)) if not meth.typ.isSingleton: params.add(newIdentDefs(ident("self"), ident(toNimType(meth.typ.name)))) @@ -737,7 +676,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), - newPNode(nkBracketExpr).addChain(ident("varargs"), ident(arg.typ)))) + newNode(nkBracketExpr).addChain(ident("varargs"), ident(arg.typ)))) of ArgKind.Bound: discard @@ -745,9 +684,9 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], else: meth.name, params, body, procType) if not withImplementation: - let pragma = newPNode(nkPragma) + let pragma = newNode(nkPragma) pragma.add(ident("gcsafe")) - pragma.add(newPNode(nkExprColonExpr).addChain(ident("locks"), + pragma.add(newNode(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 @@ -799,7 +738,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 = toHashSet(["emit_signal"]) + const discardableMethods = toSet(["emit_signal"]) result = MethodInfo( name: ident(nimName), typ: typ, @@ -828,7 +767,7 @@ proc makeProperty(types: Table[string, GodotType], tree: PNode, return let getterNameStr = toNimStyle(propertyObj["name"].str) let getterName = ident(getterNameStr) - let setterName = newPNode(nkAccQuoted).addChain(ident(getterNameStr & "=")) + let setterName = newNode(nkAccQuoted).addChain(ident(getterNameStr & "=")) let getter = findMethod(obj, propertyObj["getter"].str) let nimType = if getter.isNil: toNimType(types, propertyObj["type"].str) @@ -914,10 +853,10 @@ proc newRegisterClassNode(typ: GodotType): PNode = ) proc genSingletonDecl(typ: string): PNode = - result = newPNode(nkVarSection) + result = newNode(nkVarSection) let name = singletonName(typ) - let threadvar = newPNode(nkPragma).addChain(ident("threadvar")) - result.add(newIdentDefs(newPNode(nkPragmaExpr).addChain(name, threadvar), + let threadvar = newNode(nkPragma).addChain(ident("threadvar")) + result.add(newIdentDefs(newNode(nkPragmaExpr).addChain(name, threadvar), ident(typ))) proc shouldExport(typ: GodotType, types: Table[string, GodotType]): bool = @@ -934,9 +873,9 @@ proc sortByDerivedCount(types: Table[string, GodotType]): seq[GodotType] = proc genTypeFile(types: Table[string, GodotType], targetDir: string) = let sortedTypes = sortByDerivedCount(types) - let godotApiTypesTree = newPNode(nkStmtList) - godotApiTypesTree.add(newPNode(nkImportStmt).addChain(ident("godot"))) - let typeSection = newPNode(nkTypeSection) + let godotApiTypesTree = newNode(nkStmtList) + godotApiTypesTree.add(newNode(nkImportStmt).addChain(ident("godot"))) + let typeSection = newNode(nkTypeSection) godotApiTypesTree.add(typeSection) for typ in sortedTypes: @@ -958,10 +897,10 @@ proc genSingletonWithDerived(tree: PNode, typ: GodotType, types: Table[string, GodotType]) = let sortedTypes = sortByDerivedCount(types) - var parents = initHashSet[string]() + var parents = initSet[string]() parents.incl(typ.name) - let typeDecl = newPNode(nkTypeSection) + let typeDecl = newNode(nkTypeSection) tree.add(typeDecl) proc genDecl(typ: GodotType) = newRefTypeNode(typeDecl, typ.name, typ.baseName, typ.doc, @@ -1011,17 +950,17 @@ proc genApi*(targetDir: string, apiJsonFile: string) = for typ in types.values(): let moduleName = typeNameToModuleName(typ.name) echo "Generating ", moduleName, ".nim..." - let tree = newPNode(nkStmtList) - let importStmt = newPNode(nkImportStmt) + let tree = newNode(nkStmtList) + let importStmt = newNode(nkImportStmt) importStmt.add(ident("godot")) importStmt.add(ident("godottypes")) importStmt.add(ident("godotinternal")) tree.add(importStmt) - let exportStmt = newPNode(nkExportStmt) + let exportStmt = newNode(nkExportStmt) exportStmt.add(ident("godottypes")) tree.add(exportStmt) - var methodBindRegsitry = initHashSet[string]() + var methodBindRegsitry = initSet[string]() let obj = typ.jsonNode if typ.baseName != "NimGodotObject": let baseModule = typeNameToModuleName(typ.baseName) @@ -1082,6 +1021,7 @@ when isMainModule: import os const usage = """Tool for wrapping Godot API into Nim + godotapigen [godot binary path] [target directory]""" proc main() = @@ -1112,4 +1052,4 @@ when isMainModule: genApi(targetDir, jsonFile) - main() \ No newline at end of file + main() diff --git a/godot/internal/backwardcompat.inc.nim b/godot/internal/backwardcompat.inc.nim deleted file mode 100644 index 9d31844..0000000 --- a/godot/internal/backwardcompat.inc.nim +++ /dev/null @@ -1,19 +0,0 @@ -# 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/godotinternaltypes.nim b/godot/internal/godotinternaltypes.nim index a2910c9..8474af8 100644 --- a/godot/internal/godotinternaltypes.nim +++ b/godot/internal/godotinternaltypes.nim @@ -116,8 +116,7 @@ type expected*: VariantType GodotVariant* {.byref.} = object - data: array[2, int64] - data2: int + data: array[4 + sizeof(int) div 4, float32] type GodotMethodBind* = object diff --git a/godot/internal/godotstrings.nim b/godot/internal/godotstrings.nim index e67acfd..18bcf63 100644 --- a/godot/internal/godotstrings.nim +++ b/godot/internal/godotstrings.nim @@ -38,13 +38,7 @@ proc `$`*(self: GodotString): string = proc toGodotString*(s: string): GodotString {.inline.} = ## Converts the Nim string into ``GodotString`` - 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)) + 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 6b81f7e..5b17717 100644 --- a/godot/nim/godotmacros.nim +++ b/godot/nim/godotmacros.nim @@ -1,6 +1,6 @@ # Copyright 2018 Xored Software, Inc. -import macros, tables, typetraits, strutils, sets, sequtils, options, algorithm +import macros, tables, typetraits, strutils, sets, sequtils, options import godotinternal, internal/godotvariants import godotnim, core/variants @@ -32,8 +32,6 @@ 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) @@ -53,15 +51,15 @@ template parseError(node: NimNode, msg: string) = proc extractNames(definition: NimNode): tuple[name, parentName: string] = if definition.kind == nnkIdent: - result.name = definition.strVal + result.name = $(definition.ident) else: if not (definition.kind == nnkInfix and - definition[0].strVal == "of"): + definition[0].ident == toNimIdent("of")): parseError(definition, "invalid type definition") - result.name = definition[1].strVal + result.name = $(definition[1].ident) case definition[2].kind: of nnkIdent: - result.parentName = definition[2].strVal + result.parentName = $definition[2].ident else: parseError(definition[2], "parent type expected") @@ -74,13 +72,13 @@ proc newCStringLit(s: string): NimNode {.compileTime.} = newNimNode(nnkCallStrLit).add(ident("cstring"), newRStrLit(s)) iterator pragmas(node: NimNode): - tuple[key: string, value: NimNode, index: int] = + tuple[key: NimIdent, 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].strVal, node[index][1], index) + yield (node[index][0].ident, node[index][1], index) elif node[index].kind == nnkIdent: - yield (node[index].strVal, nil, index) + yield (node[index].ident, nil, index) proc removePragmaNode(statement: NimNode, pname: string): NimNode {.compileTime.} = @@ -93,8 +91,9 @@ 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.eqIdent(pname): + if ident == pnameIdent: pragmas.del(i) return val @@ -105,8 +104,9 @@ 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.eqIdent(pname): + if ident == pnameIdent: pragmas.del(i) return true @@ -178,9 +178,8 @@ proc parseVarSection(decl: NimNode): seq[VarDecl] = else: result.add(identDefsToVarDecls(decl[i])) -proc parseType(ast: NimNode): ObjectDecl = - let definition = ast[0] - let body = ast[^1] +proc parseType(definition, callSite: NimNode): ObjectDecl = + let body = callSite[^1] result = ObjectDecl( fields: newSeq[VarDecl](), methods: newSeq[MethodDecl]() @@ -188,11 +187,11 @@ proc parseType(ast: NimNode): ObjectDecl = (result.name, result.parentName) = extractNames(definition) var isTool = false - for i in 1..(ast.len - 2): - let option = ast[i] + for i in 2..(callSite.len - 2): + let option = callSite[i] if option.kind != nnkIdent: parseError(option, "type specifier expected") - if option.strVal == "tool": + if option.ident == toNimIdent("tool"): isTool = true else: parseError(option, "valid type specifier expected") @@ -215,7 +214,7 @@ proc parseType(ast: NimNode): ObjectDecl = macro invokeVarArgs(procIdent, objIdent; minArgs, maxArgs: static[int], numArgsIdent, argSeqIdent; argTypes: seq[NimNode], - hasReturnValue, isStaticCall: static[bool]): untyped = + hasReturnValue, isStaticCall: static[bool]): typed = ## Produces statement in form: ## ## .. code-block:: nim @@ -272,12 +271,8 @@ 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( - resultVariant, ident("godotVariant"))) + newCall("toVariant", invocation), ident("godotVariant"))) branchBody.add(getAst(initGodotVariantCall(ident("result"), theCall))) else: branchBody.add(invocation) @@ -292,7 +287,7 @@ macro invokeVarArgs(procIdent, objIdent; " arguments, but got " & $numArgs) result.add(newNimNode(nnkElse).add(getAst( - printInvokeErr(procIdent.strVal, minArgs, maxArgs, numArgsIdent)))) + printInvokeErr($procIdent.ident, minArgs, maxArgs, numArgsIdent)))) proc typeError(nimType: string, value: string, godotType: VariantType, className: cstring, propertyName: cstring): string = @@ -400,9 +395,10 @@ template registerGodotField(classNameLit, classNameIdent, propNameLit, getFunc: getFuncIdent ) mixin godotTypeInfo - const typeInfo = when compiles(godotTypeInfo(propTypeIdent)): - godotTypeInfo(propTypeIdent) - else: GodotTypeInfo() + static: + var typeInfo: GodotTypeInfo + when compiles(godotTypeInfo(propTypeIdent)): + typeInfo = godotTypeInfo(propTypeIdent) const hintStr = when hintStrLit != "NIM": hintStrLit else: @@ -458,8 +454,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(newDotExpr(ident("self"), decl.name), - decl.defaultValue)) + initBody.add(newNimNode(nnkAsgn).add(decl.name, decl.defaultValue)) let name = if not decl.isExported: decl.name else: postfix(decl.name, "*") recList.add(newIdentDefs(name, decl.typ)) @@ -485,11 +480,10 @@ 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") - ))) + # {.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) @@ -552,21 +546,26 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} = argTypes, methFuncIdent, hasReturnValue) = when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): {.emit: """/*TYPESECTION*/ -N_NOINLINE(void, setStackBottom)(void* thestackbottom); -""".} + N_NOINLINE(void, setStackBottom)(void* thestackbottom); + """.} + else: + {.emit: """/*TYPESECTION*/ + 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]): GodotVariant {.noconv.} = var stackBottom {.volatile.}: pointer - stackBottom = addr(stackBottom) when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): {.emit: """ - setStackBottom((void*)(&`stackBottom`)); + setStackBottom((void*)(&`stackBottom`)); """.} else: - nimGC_setStackBottom(stackBottom) + {.emit: """ + nimGC_setStackBottom((void*)(&`stackBottom`)); + """.} let self = cast[classNameIdent](userData) const isStaticCall = methodNameLit == cstring"_ready" or methodNameLit == cstring"_process" or @@ -609,8 +608,8 @@ 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.strVal == "void")) + (meth.returnType.kind == nnkIdent and + meth.returnType.ident == toNimIdent("void"))) let hasReturnValue = if hasReturnValueBool: ident("true") else: ident("false") result.add(getAst( @@ -636,7 +635,11 @@ N_NOINLINE(void, setStackBottom)(void* thestackbottom); GodotMethodAttributes(), refDec) result.add(getAst(registerRefIncDec(classNameLit))) -macro gdobj*(ast: varargs[untyped]): untyped = +{.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.} = ## Generates Godot type. Self-documenting example: ## ## .. code-block:: nim @@ -644,7 +647,7 @@ macro gdobj*(ast: varargs[untyped]): untyped = ## ## gdobj MyObj of Node: ## var myField: int - ## ## Not exported to Godot (i.e. editor and scripts will not see this field). + ## ## Not exported to Godot (i.e. editor will not see this field). ## ## var myString* {.gdExport, hint: Length, hintStr: "20".}: string ## ## Exported to Godot as ``my_string``. @@ -657,12 +660,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: " & self.myString) + ## print("I am ready! myString is: " & myString) ## ## proc myProc*() {.gdExport.} = ## ## Exported to Godot as ``my_proc`` ## print("myProc is called! Incrementing myField.") - ## inc self.myField + ## inc myField ## ## If parent type is omitted, the type is inherited from ``Object``. ## @@ -680,5 +683,7 @@ macro gdobj*(ast: varargs[untyped]): untyped = ## `gdnew `_ or by using ## `load `_ or any other way ## that you can find in `Godot API `_. - let typeDef = parseType(ast) + let typeDef = parseType(definition, callsite()) result = genType(typeDef) + +{.push warning[Deprecated]: on.} diff --git a/godot/nim/godotnim.nim b/godot/nim/godotnim.nim index 7f3ed96..4694572 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, options +import tables, typetraits, macros, unicode, strutils, sets import gdnativeapi import core/godotcoretypes, core/godotbase import core/vector2, core/rect2, @@ -31,7 +31,7 @@ type ## The base type all Godot types inherit from. ## Manages lifecycle of the wrapped ``GodotObject``. godotObject: ptr GodotObject - linkedObjectPtr: pointer + linkedObject: NimGodotObject ## 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,8 +39,6 @@ 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 @@ -93,8 +91,6 @@ type FNV1Hash = uint32 -include "internal/backwardcompat.inc.nim" - proc isFinalized*(obj: NimGodotObject): bool {.inline.} = obj.isFinalized @@ -114,13 +110,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)) and 0xFFFFFFFF'u32).uint32 xor val + (u64hash shl 24'u64)).uint32 xor val {.push stackTrace:off.} proc lsb(c: ptr cwchar_t): char {.noinit, inline.} = @@ -187,15 +183,12 @@ 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 obj.isFinalized = true - if (obj.isRef or not obj.linkedObject.isNil and obj.linkedObject.isRef) and - obj.godotObject.unreference(): + if obj.isRef and obj.godotObject.unreference() or + not obj.linkedObject.isNil: obj.deinit() macro baseNativeType(T: typedesc): cstring = @@ -337,6 +330,9 @@ 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.} = @@ -347,20 +343,23 @@ proc newRStrLit(s: string): NimNode {.compileTime.} = result = newNimNode(nnkRStrLit) result.strVal = s -macro toGodotName(T: typedesc): untyped = +macro toGodotName(T: typedesc): string = + var godotName: string if T is GodotString or T is string: - newStrLitNode"String" + godotName = "String" elif T is SomeFloat: - newStrLitNode"float" + godotName = "float" elif T is SomeUnsignedInt or T is SomeSignedInt: - newStrLitNode"int" - else: - let nameStr = ((T.getType()[1][1].strVal).split(':')[0]) - case nameStr: - of "File", "Directory", "Thread", "Mutex", "Semaphore": - newStrLitNode("_" & nameStr) - else: - newStrLitNode(nameStr) + godotName = "int" + if godotName.len == 0: + let nameStr = (($T.getType()[1][1].symbol).split(':')[0]) + godotName = case nameStr: + of "File", "Directory", "Thread", "Mutex", "Semaphore": + "_" & nameStr + else: + nameStr + + result = newLit(godotName) macro asCString(s: static[string]): cstring = result = newNimNode(nnkCallStrLit).add( @@ -470,17 +469,14 @@ 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. - GC_ref(nativeObj) - nimObj.linkedObjectPtr = cast[pointer](nativeObj) - nativeObj.linkedObjectPtr = cast[pointer](nimObj) + nimObj.linkedObject = nativeObj + nativeObj.linkedObject = 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. @@ -612,11 +608,7 @@ proc fromVariant*[T: SomeSignedInt or SomeUnsignedInt]( else: uint64) intVal = when T is SomeSignedInt: val.asInt() else: val.asUint() - 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: + if intVal > high(T) or intVal < low(T): result = ConversionResult.RangeError else: self = T(intVal) @@ -720,10 +712,7 @@ proc fromVariant*(s: var string, val: Variant): ConversionResult = if val.getType() == VariantType.String: s = val.asString() elif val.getType() == VariantType.Nil: - when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): - s = nil - else: - s = "" + s = "" else: result = ConversionResult.TypeError @@ -797,27 +786,6 @@ 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 @@ -869,6 +837,11 @@ 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 = @@ -881,16 +854,17 @@ proc godot_nativescript_init(handle: pointer) {. nativeLibHandle = handle var stackBottom {.volatile.}: pointer - stackBottom = addr(stackBottom) - {.emit: """ - NimMain(); - """.} + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): {.emit: """ + NimMain(); setStackBottom((void*)(&`stackBottom`)); """.} else: - nimGC_setStackBottom(stackBottom) + {.emit: """ + NimMain(); + nimGC_setStackBottom((void*)(&`stackBottom`)); + """.} GC_fullCollect() GC_disable() @@ -901,8 +875,7 @@ proc godot_gdnative_init(options: ptr GDNativeInitOptions) {. proc godot_gdnative_terminate(options: ptr GDNativeTerminateOptions) {. cdecl, exportc, dynlib.} = - if not options[].inEditor or not compileOption("threads"): - deallocHeap(runFinalizers = not options[].inEditor, allowGcAfterwards = false) + deallocHeap(runFinalizers = not options[].inEditor, allowGcAfterwards = false) const nimGcStepLengthUs {.intdefine.} = 2000 @@ -926,13 +899,15 @@ proc registerFrameCallback*(cb: proc () {.closure.}) = proc godot_nativescript_frame() {.cdecl, exportc, dynlib.} = var stackBottom {.volatile.}: pointer - stackBottom = addr(stackBottom) + when (NimMajor, NimMinor, NimPatch) < (0, 19, 0): {.emit: """ - setStackBottom((void*)(&`stackBottom`)); + setStackBottom((void*)(&`stackBottom`)); """.} else: - nimGC_setStackBottom(stackBottom) + {.emit: """ + nimGC_setStackBottom((void*)(&`stackBottom`)); + """.} for cb in idleCallbacks: cb() GC_step(nimGcStepLengthUs, true, 0) diff --git a/godot/nim/nim.cfg b/godot/nim/nim.cfg index add9a4d..f1fb6a7 100644 --- a/godot/nim/nim.cfg +++ b/godot/nim/nim.cfg @@ -1,2 +1 @@ ---path:"$projectdir/../" --d:useRealtimeGc \ No newline at end of file +--path:"$projectdir/../" \ No newline at end of file