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 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