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.

To protect your data, the CISO officer has suggested users to enable 2FA as soon as possible.
Currently 2.7% of users enabled 2FA.

Commit 1bb3e984 authored by qinsoon's avatar qinsoon
Browse files

[wip] working on api based on spec revision:

parent d7f104ea
use ast::ptr::*;
use ast::ir::*;
use ast::types::*;
use vm::api;
use vm::VM;
use vm::bundle::*;
use std::mem;
use std::os::raw;
use std::collections::HashMap;
use std::sync::Arc;
macro_rules! unimplemented_api {
() => {
// cast fn to usize before transmute, see: https://github.com/rust-lang/rust/issues/19925
unsafe {mem::transmute(unimplemented_api as usize)}
macro_rules! api {
($func: expr) => {
unsafe {mem::transmute($func as usize)}
pub fn unimplemented_api() {
pub struct MuVM {
// void* header
internal: Arc<VM>,
pub new_context: fn (mvm: *mut MuVM) -> *mut MuCtx,
id_of: fn (mvm: *const MuVM, name: MuName) -> MuID,
name_of : fn (mvm: *const MuVM, id: MuID) -> MuName,
// set_trap_handler: fn(mvm: *mut MuVM, trap_handler: MuTrapHandler, user_data: MuCPtr)
impl MuVM {
pub fn new() -> *mut MuVM {
let vm = Box::new(MuVM {
internal: Arc::new(VM::new()),
new_context: api!(MuVM::new_context),
id_of: api!(MuVM::id_of),
name_of: api!(MuVM::name_of)
pub fn new_context(&mut self) -> *mut MuCtx {
let ctx = Box::new(MuCtx::new(self.internal.clone()));
pub fn id_of(&self, name: &str) -> MuID {
pub fn name_of(&self, id: MuID) -> MuName {
pub struct MuCtx {
// void* header - current not planed to use this
internal: Box<MuCtxInternal>,
struct MuCtxInternal {
vm: Arc<VM>,
cur_bundles: HashMap<MuID, MuBundle>
\ No newline at end of file
......@@ -3,6 +3,8 @@
use ast::ptr::*;
use ast::ir::*;
use ast::types::*;
use vm::api;
use vm::VM;
use vm::bundle::*;
......@@ -26,7 +28,7 @@ macro_rules! api {
fn unimplemented_api() {
pub fn unimplemented_api() {
import re
from typing import List, Union, Tuple, Any, Callable, TypeVar, Mapping
from typing.re import Pattern
import tempfile, os.path
Predicate = Union[str,
Tuple[Pattern, ...],
Callable[[Any], bool]]
def _string_contains(line, string):
return string in line
def _pattern_value_match(line, tup):
pat = tup[0]
vals = tup[1:]
m = pat.search(line)
return m is not None and all(
v is None or g == v
for g,v in zip(m.groups(), vals))
def _apply_func(line, func):
return func(line)
def find_line(lines: List[str], substr: Predicate, start: int = 0) -> int:
"""Find the line that contains or matches substr since line ``start``. """
if isinstance(substr, str):
pred = _string_contains
elif isinstance(substr, tuple):
pred = _pattern_value_match
pred = _apply_func
for i in range(start, len(lines)):
if pred(lines[i], substr):
return i
raise KeyError("Not found: " + str(substr) + "\n text:" + str(lines) )
def extract_lines(parent: str, begin: Predicate, end: Predicate) -> str:
Extract the lines between the line containing ``begin`` and the line
containing ``end`` (excluding both lines) in ``parent``.
lines = parent.splitlines()
begin_line = find_line(lines, begin)
end_line = find_line(lines, end, begin_line+1)
new_lines = lines[begin_line+1:end_line]
return "\n".join(new_lines)
def inject_lines(parent: str, begin: Predicate, end: Predicate, generated: str) -> str:
Replace the lines between the line containing ``begin`` and the line
containing ``end`` (excluding both lines) in ``parent`` with ``generated``.
lines = parent.splitlines()
begin_line = find_line(lines, begin)
end_line = find_line(lines, end, begin_line+1)
new_lines = lines[:begin_line+1] + generated.splitlines() + lines[end_line:]
return "\n".join(new_lines)
class StandardInjectableFile(object):
def __init__(self, path: str, injection_points: List[str] = None):
self.path = path
if injection_points is None:
injection_points = []
self.injection_points = injection_points
def inject_many(self, m: Mapping[str, str], force=False):
with open(self.path) as f:
orig_txt = f.read()
txt = orig_txt
for inj_point, inj_content in m.items():
if inj_point not in self.injection_points and not force:
raise Exception("Unknown injection point '{}'".format(inj_point))
inj_begin = STANDARD_PREFIX_BEGIN + inj_point
inj_end = STANDARD_PREFIX_END + inj_point
new_txt = inject_lines(txt, inj_begin, inj_end, inj_content)
txt = new_txt
if not txt.endswith("\n"):
txt += "\n"
with tempfile.NamedTemporaryFile("w", delete=False) as f:
print("Backup to temporary file: {} -> {}".format(self.path, f.name))
with open(self.path, "w") as f:
print("Writing to file: {}".format(self.path))
def make_injectable_file_set(
root_path: str,
items : List[Tuple[str, str, List[str]]],
) -> Mapping[str, StandardInjectableFile]:
m = InjectableFileSet()
for name, path, inj_points in items:
full_path = os.path.join(root_path, path)
sif = StandardInjectableFile(full_path, inj_points)
m[name] = sif
return m
class InjectableFileSet(dict):
def inject_many(self, m: Mapping[str, Mapping[str, str]]):
for name, mm in m.items():
mod api_old;
mod api_new;
pub use vm::api::api_new::*;
This diff is collapsed.
Parse the muapi.h so that you can generate different bindings.
The result will be a simple JSON object (dict of dicts).
import re
import injecttools
rfrag_commpragma = r'(?:///\s*MUAPIPARSER\s+(?P<pragma>.*))?'
r_comment = re.compile(r'//.*$', re.MULTILINE)
r_decl = re.compile(r'(?P<ret>\w+\s*\*?)\s*\(\s*\*\s*(?P<name>\w+)\s*\)\s*\((?P<params>[^)]*)\)\s*;\s*' + rfrag_commpragma, re.MULTILINE)
r_param = re.compile(r'\s*(?P<type>\w+\s*\*?)\s*(?P<name>\w+)')
r_define = re.compile(r'^\s*#define\s+(?P<name>\w+)\s*\(\((?P<type>\w+)\)(?P<value>\w+)\)\s*' + rfrag_commpragma + r'\s*$', re.MULTILINE)
r_typedef = re.compile(r'^\s*typedef\s+(?P<expand_to>\w+\s*\*?)\s*(?P<name>\w+)\s*;', re.MULTILINE)
r_struct_start = re.compile(r'^struct\s+(\w+)\s*\{')
r_struct_end = re.compile(r'^\};')
def filter_ret_ty(text):
return text.replace(" ","")
def extract_params(text):
params = []
for text1 in text.split(','):
ty, name = r_param.search(text1).groups()
ty = ty.replace(" ",'')
params.append({"type": ty, "name": name})
return params
def extract_pragmas(text):
text = text.strip()
if len(text) == 0:
return []
return text.split(";")
def extract_method(name, params, ret_ty, pragmas):
params = extract_params(params)
ret_ty = filter_ret_ty(ret_ty)
pragmas = extract_pragmas(pragmas)
params_index = {p["name"]:p for p in params}
for pragma in pragmas:
parts = pragma.split(":")
param_name = parts[0]
if param_name not in params_index:
raise Exception("Method {}: Pragma {} is for unknown param {}".format(
name, pragma, param_name))
param = params_index[param_name]
kind = parts[1]
if kind == 'array':
sz_param_name = parts[2]
param["array_sz_param"] = sz_param_name
if sz_param_name not in params_index:
raise Exception(
"Method {}: param {}: Array length parameter {} does not exist".format(
name, pn, sz_param_name))
sz_param = params_index[sz_param_name]
sz_param["is_sz_param"] = True
elif kind == 'optional':
param["is_optional"] = True
elif kind == 'out':
param["is_out"] = True
raise Exception("Method {}: param {}: Unrecognised pragma {}".format(
name, pn, pragma))
return {
"name": name,
"params": params,
"ret_ty": ret_ty,
# "pragmas": pragmas, # Don't include it any more, since we handle everything.
def extract_methods(body):
methods = []
for ret, name, params, pragmas in r_decl.findall(body):
method = extract_method(name, params, ret, pragmas)
return methods
def extract_struct(text, name):
return injecttools.extract_lines(text, (r_struct_start, name), (r_struct_end,))
def extract_enum(name, ty, value, pragmas):
pragmas = extract_pragmas(pragmas)
enum = {
"name": name,
"value": value,
# "pragmas": pragmas, # Don't include it any more, since we handle everything.
for pragma in pragmas:
parts = pragma.split(":")
pragma_name = parts[0]
if pragma_name == "muname":
muname = parts[1]
enum["muname"] = muname
return enum
def extract_enums(text, typename, pattern):
defs = []
for name, ty, value, pragmas in r_define.findall(text):
if pattern.search(name) is not None:
enum = extract_enum(name, ty, value, pragmas)
return {
"name": typename,
"defs": defs,
_top_level_structs = ["MuVM", "MuCtx", "MuIRBuilder"]
_enums = [(typename, re.compile(regex)) for typename, regex in [
("MuTrapHandlerResult", r'^MU_(THREAD|REBIND)'),
("MuDestKind", r'^MU_DEST_'),
("MuBinOpStatus", r'^MU_BOS_'),
("MuBinOptr", r'^MU_BINOP_'),
("MuCmpOptr", r'^MU_CMP_'),
("MuConvOptr", r'^MU_CONV_'),
("MuMemOrd", r'^MU_ORD_'),
("MuAtomicRMWOptr", r'^MU_ARMW_'),
("MuCallConv", r'^MU_CC_'),
("MuCommInst", r'^MU_CI_'),
def extract_typedefs(text):
typedefs = {}
typedefs_order = []
for m in r_typedef.finditer(text):
expand_to, name = m.groups()
expand_to = expand_to.replace(" ","")
typedefs[name] = expand_to
typedefs_order.append((name, expand_to))
return typedefs, typedefs_order
def parse_muapi(text):
structs = []
for sn in _top_level_structs:
b = extract_struct(text, sn)
methods = extract_methods(b)
structs.append({"name": sn, "methods": methods})
enums = []
for tn,pat in _enums:
enums.append(extract_enums(text, tn, pat))
typedefs, typedefs_order = extract_typedefs(text)
return {
"structs": structs,
"enums": enums,
"typedefs": typedefs,
"typedefs_order": typedefs_order,
if __name__=='__main__':
import sys, pprint, shutil
width = 80
width, height = shutil.get_terminal_size((80, 25))
text = sys.stdin.read()
pprint.pprint(parse_muapi(text), width=width)
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