improve stub generator by @ashleysommer

This commit is contained in:
Richard Smith 2023-12-22 04:46:46 +00:00
parent 594fe4d41a
commit d9acf89784
5 changed files with 1279 additions and 2618 deletions

View file

@ -12,13 +12,23 @@
# #
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 # SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
from pathlib import Path
from raylib import rl, ffi from raylib import rl, ffi
from inspect import ismethod, getmembers, isbuiltin from inspect import ismethod, getmembers, isbuiltin
import inflection, sys, json import inflection, sys, json
f = open("raylib.json", "r") known_functions = {}
js = json.load(f) known_structs = {}
for filename in (Path("raylib.json"), Path("raymath.json"), Path("rlgl.json"), Path("raygui.json"), Path("physac.json")):
f = open(filename, "r")
js = json.load(f)
for fn in js["functions"]:
if fn["name"] not in known_functions:
known_functions[fn["name"]] = fn
for st in js["structs"]:
if st["name"] not in known_structs:
known_structs[st["name"]] = st
def ctype_to_python_type(t): def ctype_to_python_type(t):
if t == '_Bool': if t == '_Bool':
@ -51,16 +61,17 @@ def pointer(struct):
... ...
""") """)
# These words can be used for c arg names, but not in python
reserved_words = ("in", "list", "tuple", "set", "dict", "from", "range", "min", "max", "any", "all", "len")
for name, attr in getmembers(rl): for name, attr in getmembers(rl):
uname = inflection.underscore(name).replace('3_d', '_3d').replace('2_d', '_2d') uname = inflection.underscore(name).replace('3_d', '_3d').replace('2_d', '_2d')
if isbuiltin(attr) or str(type(attr)) == "<class '_cffi_backend.__FFIFunctionWrapper'>": if isbuiltin(attr) or str(type(attr)) == "<class '_cffi_backend.__FFIFunctionWrapper'>":
json_array = [x for x in js['functions'] if x['name'] == name] json_object = known_functions.get(name, None)
json_object = {} if json_object is None:
if len(json_array) > 0: # this is _not_ an exported function from raylib, raymath, rlgl raygui or physac
json_object = json_array[0] # so we don't want it in the pyray API
continue
sig = "" sig = ""
for i, arg in enumerate(ffi.typeof(attr).args): for i, arg in enumerate(ffi.typeof(attr).args):
param_name = arg.cname.replace("struct", "").replace("char *", "str").replace("*", param_name = arg.cname.replace("struct", "").replace("char *", "str").replace("*",
@ -69,7 +80,9 @@ for name, attr in getmembers(rl):
if 'params' in json_object: if 'params' in json_object:
p = json_object['params'] p = json_object['params']
param_name = list(p)[i]['name'] param_name = list(p)[i]['name']
# don't use a python reserved word:
if param_name in reserved_words:
param_name = param_name + "_" + str(i)
param_type = ctype_to_python_type(arg.cname) param_type = ctype_to_python_type(arg.cname)
sig += f"{param_name}: {param_type}," sig += f"{param_name}: {param_type},"
@ -95,11 +108,13 @@ for name, attr in getmembers(rl):
for struct in ffi.list_types()[0]: for struct in ffi.list_types()[0]:
print("processing", struct, file=sys.stderr) print("processing", struct, file=sys.stderr)
# json_array = [x for x in js['structs'] if x['name'] == name]
# json_object = {}
# if len(json_array) > 0:
# json_object = json_array[0]
if ffi.typeof(struct).kind == "struct": if ffi.typeof(struct).kind == "struct":
json_object = known_structs.get(struct, None)
if json_object is None:
# this is _not_ an exported struct from raylib, raymath, rlgl raygui or physac
# so we don't want it in the pyray API
continue
if ffi.typeof(struct).fields is None: if ffi.typeof(struct).fields is None:
print("weird empty struct, skipping "+struct, file=sys.stderr) print("weird empty struct, skipping "+struct, file=sys.stderr)
continue continue

View file

@ -12,14 +12,22 @@
# #
# SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0 # SPDX-License-Identifier: EPL-2.0 OR GPL-2.0 WITH Classpath-exception-2.0
from pathlib import Path
from raylib import rl, ffi from raylib import rl, ffi
from inspect import ismethod, getmembers, isbuiltin from inspect import ismethod, getmembers, isbuiltin
import inflection, sys, json import inflection, sys, json
f = open("raylib.json", "r") known_functions = {}
js = json.load(f) known_structs = {}
for filename in (Path("raylib.json"), Path("raymath.json"), Path("rlgl.json"), Path("raygui.json"), Path("physac.json"), Path("glfw3.json")):
f = open(filename, "r")
js = json.load(f)
for fn in js["functions"]:
if fn["name"] not in known_functions:
known_functions[fn["name"]] = fn
for st in js["structs"]:
if st["name"] not in known_structs:
known_structs[st["name"]] = st
@ -59,22 +67,28 @@ class struct: ...
""") """)
# These words can be used for c arg names, but not in python
reserved_words = ("in", "list", "tuple", "set", "dict", "from", "range", "min", "max", "any", "all", "len")
for name, attr in getmembers(rl): for name, attr in getmembers(rl):
uname = name uname = name
if isbuiltin(attr) or str(type(attr)) == "<class '_cffi_backend.__FFIFunctionWrapper'>": if isbuiltin(attr) or str(type(attr)) == "<class '_cffi_backend.__FFIFunctionWrapper'>":
json_array = [x for x in js['functions'] if x['name'] == name] json_object = known_functions.get(name, {})
json_object = {}
if len(json_array) > 0:
json_object = json_array[0]
sig = "" sig = ""
for i, arg in enumerate(ffi.typeof(attr).args): for i, arg in enumerate(ffi.typeof(attr).args):
param_name = arg.cname.replace("struct", "").replace("char *", "str").replace("*", if ")(" in arg.cname:
"_pointer").replace( # fn signature in arg types
" ", "")+"_"+str(i) param_name = str(arg.cname).split("(", 1)[0] + "_callback_" + str(i)
else:
param_name = arg.cname.replace("struct", "").replace("char *", "str").replace("*",
"_pointer").replace(" ", "")+"_"+str(i)
if 'params' in json_object: if 'params' in json_object:
p = json_object['params'] p = json_object['params']
#print("param_name: ", param_name, "i", i, "params: ",p,file=sys.stderr) #print("param_name: ", param_name, "i", i, "params: ",p,file=sys.stderr)
param_name = list(p)[i]['name'] param_name = list(p)[i]['name']
# don't use a python reserved word:
if param_name in reserved_words:
param_name = param_name+"_"+str(i)
param_type = ctype_to_python_type(arg.cname) param_type = ctype_to_python_type(arg.cname)
sig += f"{param_name}: {param_type}," sig += f"{param_name}: {param_type},"

View file

@ -23,9 +23,13 @@ gcc raylib-c/parser/raylib_parser.c
echo "running parser" echo "running parser"
./a.out -i raygui/src/raygui.h -o raygui.json -f JSON ./a.out -i raygui/src/raygui.h -d RAYGUIAPI -o raygui.json -f JSON
./a.out -i physac/src/physac.h -o physac.json -f JSON ./a.out -i physac/src/physac.h -d PHYSACDEF -o physac.json -f JSON
./a.out -i raylib-c/src/raylib.h -o raylib.json -f JSON ./a.out -i raylib-c/src/raylib.h -o raylib.json -f JSON
./a.out -i raylib-c/src/rlgl.h -o rlgl.json -f JSON
./a.out -i raylib-c/src/raymath.h -d RMAPI -o raymath.json -f JSON
./a.out -i raylib-c/src/external/glfw/include/GLFW/glfw3.h -d GLFWAPI -o glfw3.json -f JSON
sed -i "s|\/\*.*,$|,|g" glfw3.json
echo "building raylib_python_cffi" echo "building raylib_python_cffi"
@ -42,6 +46,7 @@ echo "creating pyi files"
python3 create_stub_pyray.py > pyray/__init__.pyi python3 create_stub_pyray.py > pyray/__init__.pyi
python3 create_enums.py >> pyray/__init__.pyi python3 create_enums.py >> pyray/__init__.pyi
cat raylib/colors.py >> pyray/__init__.pyi cat raylib/colors.py >> pyray/__init__.pyi
python3 create_stub_static.py >raylib/__init__.pyi python3 create_stub_static.py >raylib/__init__.pyi
cat raylib/colors.py >> raylib/__init__.pyi cat raylib/colors.py >> raylib/__init__.pyi

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff