Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

added signal declaration #79

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 5 additions & 5 deletions godot/internal/godotinternaltypes.nim
Original file line number Diff line number Diff line change
Expand Up @@ -92,14 +92,14 @@ type
RID,
Object,
Dictionary,
Array, ## 20
Array,
# arrays
PoolByteArray,
PoolByteArray, ## 20
PoolIntArray,
PoolRealArray,
PoolStringArray,
PoolVector2Array, ## 25
PoolVector3Array,
PoolVector2Array,
PoolVector3Array, ## 25
PoolColorArray

VariantCallErrorType* {.size: sizeof(cint), pure.} = enum
Expand Down Expand Up @@ -291,7 +291,7 @@ type
methodData*: pointer
freeFunc*: proc (a2: pointer) {.noconv.}

GodotSignalArgument* {.bycopy.} = object
GodotSignalArgument* {.bycopy, packed.} = object
name*: GodotString
typ*: cint
hint*: GodotPropertyHint
Expand Down
108 changes: 105 additions & 3 deletions godot/nim/godotmacros.nim
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# Copyright 2018 Xored Software, Inc.

import macros, tables, typetraits, strutils, sets, sequtils, options, algorithm
import macros, strutils, sets, options
import godotinternal, internal/godotvariants
import godotnim, core/variants

Expand All @@ -23,13 +23,23 @@ type
nimNode: NimNode
isNoGodot: bool

SignalArgDecl = ref object
name: string
typ: NimNode

SignalDecl = ref object
name: string
args: seq[SignalArgDecl]

ObjectDecl = ref object
name: string
parentName: string
fields: seq[VarDecl]
signals: seq[SignalDecl]
methods: seq[MethodDecl]
isTool: bool


ParseError = object of Exception

include "internal/backwardcompat.inc.nim"
Expand Down Expand Up @@ -178,11 +188,34 @@ proc parseVarSection(decl: NimNode): seq[VarDecl] =
else:
result.add(identDefsToVarDecls(decl[i]))

proc parseSignal(sig: NimNode): SignalDecl =
let errorMsg = "Signal declaration must have this format: signal my_signal(param1: int, param2: string)"

if sig.kind != nnkCommand:
parseError(sig, errorMsg)
if not (sig[1].kind == nnkCall or sig[1].kind == nnkObjConstr):
parseError(sig, errorMsg)

result = SignalDecl(
name: $sig[1][0],
args: newSeq[SignalArgDecl]()
)

if sig[1].kind == nnkObjConstr:
for i in 1..<sig[1].len:
var nexpr = sig[1][i]
case nexpr.kind:
of nnkExprColonExpr:
result.args.add(SignalArgDecl(name: nexpr[0].repr, typ: nexpr[1]))
else:
parseError(sig, errorMsg)

proc parseType(ast: NimNode): ObjectDecl =
let definition = ast[0]
let body = ast[^1]
result = ObjectDecl(
fields: newSeq[VarDecl](),
signals: newSeq[SignalDecl](),
methods: newSeq[MethodDecl]()
)
(result.name, result.parentName) = extractNames(definition)
Expand All @@ -207,6 +240,10 @@ proc parseType(ast: NimNode): ObjectDecl =
of nnkProcDef, nnkMethodDef:
let meth = parseMethod(statement)
result.methods.add(meth)
of nnkCommand:
if statement[0].strVal == "signal":
let sig = parseSignal(statement)
result.signals.add(sig)
of nnkCommentStmt:
discard
else:
Expand Down Expand Up @@ -619,6 +656,60 @@ N_NOINLINE(void, setStackBottom)(void* thestackbottom);
argTypes, genSym(nskProc, "methFunc"),
hasReturnValue)))

template registerGodotSignalNoArgs(classNameLit, signalName) =
var godotSignal = GodotSignal(
name: signalName.toGodotString())
nativeScriptRegisterSignal(getNativeLibHandle(), classNameLit, godotSignal)

template initSignalArgumentParameters(argName, argTypeIdent, typeInfoIdent,
godotStringIdent, godotVariantIdent)=
var godotStringIdent = argName.toGodotString()
mixin godotTypeInfo
const typeInfoIdent = when compiles(godotTypeInfo(argTypeIdent)):
godotTypeInfo(argTypeIdent)
else: GodotTypeInfo()
var godotVariantIdent:GodotVariant
initGodotVariant(godotVariantIdent)

template deinitSignalArgumentParameters(godotStringIdent, godotVariantIdent)=
godotStringIdent.deinit()
godotVariantIdent.deinit()

template createSignalArgument(typeInfoIdent, godotStringIdent, godotVariantIdent) =
GodotSignalArgument(name: godotStringIdent,
typ: ord(typeInfoIdent.variantType),
defaultValue: godotVariantIdent)

template registerGodotSignal(classNameLit, signalName, argCount, sigArgs) =
var sigArgsArr = sigArgs
var godotSignal = GodotSignal(
name: signalName.toGodotString(),
numArgs: argCount,
args: addr(sigArgsArr[0]))
nativeScriptRegisterSignal(getNativeLibHandle(), classNameLit, godotSignal)

for sig in obj.signals:
if sig.args.len == 0:
result.add(getAst(
registerGodotSignalNoArgs(classNameLit, sig.name)))
else:
var sigArgsParams:seq[(NimNode, NimNode, NimNode)]
for arg in sig.args:
var p = (genSym(nskConst, "typeInfo"), genSym(nskVar, "godotString"), genSym(nskVar, "godotVariant"))
sigArgsParams.add p
result.add(getAst(
initSignalArgumentParameters(arg.name, arg.typ, p[0], p[1], p[2])))

var sigArgs = newNimNode(nnkBracket)
for p in sigArgsParams:
sigArgs.add(getAst(
createSignalArgument(p[0], p[1], p[2])))
result.add(getAst(
registerGodotSignal(classNameLit, sig.name, sig.args.len, sigArgs)))
for p in sigArgsParams:
result.add(getAst(
deinitSignalArgumentParameters(p[1], p[2])))

if isRef:
# add ref/unref for types inherited from Reference
template registerRefIncDec(classNameLit) =
Expand All @@ -640,7 +731,8 @@ macro gdobj*(ast: varargs[untyped]): untyped =
## Generates Godot type. Self-documenting example:
##
## .. code-block:: nim
## import godot, node
## import godot
## import godotapi / [node]
##
## gdobj MyObj of Node:
## var myField: int
Expand All @@ -653,17 +745,27 @@ macro gdobj*(ast: varargs[untyped]): untyped =
## ## ``hintStr`` depends on the value of ``hint``, its format is
## ## described in ``GodotPropertyHint`` documentation.
##
## signal my_signal(amount:int, message:string)
## ## Defines a signal ``my_signal`` with parameters
##
## method ready*() =
## ## 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)
##
## discard self.connect("my_signal", self, "on_my_signal")
## ## Connect to the my_signal and then emit it
## self.emit_signal("my_signal", 123.toVariant, "hello godot".toVariant)
##
## proc myProc*() {.gdExport.} =
## ## Exported to Godot as ``my_proc``
## print("myProc is called! Incrementing myField.")
## inc self.myField
##
## proc onMySignal(amount:int, message:string) {.gdExport.} =
## print("received my_signal " & amount & " " & message)
##
## If parent type is omitted, the type is inherited from ``Object``.
##
## ``tool`` specifier can be added to mark the type as an
Expand All @@ -681,4 +783,4 @@ macro gdobj*(ast: varargs[untyped]): untyped =
## `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)
result = genType(typeDef)
result = genType(typeDef)