Skip to content

Commit

Permalink
Merge pull request #6 from guzba/master
Browse files Browse the repository at this point in the history
value obj constructors, default param values
  • Loading branch information
treeform authored Aug 28, 2021
2 parents 6f86beb + 7532acd commit f2fa846
Show file tree
Hide file tree
Showing 4 changed files with 174 additions and 69 deletions.
63 changes: 40 additions & 23 deletions src/bindy.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,13 @@ import bindy/internal, bindy/common, bindy/languages/nim, bindy/languages/python
proc toggleBasicOnly*() =
discard

macro exportConsts*(body: typed) =
for statement in body:
for sym in statement:
exportConstInternal(sym)
exportConstNim(sym)
exportConstPy(sym)

macro exportEnums*(body: typed) =
for statement in body:
for sym in statement:
Expand Down Expand Up @@ -52,29 +59,39 @@ macro exportProcs*(body: typed) =
statement
)

macro exportObjects*(body: typed) =
for statement in body:
for sym in statement:
let objImpl = sym.getImpl()[2]
if objImpl.kind != nnkObjectTy:
error(&"Unexpected export object impl kind {objImpl.kind}", statement)

let objType = sym.getType()
for property in objType[2]:
if not property.isExported:
error(&"Unexported property on {sym.repr}", objType)

let propertyTypeImpl = property.getTypeImpl()
if propertyTypeImpl.repr notin basicTypes:
if propertyTypeImpl.kind notin {nnkEnumTy, nnkObjectTy}:
error(
&"Object cannot export property of type {property[^2].repr}",
propertyTypeImpl
)

exportObjectInternal(sym)
exportObjectNim(sym)
exportObjectPy(sym)
macro exportObject*(sym, body: typed) =
let objImpl = sym.getImpl()[2]
if objImpl.kind != nnkObjectTy:
error(&"Unexpected export object impl kind {objImpl.kind}", sym)

if body[0].kind != nnkDiscardStmt:
error(
"First statement in export ref object must be a constructor call or discard",
body[0]
)

let constructor =
if body[0][0].len > 0:
body[0][0][0]
else:
nil

for identDefs in objImpl[2]:
for property in identDefs[0 .. ^3]:
if property.kind != nnkPostfix and property[0].repr != "*":
error(&"Unexported property on {sym.repr}", property)

let propertyTypeImpl = identDefs[^2].getTypeImpl()
if propertyTypeImpl.repr notin basicTypes:
if propertyTypeImpl.kind notin {nnkEnumTy, nnkObjectTy}:
error(
&"Object cannot export property of type {property[^2].repr}",
propertyTypeImpl
)

exportObjectInternal(sym, constructor)
exportObjectNim(sym, constructor)
exportObjectPy(sym, constructor)

