GitLab will continue to be upgraded from 11.4.5-ce.0 on November 25th 2019 at 4.00pm (AEDT) to 5.00pm (AEDT) due to Critical Security Patch Availability. During the update, GitLab and Mattermost services will not be available.

muapiparser.py 5.38 KB
Newer Older
Kunshan Wang's avatar
Kunshan Wang committed
1 2 3 4 5 6 7 8
"""
Parse the muapi.h so that you can generate different bindings.

The result will be a simple JSON object (dict of dicts).
"""

import re

Kunshan Wang's avatar
Kunshan Wang committed
9 10
import injecttools

Kunshan Wang's avatar
Kunshan Wang committed
11
rfrag_commpragma = r'(?:///\s*MUAPIPARSER\s+(?P<pragma>.*))?'
Kunshan Wang's avatar
Kunshan Wang committed
12
r_comment = re.compile(r'//.*$', re.MULTILINE)
Kunshan Wang's avatar
Kunshan Wang committed
13
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)
Kunshan Wang's avatar
Kunshan Wang committed
14 15
r_param = re.compile(r'\s*(?P<type>\w+\s*\*?)\s*(?P<name>\w+)')

Kunshan Wang's avatar
Kunshan Wang committed
16
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)
17

18
r_typedef = re.compile(r'^\s*typedef\s+(?P<const>const\s+)?(?P<expand_to>\w+\s*\*?)\s*(?P<name>\w+)\s*;', re.MULTILINE)
Kunshan Wang's avatar
Kunshan Wang committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41

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 []
    else:
        return text.split(";")

42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85
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
        else:
            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.
            }

Kunshan Wang's avatar
Kunshan Wang committed
86 87
def extract_methods(body):
    methods = []
88 89 90 91

    for ret, name, params, pragmas in r_decl.findall(body):
        method = extract_method(name, params, ret, pragmas)
        methods.append(method)
Kunshan Wang's avatar
Kunshan Wang committed
92 93 94
        
    return methods

Kunshan Wang's avatar
Kunshan Wang committed
95 96
def extract_struct(text, name):
    return injecttools.extract_lines(text, (r_struct_start, name), (r_struct_end,))
Kunshan Wang's avatar
Kunshan Wang committed
97

98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114
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

Kunshan Wang's avatar
Kunshan Wang committed
115
def extract_enums(text, typename, pattern):
Kunshan Wang's avatar
Kunshan Wang committed
116
    defs = []
117
    for name, ty, value, pragmas in r_define.findall(text):
Kunshan Wang's avatar
Kunshan Wang committed
118
        if pattern.search(name) is not None:
119 120
            enum = extract_enum(name, ty, value, pragmas)
            defs.append(enum)
Kunshan Wang's avatar
Kunshan Wang committed
121 122 123 124 125
    return {
            "name": typename,
            "defs": defs,
            }

126
_top_level_structs = ["MuVM", "MuCtx", "MuIRBuilder"]
Kunshan Wang's avatar
Kunshan Wang committed
127 128
_enums = [(typename, re.compile(regex)) for typename, regex in [
    ("MuTrapHandlerResult", r'^MU_(THREAD|REBIND)'),
129
    ("MuDestKind",          r'^MU_DEST_'),
130
    ("MuBinOpStatus",       r'^MU_BOS_'),
131 132 133 134 135 136 137
    ("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_'),
Kunshan Wang's avatar
Kunshan Wang committed
138 139
    ]]

140 141
def extract_typedefs(text):
    typedefs = {}
Kunshan Wang's avatar
Kunshan Wang committed
142
    typedefs_order = []
143
    for m in r_typedef.finditer(text):
144
        const_qualifier, expand_to, name = m.groups()
Kunshan Wang's avatar
Kunshan Wang committed
145 146 147
        expand_to = expand_to.replace(" ","")
        typedefs[name] = expand_to
        typedefs_order.append((name, expand_to))
148

Kunshan Wang's avatar
Kunshan Wang committed
149
    return typedefs, typedefs_order
150

Kunshan Wang's avatar
Kunshan Wang committed
151 152 153 154
def parse_muapi(text):
    structs = []

    for sn in _top_level_structs:
Kunshan Wang's avatar
Kunshan Wang committed
155
        b = extract_struct(text, sn)
Kunshan Wang's avatar
Kunshan Wang committed
156 157 158 159 160 161
        methods = extract_methods(b)
        structs.append({"name": sn, "methods": methods})

    enums = []

    for tn,pat in _enums:
Kunshan Wang's avatar
Kunshan Wang committed
162
        enums.append(extract_enums(text, tn, pat))
Kunshan Wang's avatar
Kunshan Wang committed
163

Kunshan Wang's avatar
Kunshan Wang committed
164
    typedefs, typedefs_order = extract_typedefs(text)
165

Kunshan Wang's avatar
Kunshan Wang committed
166 167 168
    return {
            "structs": structs,
            "enums": enums,
169
            "typedefs": typedefs,
Kunshan Wang's avatar
Kunshan Wang committed
170
            "typedefs_order": typedefs_order,
Kunshan Wang's avatar
Kunshan Wang committed
171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186
            }

if __name__=='__main__':
    import sys, pprint, shutil

    width = 80

    try:
        width, height = shutil.get_terminal_size((80, 25))
    except:
        pass

    text = sys.stdin.read()
    pprint.pprint(parse_muapi(text), width=width)