233 lines
5.9 KiB
Python
233 lines
5.9 KiB
Python
#!/usr/bin/env python3
|
|
|
|
from argparse import ArgumentParser
|
|
import json
|
|
|
|
|
|
parser = ArgumentParser(prog='bindgen.py')
|
|
parser.add_argument('api')
|
|
parser.add_argument('spec')
|
|
parser.add_argument('-g', '--guest-stubs')
|
|
parser.add_argument('--guest-include')
|
|
parser.add_argument('--wasm3-bindings')
|
|
|
|
args = parser.parse_args()
|
|
|
|
apiName = args.api
|
|
spec = args.spec
|
|
guest_stubs_path = args.guest_stubs
|
|
if guest_stubs_path == None:
|
|
guest_stubs_path = 'bindgen_' + apiName + '_guest_stubs.c'
|
|
|
|
wasm3_bindings_path = args.wasm3_bindings
|
|
if wasm3_bindings_path == None:
|
|
wasm3_bindings_path = 'bindgen_' + apiName + '_wasm3_bindings.c'
|
|
|
|
host_bindings = open(wasm3_bindings_path, 'w')
|
|
guest_bindings = None
|
|
|
|
specFile = open(spec, 'r')
|
|
data = json.load(specFile)
|
|
|
|
def needs_arg_ptr_stub(decl):
|
|
res = (decl['ret']['tag'] == 'S')
|
|
for arg in decl['args']:
|
|
if arg['type']['tag'] == 'S':
|
|
res = True
|
|
return(res)
|
|
|
|
for decl in data:
|
|
if needs_arg_ptr_stub(decl):
|
|
guest_bindings = open(guest_stubs_path, 'w')
|
|
if args.guest_include != None:
|
|
s = '#include"' + args.guest_include + '"\n\n'
|
|
print(s, file=guest_bindings)
|
|
break
|
|
|
|
for decl in data:
|
|
|
|
name = decl['name']
|
|
cname = decl.get('cname', name)
|
|
|
|
if needs_arg_ptr_stub(decl):
|
|
argPtrStubName = name + '_argptr_stub'
|
|
# pointer arg stub declaration
|
|
s = ''
|
|
if decl['ret']['tag'] == 'S':
|
|
s += 'void'
|
|
else:
|
|
s += decl['ret']['name']
|
|
|
|
s += ' ORCA_IMPORT(' + argPtrStubName + ') ('
|
|
|
|
if decl['ret']['tag'] == 'S':
|
|
s += decl['ret']['name'] + '* __retArg'
|
|
if len(decl['args']) > 0:
|
|
s += ', '
|
|
|
|
for i, arg in enumerate(decl['args']):
|
|
s += arg['type']['name']
|
|
if arg['type']['tag'] == 'S':
|
|
s += '*'
|
|
s += ' ' + arg['name']
|
|
if i+1 < len(decl['args']):
|
|
s += ', '
|
|
s += ');\n\n'
|
|
|
|
# forward function to pointer arg stub declaration
|
|
s += decl['ret']['name'] + ' ' + name + '('
|
|
for i, arg in enumerate(decl['args']):
|
|
s += arg['type']['name'] + ' ' + arg['name']
|
|
if i+1 < len(decl['args']):
|
|
s += ', '
|
|
s += ')\n'
|
|
s += '{\n'
|
|
s += '\t'
|
|
if decl['ret']['tag'] == 'S':
|
|
s += decl['ret']['name'] + ' __ret;\n\t'
|
|
elif decl['ret']['tag'] != 'v':
|
|
s += decl['ret']['name']
|
|
s += ' __ret = '
|
|
s += argPtrStubName + '('
|
|
|
|
if decl['ret']['tag'] == 'S':
|
|
s += '&__ret'
|
|
if len(decl['args']) > 0:
|
|
s += ', '
|
|
|
|
for i, arg in enumerate(decl['args']):
|
|
if arg['type']['tag'] == 'S':
|
|
s += '&'
|
|
|
|
s += arg['name']
|
|
if i+1 < len(decl['args']):
|
|
s += ', '
|
|
s += ');\n'
|
|
if decl['ret']['tag'] != 'v':
|
|
s += '\treturn(__ret);\n'
|
|
s += '}\n\n'
|
|
|
|
print(s, file=guest_bindings)
|
|
|
|
# host-side stub
|
|
s = 'void ' + cname + '_stub(void* userdata, bb_module_instance* module, const bb_val* params, bb_val* returns)'
|
|
|
|
gen_stub = decl.get('gen_stub', True)
|
|
if gen_stub == False:
|
|
s += ';\n\n'
|
|
else:
|
|
s += '\n{\n\t'
|
|
retTag = decl['ret']['tag']
|
|
|
|
if retTag == 'i':
|
|
s += 'returns[0].i32_val = '
|
|
elif retTag == 'I':
|
|
s += 'returns[0].i64_val = '
|
|
elif retTag == 'f':
|
|
s += 'returns[0].f32_val = '
|
|
elif retTag == 'F':
|
|
s += 'returns[0].f64_val = '
|
|
elif retTag == 'S':
|
|
retTypeName = decl['ret']['name']
|
|
retTypeCName = decl['ret'].get('cname', retTypeName)
|
|
s += '*(' + retTypeCName + '*)(bb_module_instance_mem(module, returns[0].i32_val, sizeof(' + retTypeCName + '))) = '
|
|
|
|
s += cname + '('
|
|
|
|
firstArgIndex = 0
|
|
|
|
for i, arg in enumerate(decl['args']):
|
|
typeName = arg['type']['name']
|
|
typeCName = arg['type'].get('cname', typeName)
|
|
argTag = arg['type']['tag']
|
|
if argTag == 'i':
|
|
s += 'params[' + str(firstArgIndex + i) + '].i32_val'
|
|
elif argTag == 'I':
|
|
s += 'params[' + str(firstArgIndex + i) + '].i64_val'
|
|
elif argTag == 'f':
|
|
s += 'params[' + str(firstArgIndex + i) + '].f32_val'
|
|
elif argTag == 'F':
|
|
s += 'params[' + str(firstArgIndex + i) + '].f64_val'
|
|
elif argTag == 'p':
|
|
s += 'bb_module_instance_mem(module, params[' + str(firstArgIndex + i) + '].i32_val, sizeof(1))'
|
|
elif argTag == 'S':
|
|
s += '*(' + typeCName + '*)bb_module_instance_mem(module, params[' + str(firstArgIndex + i) + '].i32_val, sizeof(' + typeCName + '))'
|
|
else:
|
|
print('unrecognized type ' + typeCName + ' in procedure signature\n')
|
|
break
|
|
|
|
if i+1 < len(decl['args']):
|
|
s += ', '
|
|
|
|
s += ');\n}\n'
|
|
|
|
print(s, file=host_bindings)
|
|
|
|
# link function
|
|
s = 'int bindgen_link_' + apiName + '_api(bb_import_package* package)\n{\n'
|
|
|
|
def translateTag(tag):
|
|
if tag == 'i' or tag == 'p':
|
|
return 'BB_VALTYPE_I32'
|
|
elif tag == 'I':
|
|
return 'BB_VALTYPE_I64'
|
|
elif tag == 'f':
|
|
return 'BB_VALTYPE_F32'
|
|
elif tag == 'F':
|
|
return 'BB_VALTYPE_F64'
|
|
elif tag == 'v':
|
|
return ''
|
|
print('translateTag: unhandled tag "' + tag + '" with type ')
|
|
print(type(tag))
|
|
print('\n')
|
|
return ''
|
|
|
|
for decl in data:
|
|
name = decl['name']
|
|
cname = decl.get('cname', name)
|
|
|
|
if needs_arg_ptr_stub(decl):
|
|
name = name + '_argptr_stub'
|
|
|
|
retTag = decl['ret']['tag']
|
|
|
|
retType = ''
|
|
numReturns = 0
|
|
paramTypes = []
|
|
numParams = 0
|
|
if retTag == 'S':
|
|
paramTypes.append('BB_VALTYPE_I32')
|
|
numParams += 1
|
|
elif retTag != 'v': #no returns
|
|
retType = translateTag(retTag)
|
|
numReturns = 1
|
|
|
|
for arg in decl['args']:
|
|
tag = arg['type']['tag']
|
|
if tag == 'p' or tag == 'S':
|
|
tag = 'i'
|
|
paramTypes.append(translateTag(tag))
|
|
numParams += 1
|
|
|
|
# dummy values to avoid 0-length arrays in C
|
|
if numReturns == 0:
|
|
retType = 'BB_VALTYPE_I32'
|
|
|
|
if numParams == 0:
|
|
paramTypes.append('BB_VALTYPE_I32')
|
|
|
|
s += '\t{\n'
|
|
s += '\t\tbb_valtype params[] = {' + ', '.join(paramTypes) + '};\n'
|
|
s += '\t\tsize_t num_params = ' + str(len(paramTypes)) + ';\n'
|
|
s += '\t\tbb_valtype return_type = ' + retType + ';\n'
|
|
s += '\t\tsize_t num_returns = ' + str(numReturns) + ';\n'
|
|
|
|
s += '\t\tbb_error err = bb_import_package_add_function(package, ' + cname + '_stub, "' + name + '", params, num_params, &return_type, num_returns, NULL);\n'
|
|
s += '\t\tif(err != BB_ERROR_OK) { log_error("error: %s\\n", bb_error_str(err)); return(-1); }\n'
|
|
s += '\t}\n'
|
|
|
|
|
|
s += '\treturn(0);\n}\n'
|
|
|
|
print(s, file=host_bindings)
|