Compare commits

..

8 commits

Author SHA1 Message Date
Joey Payne
1770d13119 Make setStackBottom backwards compatible 2019-03-10 17:53:41 -06:00
Joey Payne
a8021301bf Fix compiler warnings about dot imports 2019-03-10 17:09:42 -06:00
Joey Payne
0ad22b7b7c Fix compilation errors in generated API 2019-03-10 17:08:42 -06:00
Fabian Keller
8d8d095af9 fixed new name of setStackBottom 2018-12-30 18:01:10 +01:00
Fabian Keller
9f29e2eec9 fixed more isNil usages 2018-12-30 17:09:50 +01:00
Fabian Keller
a05b5c1776 work-around for nim-lang/Nim#7375 2018-12-30 16:32:40 +01:00
Fabian Keller
a536c102d6 workaround for nim/macro/typedesc issue 2018-12-30 15:41:44 +01:00
Fabian Keller
5ab4775939 attempt to make 0.19 compatible 2018-12-30 12:40:10 +01:00
17 changed files with 276 additions and 414 deletions

View file

@ -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.

View file

@ -1,4 +1,4 @@
version = "0.8.2"
version = "0.7.18"
author = "Xored Software, Inc."
description = "Godot Engine bindings"
license = "MIT"

View file

@ -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

View file

@ -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)

View file

@ -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
{.pop.} # stackTrace: off

View file

@ -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()

View file

@ -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

View file

@ -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

View file

@ -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)

View file

@ -15,4 +15,4 @@ export godotbase, godotcoretypes, vector2, rect2, vector3, transform2d, planes,
arrays, poolarrays, variants
export godotmacros, godotnim
export GodotPropertyHint, GodotPropertyUsage
export GodotPropertyHint, GodotPropertyUsage

View file

@ -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()
main()

View file

@ -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]()

View file

@ -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

View file

@ -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``

View file

@ -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 <godotnim.html#gdnew>`_ or by using
## `load <godotapi/resource_loader.html#load,string,string,bool>`_ or any other way
## that you can find in `Godot API <index.html#modules-godot-api>`_.
let typeDef = parseType(ast)
let typeDef = parseType(definition, callsite())
result = genType(typeDef)
{.push warning[Deprecated]: on.}

View file

@ -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)

View file

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