Commit ed8e3905 authored by Kunshan Wang's avatar Kunshan Wang

API-GEN: WIP: generating forwarders...

api_bridge.rs will convert low-level C valus to high-level Rust value,
such as CMuValue* -> [&APIMuValue].
parent 15a48ed7
// Invoke "python3 muapi2rustapi.py", and then
// invoke "rustc --test __api_gen_tester_mod.rs -o /tmp/api_gen_tester_junk"
// to test whether the generated code compiles.
mod api_c;
mod api_bridge;
mod api_impl;
This diff is collapsed.
...@@ -7,6 +7,7 @@ ...@@ -7,6 +7,7 @@
// This file is for interfacing with C, so it is not idiomatic Rust code. // This file is for interfacing with C, so it is not idiomatic Rust code.
#![allow(non_camel_case_types)] #![allow(non_camel_case_types)]
#![allow(dead_code)]
use std::os::raw::*; use std::os::raw::*;
......
mod api_old; //mod api_old;
mod api_new; //mod api_new;
mod api_c; mod api_c;
//mod api_bridge; // FIXME: Implement the bridges
mod api_impl;
pub use vm::api::api_new::*; //pub use vm::api::api_new::*;
...@@ -11,7 +11,7 @@ import sys ...@@ -11,7 +11,7 @@ import sys
import os, os.path import os, os.path
import re import re
import tempfile import tempfile
from typing import Tuple from typing import Tuple, List
import muapiparser import muapiparser
import injecttools import injecttools
...@@ -405,16 +405,20 @@ def generate_enum_converters(ast): ...@@ -405,16 +405,20 @@ def generate_enum_converters(ast):
return "\n".join(lines) return "\n".join(lines)
def generate_things(ast): __rust_kw_rewrite = {
stubs = generate_stubs(ast) "ref": "reff",
}
enums = generate_enums(ast) def avoid_rust_kws(name):
return __rust_kw_rewrite.get(name, name)
enum_convs = generate_enum_converters(ast) def filler_name_for(struct_name):
return "_fill__" + struct_name
return "\n".join([stubs, enums, enum_convs]) def forwarder_name_for(struct_name, meth_name):
return "_forwarder__" + struct_name + "__" + meth_name
def generate_method_field(meth): def generate_struct_field(meth) -> str:
name = meth['name'] name = meth['name']
params = meth['params'] params = meth['params']
ret_ty = meth['ret_ty'] ret_ty = meth['ret_ty']
...@@ -426,24 +430,123 @@ def generate_method_field(meth): ...@@ -426,24 +430,123 @@ def generate_method_field(meth):
rust_param_tys.append(rust_ty) rust_param_tys.append(rust_ty)
rust_ret_ty = None if ret_ty == "void" else to_rust_type(ret_ty) rust_ret_ty = None if ret_ty == "void" else to_rust_type(ret_ty)
ret_ty_text = "" if rust_ret_ty == None else "-> {}".format(rust_ret_ty)
field_def = " pub {}: fn({}){},".format( field_def = " pub {}: fn({}){},".format(
name, ", ".join(rust_param_tys), name, ", ".join(rust_param_tys), ret_ty_text)
"" if rust_ret_ty == None else "-> {}".format(rust_ret_ty))
return field_def return field_def
def generate_struct(st) -> str: def generate_forwarder(st, meth) -> str:
name = meth['name']
params = meth['params']
ret_ty = meth['ret_ty']
stmts = []
forwarder_name = forwarder_name_for(st["name"], name)
# formal parameter list
param_nts = []
for param in params:
cpn = param['name']
rpn = avoid_rust_kws(cpn)
cty = param['type']
rty = to_rust_type(cty)
param_nts.append("{}: {}".format(rpn, rty))
formal_param_list = ", ".join(param_nts)
# return type
rust_ret_ty = None if ret_ty == "void" else to_rust_type(ret_ty)
ret_ty_text = "" if rust_ret_ty == None else "-> {}".format(rust_ret_ty)
# preparing args
for param in params:
is_sz_param = param.get("is_sz_param", False)
if is_sz_param:
continue
cpn = param['name']
rpn = avoid_rust_kws(cpn)
cty = param['type']
rty = to_rust_type(cty)
arg_name = "_arg_" + rpn
array_sz_param = param.get("array_sz_param", None)
is_optional = param.get("is_optional", False)
if array_sz_param != None:
assert cty.endswith("*")
c_base_ty = cty[:-1]
sz_cpn = array_sz_param
sz_rpn = avoid_rust_kws(sz_cpn)
if type_is_ptr(c_base_ty):
converter = "from_ptr_array({}, {})".format(
rpn, sz_rpn)
elif type_is_node(c_base_ty):
converter = "from_MuID_array({}, {})".format(
rpn, sz_rpn)
else:
converter = "from_{}_array({}, {})".format(
c_base_ty, rpn, sz_rpn)
elif is_optional:
if type_is_ptr(cty):
converter = "from_ptr_optional({})".format(rpn)
elif type_is_node(cty):
converter = "from_node_optional({})".format(rpn)
elif cty in ["MuCString", "MuID"]:
converter = "from_{}_optional({})".format(cty, rpn)
else:
raise Exception("Not expecting {} to be optional".format(cty))
else:
if cty.endswith("*"):
c_base_ty = cty[:-1]
converter = "from_{}_ptr({})".format(c_base_ty, rpn)
else:
converter = "from_{}({})".format(cty, rpn)
stmt = " let mut {} = {};".format(arg_name, converter)
stmts.append(stmt)
# call
stmts.append(' panic!("not implemented")')
all_stmts = "\n".join(stmts)
bridge = """\
fn {forwarder_name}({formal_param_list}){ret_ty_text} {{
{all_stmts}
}}
""".format(**locals())
return bridge
def visit_method(st, meth) -> Tuple[str, str]:
field_def = generate_struct_field(meth)
bridge = generate_forwarder(st, meth)
return field_def, bridge
def visit_struct(st) -> Tuple[str, List[str]]:
name = st["name"] name = st["name"]
methods = st["methods"] methods = st["methods"]
rust_name = "C" + name rust_name = "C" + name
field_defs = [] field_defs = []
forwarders = []
for meth in methods: for meth in methods:
field_def = generate_method_field(meth) field_def, forwarder = visit_method(st, meth)
field_defs.append(field_def) field_defs.append(field_def)
forwarders.append(forwarder)
fields = "\n".join(field_defs) fields = "\n".join(field_defs)
...@@ -457,21 +560,23 @@ pub struct {rust_name} {{ ...@@ -457,21 +560,23 @@ pub struct {rust_name} {{
}} }}
""".format(**locals()) """.format(**locals())
return struct_def return struct_def, forwarders
def generate_structs(ast) -> str: def visit_structs(ast) -> Tuple[str, str]:
struct_defs = [] struct_defs = []
forwarders = []
structs = ast["structs"] structs = ast["structs"]
for struct in structs: for struct in structs:
struct_def = generate_struct(struct) struct_def, my_forwarders = visit_struct(struct)
struct_defs.append(struct_def) struct_defs.append(struct_def)
forwarders.extend(my_forwarders)
return "\n".join(struct_defs) return "\n".join(struct_defs), "\n".join(forwarders)
def generate_enums(ast): def visit_enums(ast):
const_defs = [] const_defs = []
for enum in ast['enums']: for enum in ast['enums']:
...@@ -484,7 +589,7 @@ def generate_enums(ast): ...@@ -484,7 +589,7 @@ def generate_enums(ast):
return "\n".join(const_defs) return "\n".join(const_defs)
def generate_types(ast): def visit_types(ast):
types = [] types = []
for c, p in ast["typedefs_order"]: for c, p in ast["typedefs_order"]:
if p.startswith("_"): if p.startswith("_"):
...@@ -503,11 +608,11 @@ def main(): ...@@ -503,11 +608,11 @@ def main():
ast = muapiparser.parse_muapi(src_text) ast = muapiparser.parse_muapi(src_text)
types = generate_types(ast) types = visit_types(ast)
structs = generate_structs(ast) structs, forwarders = visit_structs(ast)
enums = generate_enums(ast) enums = visit_enums(ast)
injectable_files["api_c.rs"].inject_many({ injectable_files["api_c.rs"].inject_many({
"Types": types, "Types": types,
...@@ -515,5 +620,9 @@ def main(): ...@@ -515,5 +620,9 @@ def main():
"Enums": enums, "Enums": enums,
}) })
injectable_files["api_bridge.rs"].inject_many({
"Forwarders": forwarders,
})
if __name__=='__main__': if __name__=='__main__':
main() main()
...@@ -13,4 +13,6 @@ muapi_h_path = os.path.join(_my_dir, "muapi.h") ...@@ -13,4 +13,6 @@ muapi_h_path = os.path.join(_my_dir, "muapi.h")
injectable_files = injecttools.make_injectable_file_set(_mu_impl_fast_root, [ injectable_files = injecttools.make_injectable_file_set(_mu_impl_fast_root, [
("api_c.rs", "src/vm/api/api_c.rs", ("api_c.rs", "src/vm/api/api_c.rs",
["Types", "Structs", "Enums"]), ["Types", "Structs", "Enums"]),
("api_bridge.rs", "src/vm/api/api_bridge.rs",
["Fillers", "Forwarders"]),
]) ])
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment