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)