Updated to work with nim 0.20

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

Fix toGodotName function

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

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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

View file

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