WARNING! Access to this system is limited to authorised users only.
Unauthorised users may be subject to prosecution.
Unauthorised access to this system is a criminal offence under Australian law (Federal Crimes Act 1914 Part VIA)
It is a criminal offence to:
(1) Obtain access to data without authority. -Penalty 2 years imprisonment.
(2) Damage, delete, alter or insert data without authority. -Penalty 10 years imprisonment.
User activity is monitored and recorded. Anyone using this system expressly consents to such monitoring and recording.

Commit 7ea266ca authored by Kunshan Wang's avatar Kunshan Wang
Browse files

API-GEN: Generating stubs and calls.

TODO: Convert retvals back to C.
parent 1085c796
......@@ -4,7 +4,10 @@
mod api_c;
mod api_bridge;
mod api_impl;
mod __api_impl_stubs;
mod api_impl {
pub use __api_impl_stubs::*;
}
/// This is for testing. In the productional setting, replace them with the definitions from
/// `src/ast/src/ir.rs` and `src/ast/src/bundle.rs`
......
This diff is collapsed.
This diff is collapsed.
......@@ -462,7 +462,48 @@ _no_conversion = {
"MuCommInst",
} | _primitive_types.keys()
def generate_forwarder(st, meth) -> str:
_cty_to_high_level_ty = {
"MuVM*": "*mut CMuVM",
"MuCtx*": "*mut CMuCtx",
"MuIRBuilder*": "*mut CMuIRBuilder",
"MuBool": "bool",
"MuID": "MuID"
}
_cty_to_high_level_param_ty = {
**_cty_to_high_level_ty,
# If the micro VM wants a string, we make it convenient.
"MuName": "MuName",
"MuCString": "String",
}
_cty_to_high_level_ret_ty = {
**_cty_to_high_level_ty,
# If the client wants a string, it has to be kept permanent in the micro VM.
"MuName": "CMuCString",
}
def to_high_level_ret_ty(cty, rty):
assert cty != "void"
if cty in _cty_to_high_level_ret_ty:
hlt = _cty_to_high_level_ret_ty[cty]
if type_is_handle(cty):
hlt = "*mut APIMuValue"
elif type_is_node(cty):
hlt = "MuID"
else:
hlt = rty
return hlt
_special_self_style = {
}
def generate_forwarder_and_stub(st, meth) -> Tuple[str, str]:
st_name = st['name']
name = meth['name']
params = meth['params']
ret_ty = meth['ret_ty']
......@@ -487,9 +528,19 @@ def generate_forwarder(st, meth) -> str:
# 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)
ret_ty_text = "" if rust_ret_ty == None else " -> {}".format(rust_ret_ty)
# parameters and ret ty for the stub
stub_param_nts = []
stub_ret_ty = None if rust_ret_ty is None else to_high_level_ret_ty(ret_ty, rust_ret_ty)
stub_ret_ty_text = "" if stub_ret_ty == None else " -> {}".format(stub_ret_ty)
# preparing args
args = []
for param in params:
is_sz_param = param.get("is_sz_param", False)
......@@ -511,49 +562,87 @@ def generate_forwarder(st, meth) -> str:
assert type_is_explicit_ptr(cty)
converter = rpn # Do not convert out param.
# Keep as ptr so that Rust prog can store into it.
stub_rty = rty
elif array_sz_param != None:
assert type_is_explicit_ptr(cty)
c_base_ty = cty[:-1]
r_base_ty = to_rust_type(c_base_ty)
sz_cpn = array_sz_param
sz_rpn = avoid_rust_kws(sz_cpn)
if type_is_handle(c_base_ty):
converter = "from_handle_array({}, {})".format(
rpn, sz_rpn)
elif type_is_node(c_base_ty):
stub_rty = "Vec<&APIMuValue>"
elif type_is_node(c_base_ty) or c_base_ty == "MuID":
converter = "from_MuID_array({}, {})".format(
rpn, sz_rpn)
stub_rty = "Vec<MuID>"
else:
converter = "from_{}_array({}, {})".format(
c_base_ty, rpn, sz_rpn)
if c_base_ty == "MuCString":
stub_rty = "Vec<String>"
else:
stub_rty = "&[{}]".format(r_base_ty)
elif is_optional:
if type_is_handle(cty):
converter = "from_handle_optional({})".format(rpn)
stub_rty = "Option<&APIMuValue>"
elif type_is_node(cty):
converter = "from_MuID_optional({})".format(rpn)
stub_rty = "Option<MuID>"
elif cty in ["MuCString", "MuID"]:
converter = "from_{}_optional({})".format(cty, rpn)
stub_rty = "Option<{}>".format(_cty_to_high_level_param_ty[cty])
else:
raise Exception("Not expecting {} to be optional".format(cty))
else:
if cty.endswith("*"):
if cty.endswith("*"): # MuVM*, MuCtx*, MuIRBuilder*
c_base_ty = cty[:-1]
converter = "from_{}_ptr({})".format(c_base_ty, rpn)
stub_rty = to_rust_type(c_base_ty)
elif type_is_handle(cty):
converter = "from_handle({})".format(rpn)
stub_rty = "&APIMuValue"
elif type_is_node(cty):
converter = "from_MuID({})".format(rpn)
stub_rty = "MuID"
elif cty in _no_conversion:
converter = rpn # Do not convert primitive types.
else:
stub_rty = rty
elif cty in _cty_to_high_level_param_ty:
converter = "from_{}({})".format(cty, rpn)
stub_rty = _cty_to_high_level_param_ty[cty]
else:
raise Exception("Don't know how to handle param type {}".format(cty))
stmt = " let mut {} = {};".format(arg_name, converter)
stmts.append(stmt)
args.append(arg_name)
stub_param_nts.append("{}: {}".format(rpn, stub_rty))
# call
self_arg = args[0]
other_args = args[1:]
args_joined = ", ".join(other_args)
ret_val_bind = "" if rust_ret_ty is None else "let _rv = "
stmts.append(" unsafe {")
call_stmt = ' {}(*{}).{}({});'.format(
ret_val_bind, self_arg, name, args_joined)
stmts.append(call_stmt)
stmts.append(" }")
# TODO: return values
stmts.append(' panic!("not implemented")')
# forwarder
all_stmts = "\n".join(stmts)
bridge = """\
......@@ -562,7 +651,18 @@ extern fn {forwarder_name}({formal_param_list}){ret_ty_text} {{
}}
""".format(**locals())
return bridge
# stub
stub_param_nts[0] = _special_self_style.get((st_name, name), "&mut self")
stub_params_joined = ", ".join(stub_param_nts)
stub = """\
pub fn {name}({stub_params_joined}){stub_ret_ty_text} {{
panic!("Not implemented")
}}
""".format(**locals())
return bridge, stub
def generate_filler_stmt(st, meth) -> str:
name = meth['name']
......@@ -574,14 +674,14 @@ def generate_filler_stmt(st, meth) -> str:
return stmt
def visit_method(st, meth) -> Tuple[str, str, str]:
def visit_method(st, meth) -> Tuple[str, str, str, str]:
field_def = generate_struct_field(meth)
bridge = generate_forwarder(st, meth)
bridge, stub = generate_forwarder_and_stub(st, meth)
filler_stmt = generate_filler_stmt(st, meth)
return field_def, bridge, filler_stmt
return field_def, bridge, filler_stmt, stub
def visit_struct(st) -> Tuple[str, List[str], str]:
def visit_struct(st) -> Tuple[str, List[str], str, str]:
name = st["name"]
methods = st["methods"]
......@@ -590,12 +690,14 @@ def visit_struct(st) -> Tuple[str, List[str], str]:
field_defs = []
forwarders = []
filler_stmts = []
stubs = []
for meth in methods:
field_def, forwarder, filler_stmt = visit_method(st, meth)
field_def, forwarder, filler_stmt, stub = visit_method(st, meth)
field_defs.append(field_def)
forwarders.append(forwarder)
filler_stmts.append(filler_stmt)
stubs.append(stub)
fields = "\n".join(field_defs)
......@@ -613,32 +715,43 @@ pub struct {rust_name} {{
filler = """\
pub fn make_new_{name}(header: *mut c_void) -> *mut {rust_name} {{
let box = Box::new({rust_name} {{
let bx = Box::new({rust_name} {{
header: header,
{filler_stmts_joined}
}});
Box::into_raw(box)
Box::into_raw(bx)
}}
""".format(**locals())
stubs_joined = "\n".join(stubs)
stub_impl = """\
impl {name} {{
{stubs_joined}
}}
""".format(**locals())
return struct_def, forwarders, filler
return struct_def, forwarders, filler, stub_impl
def visit_structs(ast) -> Tuple[str, str, str]:
def visit_structs(ast) -> Tuple[str, str, str, str]:
struct_defs = []
forwarders = []
fillers = []
stub_impls = []
structs = ast["structs"]
for struct in structs:
struct_def, my_forwarders, filler = visit_struct(struct)
struct_def, my_forwarders, filler, stub_impl = visit_struct(struct)
struct_defs.append(struct_def)
forwarders.extend(my_forwarders)
fillers.append(filler)
stub_impls.append(stub_impl)
return "\n".join(struct_defs), "\n".join(forwarders), "\n".join(fillers)
return ("\n".join(struct_defs), "\n".join(forwarders), "\n".join(fillers),
"\n".join(stub_impls))
def visit_enums(ast):
const_defs = []
......@@ -674,7 +787,7 @@ def main():
types = visit_types(ast)
structs, forwarders, fillers = visit_structs(ast)
structs, forwarders, fillers, stub_impls = visit_structs(ast)
enums = visit_enums(ast)
......@@ -689,5 +802,9 @@ def main():
"Fillers": fillers,
})
injectable_files["__api_impl_stubs.rs"].inject_many({
"StubImpls": stub_impls,
})
if __name__=='__main__':
main()
......@@ -15,4 +15,6 @@ injectable_files = injecttools.make_injectable_file_set(_mu_impl_fast_root, [
["Types", "Structs", "Enums"]),
("api_bridge.rs", "src/vm/api/api_bridge.rs",
["Fillers", "Forwarders"]),
("__api_impl_stubs.rs", "src/vm/api/__api_impl_stubs.rs",
["StubImpls"]),
])
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