Fix object property export

This commit is contained in:
Ruslan Mustakov 2017-08-08 17:23:45 +07:00
commit daa56270e5
4 changed files with 58 additions and 41 deletions

View file

@ -14,4 +14,4 @@ export godotbase, vector2, rect2, vector3, transform2d, planes, quats,
poolarrays, variants poolarrays, variants
export godotmacros, godotnim export godotmacros, godotnim
export GodotPropertyHint, GodotPropertyUsageFlags export GodotPropertyHint, GodotPropertyUsage

View file

@ -118,7 +118,7 @@ const
GODOT_PROPERTY_USAGE_STORAGE_VALUE or GODOT_PROPERTY_USAGE_NETWORK_VALUE GODOT_PROPERTY_USAGE_STORAGE_VALUE or GODOT_PROPERTY_USAGE_NETWORK_VALUE
type type
GodotPropertyUsageFlags* {.size: sizeof(cint), pure.} = enum GodotPropertyUsage* {.size: sizeof(cint), pure.} = enum
Storage = GODOT_PROPERTY_USAGE_STORAGE_VALUE Storage = GODOT_PROPERTY_USAGE_STORAGE_VALUE
Editor = GODOT_PROPERTY_USAGE_EDITOR_VALUE Editor = GODOT_PROPERTY_USAGE_EDITOR_VALUE
Network = GODOT_PROPERTY_USAGE_NETWORK_VALUE Network = GODOT_PROPERTY_USAGE_NETWORK_VALUE
@ -151,7 +151,7 @@ type
typ*: cint typ*: cint
hint*: GodotPropertyHint hint*: GodotPropertyHint
hintString*: GodotString hintString*: GodotString
usage*: GodotPropertyUsageFlags usage*: cint
defaultValue*: GodotVariant defaultValue*: GodotVariant
GodotInstanceCreateFunc* {.bycopy.} = object GodotInstanceCreateFunc* {.bycopy.} = object
@ -217,7 +217,7 @@ type
typ*: cint typ*: cint
hint*: GodotPropertyHint hint*: GodotPropertyHint
hintString*: GodotString hintString*: GodotString
usage*: GodotPropertyUsageFlags usage*: cint
defaultValue*: GodotVariant defaultValue*: GodotVariant
GodotSignal* = object GodotSignal* = object

View file