macro exportRefObject*(
sym: typed, whitelist: static[openarray[string]], body: typed
Expand Down
28 changes: 24 additions & 4 deletions src/bindy/internal.nim
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,9 @@ const exportProcPragmas = "{.raises: [], cdecl, exportc, dynlib.}"

var internal {.compiletime.}: string

proc exportConstInternal*(sym: NimNode) =
discard

proc exportEnumInternal*(sym: NimNode) =
discard

Expand Down Expand Up @@ -56,8 +59,25 @@ proc exportProcInternal*(sym: NimNode, prefixes: openarray[NimNode] = []) =
internal.add "\n"
internal.add "\n"

proc exportObjectInternal*(sym: NimNode) =
discard
proc exportObjectInternal*(sym: NimNode, constructor: NimNode) =
let
objName = sym.repr
objNameSnaked = toSnakeCase(objName)

if constructor != nil:
let constructorType = constructor.getTypeInst()

internal.add &"proc $lib_{objNameSnaked}*("
for param in constructorType[0][1 .. ^1]:
internal.add &"{param[0].repr.split('`')[0]}: {param[1].repr}, "
internal.removeSuffix ", "
internal.add &"): {objName} {exportProcPragmas} =\n"
internal.add &" {constructor.repr}("
for param in constructorType[0][1 .. ^1]:
internal.add &"{param[0].repr.split('`')[0]}, "
internal.removeSuffix ", "
internal.add ")\n"
internal.add "\n"

proc exportRefObjectInternal*(
sym: NimNode, whitelist: openarray[string], constructor: NimNode
Expand Down Expand Up @@ -128,7 +148,7 @@ proc exportRefObjectInternal*(
internal.add &" {objNameSnaked}.{propertyName}[i] = v\n"
internal.add "\n"

internal.add &"proc {prefix}_remove*({objNameSnaked}: {objName}, i: int)"
internal.add &"proc {prefix}_delete*({objNameSnaked}: {objName}, i: int)"
internal.add &" {exportProcPragmas} =\n"
internal.add &" {objNameSnaked}.{propertyName}.delete(i)\n"
internal.add "\n"
Expand Down Expand Up @@ -177,7 +197,7 @@ proc generateSeqs(sym: NimNode) =
internal.add " s.s[i] = v\n"
internal.add "\n"

internal.add &"proc $lib_{seqNameSnaked}_remove*(s: {seqName}, i: int)"
internal.add &"proc $lib_{seqNameSnaked}_delete*(s: {seqName}, i: int)"
internal.add &" {exportProcPragmas}"
internal.add " =\n"
internal.add " s.s.delete(i)\n"
Expand Down
39 changes: 23 additions & 16 deletions src/bindy/languages/nim.nim
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,11 @@ proc convertImportToNim*(sym: NimNode): string =
elif sym.repr == "Rune":
result = ".Rune"

proc exportConstNim*(sym: NimNode) =
let impl = sym.getImpl()
types.add &"const {sym.repr}* = {impl.repr}\n"
types.add "\n"

proc exportEnumNim*(sym: NimNode) =
let symImpl = sym.getImpl()[2]

Expand Down Expand Up @@ -109,21 +114,23 @@ proc exportProcNim*(sym: NimNode, prefixes: openarray[NimNode] = []) =
procs.add " raise newException(PixieError, $takeError())\n"
procs.add "\n"

proc exportObjectNim*(sym: NimNode) =
let
objName = sym.repr
objType = sym.getType()
proc exportObjectNim*(sym: NimNode, constructor: NimNode) =
let objName = sym.repr

if objName in ["Vector2", "Matrix3", "Rectangle", "Color"]:
if objName in ["Vector2", "Matrix3", "Rect", "Color"]:
return

types.add &"type {objName}* = object\n"
for property in objType[2]:
types.add &" {property.repr}*: {property.getTypeInst().repr}\n"
for identDefs in sym.getImpl()[2][2]:
for property in identDefs[0 .. ^3]:
types.add &" {property.repr}: {identDefs[^2].repr}\n"
types.add "\n"

if constructor != nil:
exportProcNim(constructor)

proc genRefObject(objName: string) =
types.add &"type {objName}Obj* = object\n"
types.add &"type {objName}Obj = object\n"
types.add " reference: pointer\n"
types.add "\n"

Expand Down Expand Up @@ -187,14 +194,14 @@ proc genSeqProcs(objName, niceName, procPrefix, objSuffix, entryName: string) =
procs.add &" {procPrefix}_set(s{objSuffix}, i, v)\n"
procs.add "\n"

procs.add &"proc {procPrefix}_remove(s: {objName}, i: int)"
procs.add &"proc {procPrefix}_delete(s: {objName}, i: int)"
procs.add " {.importc: \""
procs.add &"{procPrefix}_remove"
procs.add &"{procPrefix}_delete"
procs.add "\", cdecl.}\n"
procs.add "\n"

procs.add &"proc remove*(s: {niceName}, i: int) =\n"
procs.add &" {procPrefix}_remove(s{objSuffix}, i)\n"
procs.add &"proc delete*(s: {niceName}, i: int) =\n"
procs.add &" {procPrefix}_delete(s{objSuffix}, i)\n"
procs.add "\n"

procs.add &"proc {procPrefix}_clear(s: {objName})"
Expand Down Expand Up @@ -325,13 +332,13 @@ import bumpy, chroma, unicode, vmath
export bumpy, chroma, unicode, vmath
when defined(windows):
const dllPath = "$lib.dll"
const libName = "$lib.dll"
elif defined(macosx):
const dllPath = "lib$lib.dll"
const libName = "lib$lib.dylib"
else:
const dllPath = "lib$lib.so"
const libName = "lib$lib.so"
{.push dynlib: dllPath.}
{.push dynlib: libName.}
type PixieError = object of ValueError
Expand Down
113 changes: 87 additions & 26 deletions src/bindy/languages/python.nim
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,11 @@ proc convertImportToPy*(sym: NimNode): string =
if sym.repr == "string":
result = ".decode(\"utf8\")"

proc exportConstPy*(sym: NimNode) =
let impl = sym.getImpl()
types.add &"{toCapSnakeCase(sym.repr)} = {impl.repr}\n"
types.add "\n"

proc exportEnumPy*(sym: NimNode) =
let symImpl = sym.getImpl()[2]

Expand All @@ -69,6 +74,12 @@ proc exportProcPy*(sym: NimNode, prefixes: openarray[NimNode] = []) =
apiProcName.add &"{toSnakeCase(prefix.getName())}_"
apiProcName.add &"{procNameSnaked}"

var defaults: seq[(string, NimNode)]
for identDefs in sym.getImpl()[3][1 .. ^1]:
let default = identDefs[^1]
for entry in identDefs[0 .. ^3]:
defaults.add((entry.repr, default))

if onClass:
types.add " def "
if prefixes.len > 1:
Expand All @@ -83,9 +94,39 @@ proc exportProcPy*(sym: NimNode, prefixes: openarray[NimNode] = []) =
types.add "self"
else:
types.add toSnakeCase(param[0].repr)
if defaults[i][1].kind != nnkEmpty:
types.add &" = None"
types.add &", "
types.removeSuffix ", "
types.add "):\n"
for i, param in procParams[0 .. ^1]:
if i == 0:
continue
if defaults[i][1].kind != nnkEmpty:
if onClass:
types.add " "
types.add &" if {toSnakeCase(param[0].repr)} is None:\n"
if onClass:
types.add " "
types.add &" {toSnakeCase(param[0].repr)} = "
case defaults[i][1].kind:
of nnkIntLit, nnkFloatLit:
types.add &"{defaults[i][1].repr}"
of nnkIdent:
if defaults[i][1].repr == "true":
types.add "True"
elif defaults[i][1].repr == "false":
types.add "False"
else:
types.add &"{toCapSnakeCase(defaults[i][1].repr)}"
else:
types.add &"{exportTypePy(param[1])}("
if defaults[i][1].kind == nnkCall:
for d in defaults[i][1][1 .. ^1]:
types.add &"{d.repr}, "
types.removeSuffix ", "
types.add ")"
types.add "\n"
if onClass:
types.add " "
types.add " "
Expand Down Expand Up @@ -127,36 +168,56 @@ proc exportProcPy*(sym: NimNode, prefixes: openarray[NimNode] = []) =
procs.add &"dll.$lib_{apiProcName}.restype = {exportTypePy(procReturn)}\n"
procs.add "\n"

proc exportObjectPy*(sym: NimNode) =
let
objName = sym.repr
objType = sym.getType()
proc exportObjectPy*(sym: NimNode, constructor: NimNode) =
let objName = sym.repr

types.add &"class {objName}(Structure):\n"
types.add " _fields_ = [\n"
for property in objType[2]:
types.add &" (\"{toSnakeCase(property.repr)}\""
types.add ", "
types.add &"{exportTypePy(property.getTypeInst())}),\n"
for identDefs in sym.getImpl()[2][2]:
for property in identDefs[0 .. ^3]:
types.add &" (\"{toSnakeCase(property[1].repr)}\""
types.add ", "
types.add &"{exportTypePy(identDefs[^2])}),\n"
types.removeSuffix ",\n"
types.add "\n"
types.add " ]\n"
types.add "\n"

types.add " def __init__(self, "
for property in objType[2]:
types.add &"{toSnakeCase(property.repr)}, "
types.removeSuffix ", "
types.add "):\n"
for property in objType[2]:
types.add " "
types.add &"self.{toSnakeCase(property.repr)} = {toSnakeCase(property.repr)}\n"
types.add "\n"
if constructor != nil:
let
constructorType = constructor.getTypeInst()
constructorParams = constructorType[0][1 .. ^1]
types.add " def __init__(self, "
for param in constructorParams:
types.add &"{toSnakeCase(param[0].repr)}"
types.add ", "
types.removeSuffix ", "
types.add "):\n"
types.add &" tmp = dll.$lib_{toSnakeCase(objName)}("
for param in constructorParams:
types.add &"{toSnakeCase(param[0].repr)}"
types.add ", "
types.removeSuffix ", "
types.add ")\n"
for identDefs in sym.getImpl()[2][2]:
for property in identDefs[0 .. ^3]:
types.add &" self.{toSnakeCase(property[1].repr)} = "
types.add &"tmp.{toSnakeCase(property[1].repr)}\n"
types.add "\n"

procs.add &"dll.$lib_{toSnakeCase(objName)}.argtypes = ["
for param in constructorParams:
procs.add &"{exportTypePy(param[1])}, "
procs.removeSuffix ", "
procs.add "]\n"
procs.add &"dll.$lib_{toSnakeCase(objName)}.restype = {objName}\n"
procs.add "\n"

types.add " def __eq__(self, obj):\n"
types.add " "
for property in objType[2]:
types.add &"self.{toSnakeCase(property.repr)} == obj.{toSnakeCase(property.repr)} and "
for identDefs in sym.getImpl()[2][2]:
for property in identDefs[0 .. ^3]:
types.add &"self.{toSnakeCase(property[1].repr)} == obj.{toSnakeCase(property[1].repr)} and "
types.removeSuffix " and "
types.add "\n"
types.add "\n"
Expand Down Expand Up @@ -200,7 +261,7 @@ proc genSeqProcs(objName, procPrefix, selfSuffix: string, entryType: NimNode) =
types.add "\n"

types.add &"{baseIndent}def __delitem__(self, index):\n"
types.add &"{baseIndent} dll.{procPrefix}_remove(self{selfSuffix}, index)\n"
types.add &"{baseIndent} dll.{procPrefix}_delete(self{selfSuffix}, index)\n"
types.add "\n"

types.add &"{baseIndent}def append(self, value):\n"
Expand All @@ -223,8 +284,8 @@ proc genSeqProcs(objName, procPrefix, selfSuffix: string, entryType: NimNode) =
procs.add &"dll.{procPrefix}_set.restype = None\n"
procs.add "\n"

procs.add &"dll.{procPrefix}_remove.argtypes = [{objName}, c_longlong]\n"
procs.add &"dll.{procPrefix}_remove.restype = None\n"
procs.add &"dll.{procPrefix}_delete.argtypes = [{objName}, c_longlong]\n"
procs.add &"dll.{procPrefix}_delete.restype = None\n"
procs.add "\n"

procs.add &"dll.{procPrefix}_add.argtypes = [{objName}, {exportTypePy(entryType)}]\n"
Expand Down Expand Up @@ -370,12 +431,12 @@ src_path = Path(__file__).resolve()
src_dir = str(src_path.parent)
if sys.platform == "win32":
dllPath = "pixie.dll"
libName = "pixie.dll"
elif sys.platform == "darwin":
dllPath = "libpixie.dylib"
libName = "libpixie.dylib"
else:
dllPath = "libpixie.so"
dll = cdll.LoadLibrary(src_dir + "/" + dllPath)
libName = "libpixie.so"
dll = cdll.LoadLibrary(src_dir + "/" + libName)
class PixieError(Exception):
pass
Expand Down

0 comments on commit f2fa846

Please sign in to comment.