import re


def get_symbol_name(module, symbol_id):
    """Return a pretty printed name for the symbol_id if available.

    The pretty printed name is created from OpName decorations for the
    symbol_id if available, otherwise a numerical ID (e.g. '%23') is
    returned.

    Names are not unique in SPIR-V, so it is possible that several IDs
    have the same name in their OpName decoration. This function will
    return that name for the first ID found, and the rest will get a
    numerical name."""
    if symbol_id in module.id_to_symbol_name:
        return module.id_to_symbol_name[symbol_id]

    for inst in module.global_instructions.name_insts:
        if inst.op_name == 'OpName' and inst.operands[0] == symbol_id:
            name = inst.operands[1]

            # glslang tend to add type information to function names.
            # E.g. "foo(vec4)" get the symbol name "foo(vf4;"
            # Truncate such names to fit our IL.
            regex = re.compile(r'^[a-zA-Z_][a-zA-Z0-9_]*')
            match = regex.match(name)
            if match is None:
                return '%' + str(symbol_id.value)
            new_name = match.group(0)
            symbol_name = '%' + new_name
            if symbol_name in module.symbol_name_to_id:
                # This name is already used for another ID (which is
                # possible, as the decorations we are using for symbol
                # names are not guaranteed to be unique). Let the first
                # ID use this name, and use a numerical name for this ID.
                symbol_name = '%' + str(symbol_id.value)
            break
    else:
        symbol_name = '%' + str(symbol_id.value)

    module.id_to_symbol_name[symbol_id] = symbol_name
    module.symbol_name_to_id[symbol_name] = symbol_id

    return symbol_name