@ -12,7 +12,7 @@ type
isNoGodot: bool isNoGodot: bool
hint: string hint: string
hintStr: string hintStr: string
usage: string usage: NimNode
isExported: bool isExported: bool
MethodDecl = ref object MethodDecl = ref object
@ -71,15 +71,31 @@ 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: string, index: int] = tuple[key: NimIdent, 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:
let val = $(node[index][1]) yield (node[index][0].ident, node[index][1], index)
yield (node[index][0].ident, val, index)
elif node[index].kind == nnkIdent: elif node[index].kind == nnkIdent:
yield (node[index].ident, nil, index) yield (node[index].ident, nil, index)
proc removePragmaNode(statement: NimNode,
pname: string): NimNode {.compileTime.} =
## Removes the pragma from the node and returns value of the pragma
## Works for routine nodes or nnkPragmaExpr
if not (RoutineNodes.contains(statement.kind) or
statement.kind == nnkPragmaExpr):
return nil
result = nil
var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma()
else: statement[1]
let pnameIdent = !pname
for ident, val, i in pragmas(pragmas):
if ident == pnameIdent:
pragmas.del(i)
return val
proc removePragma(statement: NimNode, pname: string): bool = proc removePragma(statement: NimNode, pname: string): bool =
## Removes the pragma from the node and returns whether pragma was removed ## Removes the pragma from the node and returns whether pragma was removed
if not (RoutineNodes.contains(statement.kind) or if not (RoutineNodes.contains(statement.kind) or
@ -97,18 +113,9 @@ proc removeStrPragma(statement: NimNode,
pname: string): string {.compileTime.} = pname: string): string {.compileTime.} =
## Removes the pragma from the node and returns value of the pragma ## Removes the pragma from the node and returns value of the pragma
## Works for routine nodes or nnkPragmaExpr ## Works for routine nodes or nnkPragmaExpr
if not (RoutineNodes.contains(statement.kind) or let node = removePragmaNode(statement, pname)
statement.kind == nnkPragmaExpr): result = if node.isNil: nil
return nil else: $node
result = nil
var pragmas = if RoutineNodes.contains(statement.kind): statement.pragma()
else: statement[1]
let pnameIdent = !pname
for ident, val, i in pragmas(pragmas):
if ident == pnameIdent:
pragmas.del(i)
return (if val.isNil: "" else: val)
proc isExported(node: NimNode): bool {.compileTime.} = proc isExported(node: NimNode): bool {.compileTime.} =
if node.kind == nnkPragmaExpr: if node.kind == nnkPragmaExpr:
@ -130,7 +137,7 @@ proc identDefsToVarDecls(identDefs: NimNode): seq[VarDecl] =
let nameNode = identDefs[i].copyNimTree() let nameNode = identDefs[i].copyNimTree()
let hint = removeStrPragma(nameNode, "hint") let hint = removeStrPragma(nameNode, "hint")
let hintStr = removeStrPragma(nameNode, "hintStr") let hintStr = removeStrPragma(nameNode, "hintStr")
let usage = removeStrPragma(nameNode, "usage") let usage = removePragmaNode(nameNode, "usage")
let isGdExport = removePragma(nameNode, "gdExport") let isGdExport = removePragma(nameNode, "gdExport")
result.add(VarDecl( result.add(VarDecl(
@ -345,7 +352,7 @@ template registerGodotClass(classNameIdent, classNameLit, isRef,
template registerGodotField(classNameLit, classNameIdent, propNameLit, template registerGodotField(classNameLit, classNameIdent, propNameLit,
propNameIdent, propTypeLit, propTypeIdent, propNameIdent, propTypeLit, propTypeIdent,
setFuncIdent, getFuncIdent, hintStrLit, setFuncIdent, getFuncIdent, hintStrLit,
hintIdent, usageIdent, hasDefaultValue, hintIdent, usageExpr, hasDefaultValue,
defaultValueNode) = defaultValueNode) =
proc setFuncIdent(obj: ptr GodotObject, methData: pointer, proc setFuncIdent(obj: ptr GodotObject, methData: pointer,
nimPtr: pointer, val: GodotVariant) {.noconv.} = nimPtr: pointer, val: GodotVariant) {.noconv.} =
@ -397,7 +404,7 @@ template registerGodotField(classNameLit, classNameIdent, propNameLit,
typ: ord(variantType), typ: ord(variantType),
hint: hint, hint: hint,
hintString: hintStrGodot, hintString: hintStrGodot,
usage: GodotPropertyUsageFlags.usageIdent usage: usageExpr
) )
{.push warning[ProveInit]: on.} {.push warning[ProveInit]: on.}
when hasDefaultValue: when hasDefaultValue:
@ -504,12 +511,14 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
else: field.hintStr else: field.hintStr
let hint = if field.hint.isNil: "NIM" let hint = if field.hint.isNil: "NIM"
else: field.hint else: field.hint
let usage = if field.usage.isNil: "Default" let usage =
if field.usage.isNil:
newLit(ord(GodotPropertyUsage.Default) or
ord(GodotPropertyUsage.ScriptVariable))
else: field.usage else: field.usage
let hasDefaultValue = not field.defaultValue.isNil and let hasDefaultValue = not field.defaultValue.isNil and
field.defaultValue.kind != nnkEmpty field.defaultValue.kind != nnkEmpty
let hintIdent = ident(hint) let hintIdent = ident(hint)
let usageIdent = ident(usage)
let nimType = repr field.typ let nimType = repr field.typ
result.add(getAst( result.add(getAst(
registerGodotField(classNameLit, classNameIdent, registerGodotField(classNameLit, classNameIdent,
@ -517,7 +526,7 @@ proc genType(obj: ObjectDecl): NimNode {.compileTime.} =
ident(field.name), nimType, ident(field.name), nimType,
field.typ, genSym(nskProc, "setFunc"), field.typ, genSym(nskProc, "setFunc"),
genSym(nskProc, "getFunc"), genSym(nskProc, "getFunc"),
newStrLitNode(hintStr), hintIdent, usageIdent, newStrLitNode(hintStr), hintIdent, usage,
ident($hasDefaultValue), field.defaultValue))) ident($hasDefaultValue), field.defaultValue)))
# Register methods # Register methods

View file

@ -168,18 +168,22 @@ macro baseNativeType(T: typedesc): cstring =
rStr.strVal = baseT rStr.strVal = baseT
result = newNimNode(nnkCallStrLit).add(ident("cstring"), rStr) result = newNimNode(nnkCallStrLit).add(ident("cstring"), rStr)
macro isReference(T: typedesc): bool = proc inherits(t: NimNode, parent: string): bool {.compileTime.} =
var isRef = false var curT = t
var t = getType(T)
while true: while true:
let typeName = ($t[1][1]).split(':')[0] let typeName = ($curT[1][1]).split(':')[0]
if typeName == "Reference": if typeName == parent:
isRef = true return true
break
if typeName == "NimGodotObject": if typeName == "NimGodotObject":
break break
t = getType(t[1][1]) curT = getType(curT[1][1])
result = if isRef: ident("true")
macro isReference(T: typedesc): bool =
result = if inherits(getType(T), "Reference"): ident("true")
else: ident("false")
macro isResource(T: typedesc): bool =
result = if inherits(getType(T), "Resource"): ident("true")
else: ident("false") else: ident("false")
template registerClass*(T: typedesc; godotClassName: cstring, template registerClass*(T: typedesc; godotClassName: cstring,
@ -298,7 +302,7 @@ proc newRStrLit(s: string): NimNode {.compileTime.} =
static: static:
import strutils import strutils
macro toGodotName(T: typedesc): cstring = macro toGodotName(T: typedesc): string =
var godotName: string var godotName: string
if T is GodotString or T is string: if T is GodotString or T is string:
godotName = "String" godotName = "String"
@ -314,14 +318,17 @@ macro toGodotName(T: typedesc): cstring =
else: else:
nameStr nameStr
result = newLit(godotName)
macro asCString(s: static[string]): cstring =
result = newNimNode(nnkCallStrLit).add( result = newNimNode(nnkCallStrLit).add(
ident("cstring"), newRStrLit(godotName)) ident("cstring"), newRStrLit(s))
proc getSingleton*[T: NimGodotObject](): T = proc getSingleton*[T: NimGodotObject](): T =
## Returns singleton of type ``T``. Normally, this should not be used, ## Returns singleton of type ``T``. Normally, this should not be used,
## because `godotapigen <godotapigen.html>`_ wraps singleton methods so that ## because `godotapigen <godotapigen.html>`_ wraps singleton methods so that
## singleton objects don't have to be provided as parameters. ## singleton objects don't have to be provided as parameters.
const godotName = toGodotName(T) const godotName = asCString(toGodotName(T))
let singleton = getGodotSingleton(godotName) let singleton = getGodotSingleton(godotName)
if singleton.isNil: if singleton.isNil:
printError("Tried to get non-existing singleton of type " & $godotName) printError("Tried to get non-existing singleton of type " & $godotName)
@ -366,7 +373,7 @@ proc newOwnObj[T: NimGodotObject](name: cstring): T =
proc gdnew*[T: NimGodotObject](): T = proc gdnew*[T: NimGodotObject](): T =
## Instantiates new object of type ``T``. ## Instantiates new object of type ``T``.
const godotName = toGodotName(T) const godotName = asCString(toGodotName(T))
const objInfo = classRegistryStatic[godotName] const objInfo = classRegistryStatic[godotName]
result = when objInfo.isNative: result = when objInfo.isNative:
asNimGodotObject[T](getClassConstructor(godotName)()) asNimGodotObject[T](getClassConstructor(godotName)())
@ -432,7 +439,8 @@ proc godotObject*(nimObj: NimGodotObject): ptr GodotObject {.inline.} =
proc godotTypeInfo*(T: typedesc[NimGodotObject]): GodotTypeInfo {.inline.} = proc godotTypeInfo*(T: typedesc[NimGodotObject]): GodotTypeInfo {.inline.} =
GodotTypeInfo( GodotTypeInfo(
variantType: VariantType.Object, variantType: VariantType.Object,
hint: GodotPropertyHint.None, hint: when isResource(T): GodotPropertyHint.ResourceType
else: GodotPropertyHint.None,
hintStr: toGodotName(T) hintStr: toGodotName(T)
) )