diff options
Diffstat (limited to 'fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/utils/bindgen.py')
-rw-r--r-- | fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/utils/bindgen.py | 386 |
1 files changed, 386 insertions, 0 deletions
diff --git a/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/utils/bindgen.py b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/utils/bindgen.py new file mode 100644 index 000000000..a505404d5 --- /dev/null +++ b/fluent-bit/lib/wasm-micro-runtime-WAMR-1.2.2/language-bindings/python/wasm-c-api/utils/bindgen.py @@ -0,0 +1,386 @@ +# -*- coding: utf-8 -*- +#!/usr/bin/env python3 +# +# Copyright (C) 2019 Intel Corporation. All rights reserved. +# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +# +# pylint: disable=missing-class-docstring +# pylint: disable=missing-function-docstring +# pylint: disable=missing-module-docstring + +""" +- Need to run *download_wamr.py* firstly. +- Parse *./wasm-micro-runtime/core/iwasm/include/wasm_c_api.h* and generate + *wamr/binding.py* +""" +import os +import pathlib +import shutil +import sys + +from pycparser import c_ast, parse_file + +WASM_C_API_HEADER = "core/iwasm/include/wasm_c_api.h" +BINDING_PATH = "language-bindings/python/wamr/wasmcapi/binding.py" +# 4 spaces as default indent +INDENT = " " + +IGNORE_SYMOLS = ( + "wasm_engine_new_with_args", + "wasm_valkind_is_num", + "wasm_valkind_is_ref", + "wasm_valtype_is_num", + "wasm_valtype_is_ref", + "wasm_valtype_new_i32", + "wasm_valtype_new_i64", + "wasm_valtype_new_f32", + "wasm_valtype_new_f64", + "wasm_valtype_new_anyref", + "wasm_valtype_new_funcref", + "wasm_functype_new_0_0", + "wasm_functype_new_0_0", + "wasm_functype_new_1_0", + "wasm_functype_new_2_0", + "wasm_functype_new_3_0", + "wasm_functype_new_0_1", + "wasm_functype_new_1_1", + "wasm_functype_new_2_1", + "wasm_functype_new_3_1", + "wasm_functype_new_0_2", + "wasm_functype_new_1_2", + "wasm_functype_new_2_2", + "wasm_functype_new_3_2", + "wasm_val_init_ptr", + "wasm_val_ptr", + "wasm_val_t", + "wasm_ref_t", + "wasm_name_new_from_string", + "wasm_name_new_from_string_nt", +) + + +class Visitor(c_ast.NodeVisitor): + def __init__(self): + self.type_map = { + "_Bool": "c_bool", + "byte_t": "c_ubyte", + "char": "c_char", + "errno_t": "c_int", + "int": "c_int", + "long": "c_long", + "size_t": "c_size_t", + "uint32_t": "c_uint32", + "uint8_t": "c_uint8", + "void": "None", + } + self.ret = ( + "# -*- coding: utf-8 -*-\n" + "#!/usr/bin/env python3\n" + "#\n" + "# Copyright (C) 2019 Intel Corporation. All rights reserved.\n" + "# SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception\n" + "#\n" + "#It is a generated file. DO NOT EDIT.\n" + "#\n" + "from ctypes import *\n" + "\n" + "from .ffi import dereference, libiwasm, wasm_ref_t, wasm_val_t\n" + "\n" + "\n" + ) + + def get_type_name(self, c_type): + if isinstance(c_type, c_ast.TypeDecl): + return self.get_type_name(c_type.type) + elif isinstance(c_type, c_ast.PtrDecl): + pointed_type = self.get_type_name(c_type.type) + + if isinstance(c_type.type, c_ast.FuncDecl): + # CFUCNTYPE is a pointer of function + return pointed_type + + if "None" == pointed_type: + return "c_void_p" + + return f"POINTER({pointed_type})" + + elif isinstance(c_type, c_ast.ArrayDecl): + return f"POINTER({self.get_type_name(c_type.type)})" + elif isinstance(c_type, c_ast.IdentifierType): + if len(c_type.names) > 1: + raise RuntimeError(f"unexpected type with a long names: {c_type}") + + type_name = c_type.names[0] + + if type_name.startswith("wasm_"): + return type_name + + if not type_name in self.type_map: + raise RuntimeError(f"a new type should be in type_map: {type_name}") + + return self.type_map.get(type_name) + elif isinstance(c_type, c_ast.Union): + if not c_type.name: + raise RuntimeError(f"found an anonymous union {c_type}") + + return c_type.name + elif isinstance(c_type, c_ast.Struct): + if not c_type.name: + raise RuntimeError(f"found an anonymous union {c_type}") + + return c_type.name + elif isinstance(c_type, c_ast.FuncDecl): + content = "CFUNCTYPE(" + if isinstance(c_type.type, c_ast.PtrDecl): + # there is a bug in CFUNCTYPE if the result type is a pointer + content += "c_void_p" + else: + content += f"{self.get_type_name(c_type.type)}" + content += f",{self.get_type_name(c_type.args)}" if c_type.args else "" + content += ")" + return content + elif isinstance(c_type, c_ast.Decl): + return self.get_type_name(c_type.type) + elif isinstance(c_type, c_ast.ParamList): + content = ",".join( + [self.get_type_name(param.type) for param in c_type.params] + ) + return content + else: + raise RuntimeError(f"unexpected type: {c_type.show()}") + + def visit_Struct(self, node): + # pylint: disable=invalid-name + def gen_fields(info, indent): + content = "" + for k, v in info.items(): + content += f'{indent}("{k}", {v}),\n' + return content[:-1] + + def gen_equal(info, indent): + content = f"{indent}return" + for k, v in info.items(): + # not compare pointer value in __eq__ + if v.startswith("POINTER") or v.startswith("c_void_p"): + continue + + content += f" self.{k} == other.{k} and" + return content[:-4] + + def gen_repr(info, indent): + content = f'{indent}return f"{{{{' + for k, _ in info.items(): + content += f"{k}={{self.{k}}}, " + content = content[:-2] + '}}"' + return content + + def gen_vector_repr(info, indent): + content = f'{indent}ret = ""\n' + content += f"{indent}for i in range(self.num_elems):\n" + + if 1 == info["data"].count("POINTER"): + # pointer + content += f"{2*indent}ret += str(self.data[i])\n" + else: + # pointer of pointer + content += f"{2*indent}ret += str(dereference(self.data[i]))\n" + + content += f'{2*indent}ret += " "\n' + content += f"{indent}return ret\n" + return content + + if not node.name or not node.name.lower().startswith("wasm"): + return + + if node.name in IGNORE_SYMOLS: + return + + name = node.name + + info = {} + if node.decls: + for decl in node.decls: + info[decl.name] = self.get_type_name(decl.type) + + if info: + self.ret += ( + f"class {name}(Structure):\n" + f"{INDENT}_fields_ = [\n" + f"{gen_fields(info, INDENT*2)}\n" + f"{INDENT}]\n" + f"\n" + f"{INDENT}def __eq__(self, other):\n" + f"{INDENT*2}if not isinstance(other, {name}):\n" + f"{INDENT*3}return False\n" + f"{gen_equal(info, INDENT*2)}\n" + f"\n" + f"{INDENT}def __repr__(self):\n" + ) + self.ret += ( + f"{gen_vector_repr(info, INDENT*2)}\n" + if name.endswith("_vec_t") + else f"{gen_repr(info, INDENT*2)}\n" + ) + self.ret += "\n" + + else: + self.ret += f"class {name}(Structure):\n{INDENT}pass\n" + + self.ret += "\n" + + def visit_Union(self, node): + # pylint: disable=invalid-name + print(f"Union: {node.show()}") + + def visit_Typedef(self, node): + # pylint: disable=invalid-name + # system defined + if not node.name: + return + + if not node.name.startswith("wasm_"): + return + + if node.name in IGNORE_SYMOLS: + return + + self.visit(node.type) + + if node.name == self.get_type_name(node.type): + return + else: + self.ret += f"{node.name} = {self.get_type_name(node.type)}\n" + self.ret += "\n" + + def visit_FuncDecl(self, node): + # pylint: disable=invalid-name + restype = self.get_type_name(node.type) + + if isinstance(node.type, c_ast.TypeDecl): + func_name = node.type.declname + elif isinstance(node.type, c_ast.PtrDecl): + func_name = node.type.type.declname + else: + raise RuntimeError(f"unexpected type in FuncDecl: {type}") + + if not func_name.startswith("wasm_") or func_name.endswith("_t"): + return + + if func_name in IGNORE_SYMOLS: + return + + params_len = 0 + for arg in node.args.params: + # ignore void but not void* + if isinstance(arg.type, c_ast.TypeDecl): + type_name = self.get_type_name(arg.type) + if "None" == type_name: + continue + + params_len += 1 + + args = ( + "" if not params_len else ",".join([f"arg{i}" for i in range(params_len)]) + ) + argtypes = f"[{self.get_type_name(node.args)}]" if params_len else "None" + + self.ret += ( + f"def {func_name}({args}):\n" + f"{INDENT}_{func_name} = libiwasm.{func_name}\n" + f"{INDENT}_{func_name}.restype = {restype}\n" + f"{INDENT}_{func_name}.argtypes = {argtypes}\n" + f"{INDENT}return _{func_name}({args})\n" + ) + self.ret += "\n" + + def visit_Enum(self, node): + # pylint: disable=invalid-name + elem_value = 0 + # generate enum elementes directly as consts with values + for i, elem in enumerate(node.values.enumerators): + self.ret += f"{elem.name}" + + if elem.value: + elem_value = int(elem.value.value) + else: + if 0 == i: + elem_value = 0 + else: + elem_value += 1 + + self.ret += f" = {elem_value}\n" + + self.ret += "\n" + + +def preflight_check(workspace): + wamr_repo = workspace + file_check_list = [ + wamr_repo.exists(), + wamr_repo.joinpath(WASM_C_API_HEADER).exists(), + ] + + if not all(file_check_list): + print( + "please run utils/download_wamr.py to download the repo, or re-download the repo" + ) + return False + + if not shutil.which("gcc"): + print("please install gcc") + return False + + return True + + +def do_parse(workspace): + filename = workspace.joinpath(WASM_C_API_HEADER) + filename = str(filename) + + ast = parse_file( + filename, + use_cpp=True, + cpp_path="gcc", + cpp_args=[ + "-E", + "-D__attribute__(x)=", + "-D__asm__(x)=", + "-D__asm(x)=", + "-D__builtin_va_list=int", + "-D__extension__=", + "-D__inline__=", + "-D__restrict=", + "-D__restrict__=", + "-D_Static_assert(x, y)=", + "-D__signed=", + "-D__volatile__(x)=", + "-Dstatic_assert(x, y)=", + ], + ) + + ast_visitor = Visitor() + ast_visitor.visit(ast) + return ast_visitor.ret + + +def main(): + current_file = pathlib.Path(__file__) + if current_file.is_symlink(): + current_file = pathlib.Path(os.readlink(current_file)) + + current_dir = current_file.parent.resolve() + root_dir = current_dir.joinpath("../../../..").resolve() + + if not preflight_check(root_dir): + return False + + wamr_repo = root_dir + binding_file_path = root_dir.joinpath(BINDING_PATH) + with open(binding_file_path, "wt", encoding="utf-8") as binding_file: + binding_file.write(do_parse(wamr_repo)) + + return True + + +if __name__ == "__main__": + sys.exit(0 if main() else 1) |