Source code for ifgen.svd.group.enums

"""
A module for handling SVD bit-field enumerations.
"""

# built-in
from os.path import commonprefix
from typing import Any

# internal
from ifgen.svd.model.enum import EnumeratedValues

EnumValues = dict[str, Any]
ENUM_DEFAULTS: dict[str, Any] = {
    "unit_test": False,
    "json": False,
    "use_map": False,
    "identifier": False,
}

BY_HASH: dict[str, dict[int, str]] = {}
PRUNE_ENUMS = False


[docs] def get_enum_name(name: str, peripheral: str, raw_mapping: EnumValues) -> str: """Get the name of an enumeration.""" if not PRUNE_ENUMS: return name hashed = hash( ",".join( name + f"={val['value']}" for name, val in sorted(raw_mapping.items()) ) ) BY_HASH.setdefault(peripheral, {}) for_periph = BY_HASH[peripheral] for_periph.setdefault(hashed, name) return for_periph[hashed]
IGNORE_WORDS = { "the", "as", "a", "is", "will", "but", "are", "yet", "that", "to", "and", "in", "of", "on", "for", "from", "its", "it", }
[docs] def is_name_part(value: str) -> bool: """Determine if a word should be part of an enumeration value name.""" return bool(value) and value not in IGNORE_WORDS
[docs] def as_alnum(word: str) -> str: """Get a word's alpha-numeric contents only.""" result = "" for char in word: if char.isalnum() or char == "_": result += char return result
SKIP = {"-"}
[docs] def handle_enum_name(name: str, description: str = None) -> str: """Attempt to generate more useful enumeration names.""" if name.startswith("value") and description: alnum_parts = [ as_alnum(x.strip().lower().replace("-", "_")) for x in description.split() if x not in SKIP ] # Prune some words if the description is very long. if len(alnum_parts) > 1: alnum_parts = list(filter(is_name_part, alnum_parts)) assert alnum_parts, (name, description) new_name = "_".join(alnum_parts) assert new_name, (name, description) name = new_name return name
[docs] def remove_common_prefixes(data: dict[str, Any]) -> dict[str, Any]: """Attempt to remove common prefixes in enumeration names.""" result = data length = len(commonprefix(list(result))) if length > 1: result = { key[length:] if length < len(key) else key: value for key, value in result.items() } return result
[docs] def handle_duplicate(existing: dict[str, Any], key: str, value: Any) -> None: """Handle key de-duplication for enumerations.""" assert key if key[0].isnumeric(): key = "_" + key while key in existing: key += "_x" existing[key] = value
[docs] def translate_enums(enum: EnumeratedValues) -> EnumValues: """Generate an enumeration definition.""" result: dict[str, Any] = {} enum.handle_description(result) for name, value in enum.derived_elem.enum.items(): enum_data: dict[str, Any] = {} value.handle_description(enum_data) value_str: str = value.raw_data["value"].lower() prefix = "" for possible_prefix in ("#", "0b", "0x"): if value_str.startswith(possible_prefix): prefix = possible_prefix break if prefix in ("#", "0b"): enum_data["value"] = int( value_str[len(prefix) :].replace("x", "1"), 2 ) elif prefix == "0x": enum_data["value"] = int(value_str[len(prefix) :], 16) else: enum_data["value"] = int(value_str) handle_duplicate( result, handle_enum_name(name, value.raw_data.get("description")), enum_data, ) # Truncate names. new_result: dict[str, Any] = {} for key, value in remove_common_prefixes(result).items(): handle_duplicate( new_result, key if len(key) < 51 else key[:45] + "_cont", value ) return new_result