Mark emitSignal as discardable

This commit is contained in:
Ruslan Mustakov 2017-08-14 20:21:47 +07:00
commit c5f6d47f3e
2 changed files with 86 additions and 62 deletions

View file

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

View file

@ -255,7 +255,17 @@ proc makeConstSection(constObj: JsonNode): PNode =
def.add(valNode) def.add(valNode)
result.add(def) result.add(def)
type MethodArg = tuple[name, typ: string, defaultVal: JsonNode, isVarargs: bool] type
MethodArg = tuple[name, typ: string, defaultVal: JsonNode, isVarargs: bool]
MethodInfo = ref object
name: PNode
godotName: string
typ: GodotType
args: seq[MethodArg]
returnType: string
isVirtual: bool
isBase: bool
isDiscardable: bool
const standardTypes = toSet( const standardTypes = toSet(
["bool", "cint", "int", "uint8", "int8", "uint16", "int16", "uint32", "int32", ["bool", "cint", "int", "uint8", "int8", "uint16", "int16", "uint32", "int32",
@ -337,21 +347,22 @@ proc makeDefaultValue(arg: MethodArg): PNode =
[$arg.defaultVal, arg.typ]) [$arg.defaultVal, arg.typ])
proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string], proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
name: PNode, godotMethodName: string, meth: MethodInfo, withImplementation: bool) =
typ: GodotType, args: seq[MethodArg],
returnType: string, isVirtual,
isBase, withImplementation: bool) =
var body: PNode var body: PNode
if not withImplementation: if not withImplementation:
body = newNode(nkEmpty) body = newNode(nkEmpty)
elif godotMethodName == "_init" and 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 = newNode(nkStmtList).addChain(
newNode(nkDiscardStmt).addChain(newNode(nkEmpty))) newNode(nkDiscardStmt).addChain(newNode(nkEmpty)))
else: else:
let methGodotName = if meth.godotName.startsWith('_'):
"underscore" & meth.godotName[1..^1]
else:
meth.godotName
var methodBindName = toNimStyle( var methodBindName = toNimStyle(
typ.name & "_" & godotMethodName & "_method_bind") meth.typ.name & "_" & methGodotName & "_method_bind")
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:
@ -366,8 +377,8 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
methodBindRegistry.incl(methodBindName) methodBindRegistry.incl(methodBindName)
let nilCheck = newNilCheck(ident(methodBindName), let nilCheck = newNilCheck(ident(methodBindName),
newCall("getMethod", newCStringLit(typ.godotName), newCall("getMethod", newCStringLit(meth.typ.godotName),
newCStringLit(godotMethodName)) newCStringLit(meth.godotName))
) )
let vars = newNode(nkVarSection) let vars = newNode(nkVarSection)
var varargsName: string var varargsName: string
@ -375,8 +386,8 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
var staticArgsLen: int var staticArgsLen: int
var argLenNode = newIntLit(0) var argLenNode = newIntLit(0)
let argsName = ident("argsToPassToGodot") let argsName = ident("argsToPassToGodot")
if args.len > 0: if meth.args.len > 0:
for arg in args: for arg in meth.args:
if arg.isVarargs: if arg.isVarargs:
varargsName = arg.name varargsName = arg.name
isVarargs = true isVarargs = true
@ -388,8 +399,8 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
ident("array"), ident("MAX_ARG_COUNT"), ident("array"), ident("MAX_ARG_COUNT"),
if isVarargs: newNode(nkPtrTy).addChain(ident("GodotVariant")) if isVarargs: newNode(nkPtrTy).addChain(ident("GodotVariant"))
else: ident("pointer")))) else: ident("pointer"))))
staticArgsLen = if varargsName.isNil: args.len staticArgsLen = if varargsName.isNil: meth.args.len
else: args.len - 1 else: meth.args.len - 1
if not varargsName.isNil: if not varargsName.isNil:
argLenNode = newCall("cint", argLenNode = newCall("cint",
infix(newIntLit(staticArgsLen), infix(newIntLit(staticArgsLen),
@ -410,7 +421,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
vars.add(newIdentDefs(argsName, newNode(nkEmpty), argsAlloc)) vars.add(newIdentDefs(argsName, newNode(nkEmpty), argsAlloc))
let argConversions = newNode(nkStmtList) let argConversions = newNode(nkStmtList)
for idx, arg in args: for idx, arg in meth.args:
var argName = ident(arg.name) var argName = ident(arg.name)
if arg.isVarargs: if arg.isVarargs:
argName = newNode(nkBracketExpr).addChain( argName = newNode(nkBracketExpr).addChain(
@ -429,7 +440,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
if not isStandardType and arg.isVarargs: if not isStandardType and arg.isVarargs:
raise newException(ValueError, raise newException(ValueError,
"Non-standard type $# for varargs params of method $# of type $#" % "Non-standard type $# for varargs params of method $# of type $#" %
[arg.typ, godotMethodName, typ.godotName]) [arg.typ, meth.godotName, meth.typ.godotName])
if not isStandardType and varargsName.isNil: if not isStandardType and varargsName.isNil:
if arg.typ == "string": if arg.typ == "string":
argConversions.add(newNode(nkVarSection).addChain( argConversions.add(newNode(nkVarSection).addChain(
@ -465,7 +476,7 @@ 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 args.len > 0: argsName else: newNode(nkNilLit), if meth.args.len > 0: argsName else: newNode(nkNilLit),
argLenNode, argLenNode,
if not isVarargs: ident(retName) else: ident("callError") if not isVarargs: ident(retName) else: ident("callError")
) )
@ -473,10 +484,10 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
theCall.sons.delete(3) theCall.sons.delete(3)
let freeCall = newCall("godotFree", argsName) let freeCall = newCall("godotFree", argsName)
body = newNode(nkStmtList) body = newNode(nkStmtList)
if typ.isSingleton: if meth.typ.isSingleton:
let varName = singletonName(typ.name) let varName = singletonName(meth.typ.name)
body.add(newNilCheck(varName, newCall( body.add(newNilCheck(varName, newCall(
newBracketExpr(ident("getSingleton"), ident(typ.name))))) newBracketExpr(ident("getSingleton"), ident(meth.typ.name)))))
body.add(newNode(nkLetSection).addChain(newIdentDefs( body.add(newNode(nkLetSection).addChain(newIdentDefs(
ident("self"), newNode(nkEmpty), varName ident("self"), newNode(nkEmpty), varName
))) )))
@ -494,26 +505,26 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
var isStringRet: bool var isStringRet: bool
var isWrapperRet: bool var isWrapperRet: bool
let retValIdent = if not isVarargs: ident("ptrCallVal") else: ident(retName) let retValIdent = if not isVarargs: ident("ptrCallVal") else: ident(retName)
if not returnType.isNil and not isVarargs: if not meth.returnType.isNil and not isVarargs:
var addrToAssign = newCall("addr", retValIdent) var addrToAssign = newCall("addr", retValIdent)
if returnType in smallIntTypes: if meth.returnType in smallIntTypes:
isConversionRet = true isConversionRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs( body.add(newNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("int64"), retValIdent, ident("int64"),
))) )))
elif returnType in float32Types: elif meth.returnType in float32Types:
isConversionRet = true isConversionRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs( body.add(newNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("float64"), retValIdent, ident("float64"),
))) )))
elif returnType in wrapperTypes: elif meth.returnType in wrapperTypes:
isWrapperRet = true isWrapperRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs( body.add(newNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("Godot" & returnType), retValIdent, ident("Godot" & meth.returnType),
))) )))
elif returnType in standardTypes: elif meth.returnType in standardTypes:
addrToAssign = newCall("addr", ident("result")) addrToAssign = newCall("addr", ident("result"))
elif returnType == "string": elif meth.returnType == "string":
isStringRet = true isStringRet = true
body.add(newNode(nkVarSection).addChain(newIdentDefs( body.add(newNode(nkVarSection).addChain(newIdentDefs(
retValIdent, ident("GodotString"), retValIdent, ident("GodotString"),
@ -528,7 +539,7 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
if not isVarargs: if not isVarargs:
body.add(theCall) body.add(theCall)
else: else:
if not returnType.isNil: if not meth.returnType.isNil:
isVariantRet = true isVariantRet = true
let callStmt = newNode(nkLetSection).addChain( let callStmt = newNode(nkLetSection).addChain(
newIdentDefs( newIdentDefs(
@ -538,11 +549,11 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
body.add(callStmt) body.add(callStmt)
if varargsName.isNil: if varargsName.isNil:
for idx, arg in args: for idx, arg in meth.args:
if arg.typ == "string": if arg.typ == "string":
body.add(newCall("deinit", ident("argToPassToGodot" & $idx))) body.add(newCall("deinit", ident("argToPassToGodot" & $idx)))
if args.len > 0 and not varargsName.isNil: if meth.args.len > 0 and not varargsName.isNil:
body.add(freeCall) body.add(freeCall)
if not varargsName.isNil: if not varargsName.isNil:
let errCheck = newIfStmt( let errCheck = newIfStmt(
@ -572,11 +583,11 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
elif isConversionRet: elif isConversionRet:
body.add(newNode(nkAsgn).addChain( body.add(newNode(nkAsgn).addChain(
ident("result"), ident("result"),
newCall(returnType, retValIdent))) newCall(meth.returnType, retValIdent)))
elif isWrapperRet: elif isWrapperRet:
body.add(newNode(nkAsgn).addChain( body.add(newNode(nkAsgn).addChain(
ident("result"), ident("result"),
newCall("new" & returnType, retValIdent))) newCall("new" & meth.returnType, retValIdent)))
elif isObjRet: elif isObjRet:
body.add(newNode(nkAsgn).addChain(ident("result"), body.add(newNode(nkAsgn).addChain(ident("result"),
newCall(newBracketExpr(ident("asNimGodotObject"), newCall(newBracketExpr(ident("asNimGodotObject"),
@ -585,45 +596,42 @@ proc doGenerateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
body.add(newNode(nkAsgn).addChain(ident("result"), body.add(newNode(nkAsgn).addChain(ident("result"),
newCall("$", retValIdent))) newCall("$", retValIdent)))
let procType = if isVirtual: nkMethodDef let procType = if meth.isVirtual: nkMethodDef
else: nkProcDef else: nkProcDef
var params = newSeqOfCap[PNode](args.len + 2) var params = newSeqOfCap[PNode](meth.args.len + 2)
if not returnType.isNil: if not meth.returnType.isNil:
params.add(ident(returnType)) params.add(ident(meth.returnType))
else: else:
params.add(newNode(nkEmpty)) params.add(newNode(nkEmpty))
if not typ.isSingleton: if not meth.typ.isSingleton:
params.add(newIdentDefs(ident("self"), ident(toNimType(typ.name)))) params.add(newIdentDefs(ident("self"), ident(toNimType(meth.typ.name))))
for arg in args: for arg in meth.args:
if arg.isVarargs: if arg.isVarargs:
params.add(newIdentDefs(ident(arg.name), params.add(newIdentDefs(ident(arg.name),
newNode(nkBracketExpr).addChain(ident("varargs"), ident(arg.typ)))) newNode(nkBracketExpr).addChain(ident("varargs"), ident(arg.typ))))
else: else:
let defaultValue = arg.makeDefaultValue() let defaultValue = arg.makeDefaultValue()
params.add(newIdentDefs(ident(arg.name), ident(arg.typ), defaultValue)) params.add(newIdentDefs(ident(arg.name), ident(arg.typ), defaultValue))
let procDecl = newProc(if not withImplementation: postfix(name, "*") let procDecl = newProc(if not withImplementation: postfix(meth.name, "*")
else: name, else: meth.name,
params, body, procType) params, body, procType)
if not withImplementation: if not withImplementation:
let pragma = newNode(nkPragma) let pragma = newNode(nkPragma)
pragma.add(ident("gcsafe")) pragma.add(ident("gcsafe"))
pragma.add(newNode(nkExprColonExpr).addChain(ident("locks"), pragma.add(newNode(nkExprColonExpr).addChain(ident("locks"),
newIntLit(0))) newIntLit(0)))
if isVirtual and isBase and 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
pragma.add(ident("base")) pragma.add(ident("base"))
if meth.isDiscardable and not meth.returnType.isNil:
pragma.add(ident("discardable"))
procDecl.sons[4] = pragma procDecl.sons[4] = pragma
tree.add(procDecl) tree.add(procDecl)
proc generateMethod(tree: PNode, methodBindRegistry: var HashSet[string], proc generateMethod(tree: PNode, methodBindRegistry: var HashSet[string],
name: PNode, godotMethodName: string, meth: MethodInfo, withImplementation: bool) =
typ: GodotType, args: seq[MethodArg], doGenerateMethod(tree, methodBindRegistry, meth, withImplementation)
returnType: string,
isVirtual, isBase, withImplementation: bool) =
doGenerateMethod(
tree, methodBindRegistry, name, godotMethodName, typ,
args, returnType, isVirtual, isBase, withImplementation)
proc makeProperty(types: Table[string, GodotType], tree: PNode, proc makeProperty(types: Table[string, GodotType], tree: PNode,
methodBindRegistry: var HashSet[string], methodBindRegistry: var HashSet[string],
@ -634,14 +642,21 @@ proc makeProperty(types: Table[string, GodotType], tree: PNode,
let setterName = newNode(nkAccQuoted).addChain(ident(getterNameStr & "=")) let setterName = newNode(nkAccQuoted).addChain(ident(getterNameStr & "="))
let nimType = toNimType(types, propertyObj["type"].str) let nimType = toNimType(types, propertyObj["type"].str)
generateMethod(tree, methodBindRegistry, let getterInfo = MethodInfo(
getterName, propertyObj["getter"].str, typ, name: getterName,
@[], nimType, isVirtual = false, typ: typ,
isBase = false, withImplementation) godotName: propertyObj["getter"].str,
generateMethod(tree, methodBindRegistry, args: @[],
setterName, propertyObj["setter"].str, typ, returnType: nimType
@[("val", nimType, JsonNode(nil), false)], )
nil, isVirtual = false, isBase = false, withImplementation) let setterInfo = MethodInfo(
name: setterName,
typ: typ,
godotName: propertyObj["setter"].str,
args: @[("val", nimType, JsonNode(nil), false)]
)
generateMethod(tree, methodBindRegistry, getterInfo, withImplementation)
generateMethod(tree, methodBindRegistry, setterInfo, withImplementation)
proc makeMethod(types: Table[string, GodotType], tree: PNode, proc makeMethod(types: Table[string, GodotType], tree: PNode,
methodBindRegistry: var HashSet[string], methodBindRegistry: var HashSet[string],
@ -688,11 +703,20 @@ proc makeMethod(types: Table[string, GodotType], tree: PNode,
if meth["name"].str == '_' & godotName: if meth["name"].str == '_' & godotName:
nimName = nimName & "Impl" nimName = nimName & "Impl"
generateMethod(tree, methodBindRegistry, const discardableMethods = toSet(["emit_signal"])
ident(nimName), methodObj["name"].str, let methodInfo = MethodInfo(
typ, args, name: ident(nimName),
returnType, methodObj["is_virtual"].bval, isBase, typ: typ,
withImplementation) godotName: methodObj["name"].str,
args: args,
returnType: returnType,
isVirtual: methodObj["is_virtual"].bval,
isBase: isBase,
isDiscardable: typ.godotName == "Object" and
methodObj["name"].str in discardableMethods
)
generateMethod(tree, methodBindRegistry, methodInfo, withImplementation)
proc addAttributeToDoc(doc: var string, propName, propValue: string) = proc addAttributeToDoc(doc: var string, propName, propValue: string) =
if doc.len > 0: if doc.len > 0: