Changeset cdb62c9 in rtems-central


Ignore:
Timestamp:
Jun 16, 2021, 5:06:38 PM (7 weeks ago)
Author:
Sebastian Huber <sebastian.huber@…>
Branches:
master
Children:
9c2bfab
Parents:
45b1ab5
git-author:
Sebastian Huber <sebastian.huber@…> (06/16/21 17:06:38)
git-committer:
Sebastian Huber <sebastian.huber@…> (06/16/21 17:08:46)
Message:

validation: Split file

Files:
1 added
2 edited

Legend:

Unmodified
Added
Removed
  • rtemsspec/validation.py

    r45b1ab5 rcdb62c9  
    2525# POSSIBILITY OF SUCH DAMAGE.
    2626
    27 # pylint: disable=too-many-lines
    28 
    2927import itertools
    30 import math
    3128import os
    3229import re
    33 import textwrap
    34 from typing import Any, Dict, Iterator, List, NamedTuple, Optional, Tuple
    35 
    36 from rtemsspec.content import CContent, CInclude, enabled_by_to_exp, \
    37     ExpressionMapper, GenericContent, get_value_params, get_value_plural, \
     30from typing import Any, Dict, List, Optional, Tuple
     31
     32from rtemsspec.content import CContent, CInclude, \
     33    GenericContent, get_value_params, get_value_plural, \
    3834    get_value_doxygen_group, get_value_doxygen_function, to_camel_case
    39 from rtemsspec.items import is_enabled, Item, ItemCache, \
     35from rtemsspec.items import Item, ItemCache, \
    4036    ItemGetValueContext, ItemMapper
     37from rtemsspec.transitionmap import TransitionMap
    4138
    4239ItemMap = Dict[str, Item]
     
    467464
    468465
    469 class Transition(NamedTuple):
    470     """ Represents a action requirement transition map entry.  """
    471     desc_idx: int
    472     enabled_by: Any
    473     skip: int
    474     pre_cond_na: Tuple[int, ...]
    475     post_cond: Tuple[Any, ...]
    476 
    477 
    478 def _variant_to_key(variant: Transition) -> str:
    479     return "".join((enabled_by_to_exp(variant.enabled_by,
    480                                       ExpressionMapper()), str(variant.skip),
    481                     str(variant.pre_cond_na), str(variant.post_cond)))
    482 
    483 
    484 class _TransitionEntry:
    485     def __init__(self):
    486         self.key = ""
    487         self.variants = []  # type: List[Transition]
    488 
    489     def __bool__(self):
    490         return bool(self.variants)
    491 
    492     def __getitem__(self, key):
    493         return self.variants[key]
    494 
    495     def __len__(self):
    496         return len(self.variants)
    497 
    498     def add(self, variant: Transition) -> None:
    499         """ Adds the variant to the transitions of the entry. """
    500         self.key += _variant_to_key(variant)
    501         self.variants.append(variant)
    502 
    503     def replace(self, index: int, variant: Transition) -> None:
    504         """ Replace the variant at transition variant index. """
    505         self.key = self.key.replace(_variant_to_key(self.variants[index]),
    506                                     _variant_to_key(variant))
    507         self.variants[index] = variant
    508 
    509 
    510466_IdxToX = Tuple[Tuple[str, ...], ...]
    511 _TransitionMap = List[_TransitionEntry]
    512 
    513 
    514 def _to_st_idx(conditions: List[Any]) -> Tuple[Dict[str, int], ...]:
    515     return tuple(
    516         dict((state["name"], st_idx) for st_idx, state in enumerate(
    517             itertools.chain(condition["states"], [{
    518                 "name": "N/A"
    519             }]))) for condition in conditions)
    520 
    521 
    522 def _to_st_name(conditions: List[Any]) -> _IdxToX:
    523     return tuple(
    524         tuple(
    525             itertools.chain((state["name"]
    526                              for state in condition["states"]), ["NA"]))
    527         for condition in conditions)
    528 
    529 
    530 class _PostCondContext(NamedTuple):
    531     transition_map: "TransitionMap"
    532     map_idx: int
    533     pre_co_states: Tuple[int, ...]
    534     post_co_states: Tuple[Any, ...]
    535     post_co_idx: int
    536     ops: Any
    537 
    538 
    539 def _post_cond_bool_and(ctx: _PostCondContext, exp: Any) -> bool:
    540     for element in exp:
    541         if not _post_cond_bool_exp(ctx, element):
    542             return False
    543     return True
    544 
    545 
    546 def _post_cond_bool_not(ctx: _PostCondContext, exp: Any) -> bool:
    547     return not _post_cond_bool_exp(ctx, exp)
    548 
    549 
    550 def _post_cond_bool_or(ctx: _PostCondContext, exp: Any) -> bool:
    551     for element in exp:
    552         if _post_cond_bool_exp(ctx, element):
    553             return True
    554     return False
    555 
    556 
    557 def _post_cond_bool_post_cond(ctx: _PostCondContext, exp: Any) -> bool:
    558     for post_co_name, status in exp.items():
    559         if isinstance(status, str):
    560             status = [status]
    561         post_co_idx = ctx.transition_map.post_co_name_to_co_idx(post_co_name)
    562         st_idx = [
    563             ctx.transition_map.post_co_idx_st_name_to_st_idx(
    564                 post_co_idx, st_name) for st_name in status
    565         ]
    566         if ctx.post_co_states[post_co_idx] not in st_idx:
    567             return False
    568     return True
    569 
    570 
    571 def _post_cond_bool_pre_cond(ctx: _PostCondContext, exp: Any) -> bool:
    572     for pre_co_name, status in exp.items():
    573         if isinstance(status, str):
    574             status = [status]
    575         pre_co_idx = ctx.transition_map.pre_co_name_to_co_idx(pre_co_name)
    576         st_idx = [
    577             ctx.transition_map.pre_co_idx_st_name_to_st_idx(
    578                 pre_co_idx, st_name) for st_name in status
    579         ]
    580         if ctx.pre_co_states[pre_co_idx] not in st_idx:
    581             return False
    582     return True
    583 
    584 
    585 _POST_COND_BOOL_OPS = {
    586     "and": _post_cond_bool_and,
    587     "not": _post_cond_bool_not,
    588     "or": _post_cond_bool_or,
    589     "post-conditions": _post_cond_bool_post_cond,
    590     "pre-conditions": _post_cond_bool_pre_cond,
    591 }
    592 
    593 
    594 def _post_cond_bool_exp(ctx: _PostCondContext, exp: Any) -> Optional[int]:
    595     if isinstance(exp, list):
    596         return _post_cond_bool_or(ctx, exp)
    597     key = next(iter(exp))
    598     return _POST_COND_BOOL_OPS[key](ctx, exp[key])
    599 
    600 
    601 def _post_cond_do_specified_by(ctx: _PostCondContext, pre_co_name: str) -> int:
    602     pre_co_idx = ctx.transition_map.pre_co_name_to_co_idx(pre_co_name)
    603     st_name = ctx.transition_map.pre_co_idx_st_idx_to_st_name(
    604         pre_co_idx, ctx.pre_co_states[pre_co_idx])
    605     return ctx.transition_map.post_co_idx_st_name_to_st_idx(
    606         ctx.post_co_idx, st_name)
    607 
    608 
    609 def _post_cond_if(ctx: _PostCondContext) -> Optional[int]:
    610     if _post_cond_bool_exp(ctx, ctx.ops["if"]):
    611         if "then-specified-by" in ctx.ops:
    612             return _post_cond_do_specified_by(ctx,
    613                                               ctx.ops["then-specified-by"])
    614         return ctx.transition_map.post_co_idx_st_name_to_st_idx(
    615             ctx.post_co_idx, ctx.ops["then"])
    616     return None
    617 
    618 
    619 def _post_cond_specified_by(ctx: _PostCondContext) -> Optional[int]:
    620     return _post_cond_do_specified_by(ctx, ctx.ops["specified-by"])
    621 
    622 
    623 def _post_cond_else(ctx: _PostCondContext) -> Optional[int]:
    624     return ctx.transition_map.post_co_idx_st_name_to_st_idx(
    625         ctx.post_co_idx, ctx.ops["else"])
    626 
    627 
    628 _POST_COND_OP = {
    629     "else": _post_cond_else,
    630     "if": _post_cond_if,
    631     "specified-by": _post_cond_specified_by,
    632 }
    633 
    634 PostCond = Tuple[int, ...]
    635 
    636 PreCondsOfPostCond = List[Tuple[List[int], ...]]
    637 
    638 
    639 def _compact(pre_conds: PreCondsOfPostCond) -> PreCondsOfPostCond:
    640     while True:
    641         last = pre_conds[0]
    642         combined_pre_conds = [last]
    643         combined_count = 0
    644         for row in pre_conds[1:]:
    645             diff = [
    646                 index for index, states in enumerate(last)
    647                 if states != row[index]
    648             ]
    649             if len(diff) == 1:
    650                 index = diff[0]
    651                 combined_count += 1
    652                 last[index].extend(row[index])
    653             else:
    654                 combined_pre_conds.append(row)
    655                 last = row
    656         pre_conds = combined_pre_conds
    657         if combined_count == 0:
    658             break
    659     return pre_conds
    660 
    661 
    662 def _compact_more(pre_conds: PreCondsOfPostCond) -> PreCondsOfPostCond:
    663     while True:
    664         combined_count = 0
    665         next_pre_conds = []
    666         while pre_conds:
    667             first = pre_conds.pop(0)
    668             next_pre_conds.append(first)
    669             for row in pre_conds:
    670                 diff = [
    671                     index for index, states in enumerate(first)
    672                     if states != row[index]
    673                 ]
    674                 if len(diff) <= 1:
    675                     if diff:
    676                         index = diff[0]
    677                         first[index].extend(row[index])
    678                     combined_count += 1
    679                     pre_conds.remove(row)
    680         pre_conds = next_pre_conds
    681         if combined_count == 0:
    682             break
    683     return pre_conds
    684 
    685 
    686 class TransitionMap:
    687     """ Representation of an action requirement transition map. """
    688 
    689     # pylint: disable=too-many-instance-attributes
    690     def __init__(self, item: Item):
    691         self._item = item
    692         self._pre_co_count = len(item["pre-conditions"])
    693         self._post_co_count = len(item["post-conditions"])
    694         self.pre_co_summary = tuple(0 for _ in range(self._pre_co_count + 1))
    695         self._pre_co_idx_st_idx_to_st_name = _to_st_name(
    696             item["pre-conditions"])
    697         self._post_co_idx_st_idx_to_st_name = _to_st_name(
    698             item["post-conditions"])
    699         self._pre_co_idx_st_name_to_st_idx = _to_st_idx(item["pre-conditions"])
    700         self._post_co_idx_st_name_to_st_idx = _to_st_idx(
    701             item["post-conditions"])
    702         self._pre_co_idx_to_cond = dict(
    703             (co_idx, condition)
    704             for co_idx, condition in enumerate(item["pre-conditions"]))
    705         self._pre_co_name_to_co_idx = dict(
    706             (condition["name"], co_idx)
    707             for co_idx, condition in enumerate(item["pre-conditions"]))
    708         self._post_co_name_to_co_idx = dict(
    709             (condition["name"], co_idx)
    710             for co_idx, condition in enumerate(item["post-conditions"]))
    711         self._post_co_idx_to_co_name = dict(
    712             (co_idx, condition["name"])
    713             for co_idx, condition in enumerate(item["post-conditions"]))
    714         self._skip_idx_to_name = dict(
    715             (skip_idx + 1, key)
    716             for skip_idx, key in enumerate(item["skip-reasons"].keys()))
    717         self._skip_name_to_idx = dict(
    718             (key, skip_idx + 1)
    719             for skip_idx, key in enumerate(item["skip-reasons"].keys()))
    720         self._entries = {}  # type: Dict[str, List[Any]]
    721         self._map = self._build_map()
    722         self._post_process()
    723 
    724     def __getitem__(self, key: str):
    725         return self._item[key]
    726 
    727     def __iter__(self):
    728         yield from self._map
    729 
    730     def entries(self) -> Iterator[List[Any]]:
    731         """ Yields the transition map entry variants sorted by frequency. """
    732         yield from sorted(self._entries.values(), key=lambda x: x[1])
    733 
    734     def get_variants(self,
    735                      enabled: List[str]) -> Iterator[Tuple[int, Transition]]:
    736         """
    737         Yields the map index and the transition variants enabled by the enabled
    738         list.
    739         """
    740         for map_idx, transitions in enumerate(self._map):
    741             for variant in transitions[1:]:
    742                 if is_enabled(enabled, variant.enabled_by):
    743                     break
    744             else:
    745                 variant = transitions[0]
    746             yield map_idx, variant
    747 
    748     def get_post_conditions(
    749             self, enabled: List[str]
    750     ) -> Iterator[Tuple[PostCond, PreCondsOfPostCond]]:
    751         """
    752         Yields tuples of post-condition variants and the corresponding
    753         pre-condition variants which are enabled by the enabled list.
    754 
    755         The first entry of the post-condition variant is the skip index.  The
    756         remaining entries are post-condition indices.  The pre-condition
    757         variants are a list of tuples.  Each tuple entry corresponds to a
    758         pre-condition and provides a list of corresponding pre-condition state
    759         indices.
    760         """
    761         entries = {}  # type: Dict[PostCond, PreCondsOfPostCond]
    762         for map_idx, variant in self.get_variants(enabled):
    763             key = (variant.skip, ) + variant.post_cond
    764             entry = entries.setdefault(key, [])
    765             entry.append(
    766                 tuple([state] for state in self.map_idx_to_pre_co_states(
    767                     map_idx, variant.pre_cond_na)))
    768         for post_cond, pre_conds in sorted(entries.items(),
    769                                            key=lambda x: (x[0][0], len(x[1]))):
    770             pre_conds = _compact_more(_compact(pre_conds))
    771             yield post_cond, pre_conds
    772 
    773     def _post_process(self) -> None:
    774         for map_idx, transitions in enumerate(self):
    775             if not transitions or not isinstance(
    776                     transitions[0].enabled_by,
    777                     bool) or not transitions[0].enabled_by:
    778                 raise ValueError(
    779                     f"transition map of {self._item.spec} contains no default "
    780                     "entry for pre-condition set "
    781                     f"{{{self._map_index_to_pre_conditions(map_idx)}}}")
    782             entry = self._entries.setdefault(transitions.key,
    783                                              [0, 0, transitions, []])
    784             entry[0] += 1
    785             entry[3].append(map_idx)
    786         for index, entry in enumerate(
    787                 sorted(self._entries.values(),
    788                        key=lambda x: x[0],
    789                        reverse=True)):
    790             entry[1] = index
    791 
    792     def _map_index_to_pre_conditions(self, map_idx: int) -> str:
    793         conditions = []
    794         for condition in reversed(self._item["pre-conditions"]):
    795             states = condition["states"]
    796             count = len(states)
    797             st_idx = int(map_idx % count)
    798             conditions.append(f"{condition['name']}={states[st_idx]['name']}")
    799             map_idx //= count
    800         return ", ".join(reversed(conditions))
    801 
    802     def map_idx_to_pre_co_states(
    803             self, map_idx: int, pre_cond_na: Tuple[int,
    804                                                    ...]) -> Tuple[int, ...]:
    805         """
    806         Maps the transition map index and the associated pre-condition state
    807         indices.
    808         """
    809         co_states = []
    810         for condition in reversed(self._item["pre-conditions"]):
    811             count = len(condition["states"])
    812             co_states.append(count if pre_cond_na[self._pre_co_name_to_co_idx[
    813                 condition["name"]]] else int(map_idx % count))
    814             map_idx //= count
    815         return tuple(reversed(co_states))
    816 
    817     def pre_co_name_to_co_idx(self, co_name: str) -> int:
    818         """
    819         Maps the pre-condition name to the associated pre-condition index.
    820         """
    821         return self._pre_co_name_to_co_idx[co_name]
    822 
    823     def pre_co_idx_to_co_name(self, co_idx: int) -> str:
    824         """
    825         Maps the pre-condition index to the associated pre-condition name.
    826         """
    827         return self._pre_co_idx_to_cond[co_idx]["name"]
    828 
    829     def post_co_name_to_co_idx(self, co_name: str) -> int:
    830         """
    831         Maps the post-condition name to the associated post-condition index.
    832         """
    833         return self._post_co_name_to_co_idx[co_name]
    834 
    835     def post_co_idx_to_co_name(self, co_idx: int) -> str:
    836         """
    837         Maps the post-condition index to the associated post-condition name.
    838         """
    839         return self._post_co_idx_to_co_name[co_idx]
    840 
    841     def pre_co_idx_st_idx_to_st_name(self, co_idx: int, st_idx: int) -> str:
    842         """
    843         Maps the pre-condition name and state index to the associated state
    844         name.
    845         """
    846         return self._pre_co_idx_st_idx_to_st_name[co_idx][st_idx]
    847 
    848     def post_co_idx_st_idx_to_st_name(self, co_idx: int, st_idx: int) -> str:
    849         """
    850         Maps the post-condition name and state index to the associated state
    851         name.
    852         """
    853         return self._post_co_idx_st_idx_to_st_name[co_idx][st_idx]
    854 
    855     def pre_co_idx_st_name_to_st_idx(self, co_idx: int, st_name: str) -> int:
    856         """
    857         Maps the pre-condition index and state name to the associated state
    858         index.
    859         """
    860         return self._pre_co_idx_st_name_to_st_idx[co_idx][st_name]
    861 
    862     def post_co_idx_st_name_to_st_idx(self, co_idx: int, st_name: str) -> int:
    863         """
    864         Maps the post-condition index and state name to the associated state
    865         index.
    866         """
    867         return self._post_co_idx_st_name_to_st_idx[co_idx][st_name]
    868 
    869     def skip_idx_to_name(self, skip_idx: int) -> str:
    870         """
    871         Maps the skip index the associated skip name index.
    872         """
    873         return self._skip_idx_to_name[skip_idx]
    874 
    875     def _map_post_cond(self, map_idx: int, co_idx: int,
    876                        variant: Transition) -> Transition:
    877         if isinstance(variant.post_cond[co_idx], int):
    878             return variant
    879         pre_co_states = self.map_idx_to_pre_co_states(map_idx,
    880                                                       variant.pre_cond_na)
    881         for ops in variant.post_cond[co_idx]:
    882             idx = _POST_COND_OP[next(iter(ops))](_PostCondContext(
    883                 self, map_idx, pre_co_states, variant.post_cond, co_idx, ops))
    884             if idx is not None:
    885                 return Transition(
    886                     variant.desc_idx, variant.enabled_by, variant.skip,
    887                     variant.pre_cond_na, variant.post_cond[0:co_idx] +
    888                     (idx, ) + variant.post_cond[co_idx + 1:])
    889         raise ValueError(
    890             "cannot determine state for post-condition "
    891             f"'{self._post_co_idx_to_co_name[co_idx]}' of transition map "
    892             f"descriptor {variant.desc_idx} of {self._item.spec} for "
    893             "pre-condition set "
    894             f"{{{self._map_index_to_pre_conditions(map_idx)}}}")
    895 
    896     def _make_post_cond(self, map_idx: int, variant: Transition) -> Transition:
    897         for co_idx in range(len(variant.post_cond)):
    898             variant = self._map_post_cond(map_idx, co_idx, variant)
    899         return variant
    900 
    901     def _add_variant(self, transition_map: _TransitionMap, map_idx: int,
    902                      variant: Transition) -> None:
    903         if transition_map[map_idx]:
    904             for index, existing in enumerate(transition_map[map_idx].variants):
    905                 if existing.enabled_by == variant.enabled_by:
    906                     if variant.skip:
    907                         # Allow transition map variants with a skip reason to
    908                         # overwrite existing variants with the same enabled-by
    909                         # attribute.  This is important if variants use N/A for
    910                         # some pre-conditions.  It makes it also easier to skip
    911                         # pre-conditon states which are controlled by build
    912                         # options.
    913                         transition_map[map_idx].replace(index, variant)
    914                         return
    915                     raise ValueError(
    916                         f"transition map descriptor {variant.desc_idx} of "
    917                         f"{self._item.spec} duplicates pre-condition set "
    918                         f"{{{self._map_index_to_pre_conditions(map_idx)}}}"
    919                         " defined by transition map descriptor "
    920                         f"{existing.desc_idx}")
    921             default = transition_map[map_idx][0]
    922             if (default.post_cond, default.skip,
    923                     default.pre_cond_na) == (variant.post_cond, variant.skip,
    924                                              variant.pre_cond_na):
    925                 return
    926         elif not isinstance(variant.enabled_by,
    927                             bool) or not variant.enabled_by:
    928             raise ValueError(
    929                 f"transition map descriptor {variant.desc_idx} of "
    930                 f"{self._item.spec} is the first variant for "
    931                 f"{{{self._map_index_to_pre_conditions(map_idx)}}} "
    932                 "and it is not enabled by default")
    933         self.pre_co_summary = tuple(
    934             a + b for a, b in zip(self.pre_co_summary, (variant.skip, ) +
    935                                   variant.pre_cond_na))
    936         transition_map[map_idx].add(variant)
    937 
    938     def _add_transitions(self, transition_map: _TransitionMap,
    939                          desc: Dict[str, Any], desc_idx: int,
    940                          skip_post_cond: Tuple[Any, ...], co_idx: int,
    941                          map_idx: int, pre_cond_na: Tuple[int, ...]) -> None:
    942         # pylint: disable=too-many-arguments
    943         # pylint: disable=too-many-locals
    944         if co_idx < self._pre_co_count:
    945             condition = self._pre_co_idx_to_cond[co_idx]
    946             state_count = len(condition["states"])
    947             map_idx *= state_count
    948             states = desc["pre-conditions"][condition["name"]]
    949             if isinstance(states, str):
    950                 assert states in ["all", "N/A"]
    951                 for st_idx in range(state_count):
    952                     self._add_transitions(
    953                         transition_map, desc, desc_idx, skip_post_cond,
    954                         co_idx + 1, map_idx + st_idx,
    955                         pre_cond_na + (int(states == "N/A"), ))
    956             else:
    957                 for st_name in states:
    958                     try:
    959                         st_idx = self._pre_co_idx_st_name_to_st_idx[co_idx][
    960                             st_name]
    961                     except KeyError as err:
    962                         msg = (f"transition map descriptor {desc_idx} of "
    963                                f"{self._item.spec} refers to non-existent "
    964                                f"state {err} of pre-condition "
    965                                f"'{condition['name']}'")
    966                         raise ValueError(msg) from err
    967                     self._add_transitions(transition_map, desc, desc_idx,
    968                                           skip_post_cond, co_idx + 1,
    969                                           map_idx + st_idx,
    970                                           pre_cond_na + (0, ))
    971         else:
    972             variant = self._make_post_cond(
    973                 map_idx,
    974                 Transition(desc_idx, desc["enabled-by"], skip_post_cond[0],
    975                            pre_cond_na, skip_post_cond[1:]))
    976             self._add_variant(transition_map, map_idx, variant)
    977 
    978     def _add_default(self, transition_map: _TransitionMap, desc: Dict[str,
    979                                                                       Any],
    980                      desc_idx: int, skip_post_cond: Tuple[int, ...]) -> None:
    981         enabled_by = desc["enabled-by"]
    982         for map_idx, transition in enumerate(transition_map):
    983             if not transition:
    984                 transition.add(
    985                     self._make_post_cond(
    986                         map_idx,
    987                         Transition(desc_idx, enabled_by, skip_post_cond[0],
    988                                    (0, ) * self._pre_co_count,
    989                                    skip_post_cond[1:])))
    990 
    991     def _get_post_cond(self, desc: Dict[str, Any], co_idx: int) -> Any:
    992         info = desc["post-conditions"][self._post_co_idx_to_co_name[co_idx]]
    993         if isinstance(info, str):
    994             return self._post_co_idx_st_name_to_st_idx[co_idx][info]
    995         return info
    996 
    997     def _build_map(self) -> _TransitionMap:
    998         transition_count = 1
    999         for condition in self["pre-conditions"]:
    1000             state_count = len(condition["states"])
    1001             if state_count == 0:
    1002                 raise ValueError(f"pre-condition '{condition['name']}' of "
    1003                                  f"{self._item.spec} has no states")
    1004             transition_count *= state_count
    1005         transition_map = [_TransitionEntry() for _ in range(transition_count)]
    1006         for desc_idx, desc in enumerate(self["transition-map"]):
    1007             if isinstance(desc["post-conditions"], dict):
    1008                 try:
    1009                     skip_post_cond = (0, ) + tuple(
    1010                         self._get_post_cond(desc, co_idx)
    1011                         for co_idx in range(self._post_co_count))
    1012                 except KeyError as err:
    1013                     msg = (f"transition map descriptor {desc_idx} of "
    1014                            f"{self._item.spec} refers to non-existent "
    1015                            f"post-condition state {err}")
    1016                     raise ValueError(msg) from err
    1017             else:
    1018                 skip_post_cond = (
    1019                     self._skip_name_to_idx[desc["post-conditions"]], ) + tuple(
    1020                         self._post_co_idx_st_name_to_st_idx[co_idx]["N/A"]
    1021                         for co_idx in range(self._post_co_count))
    1022             if isinstance(desc["pre-conditions"], dict):
    1023                 self._add_transitions(transition_map, desc, desc_idx,
    1024                                       skip_post_cond, 0, 0, ())
    1025             else:
    1026                 assert desc["pre-conditions"] == "default"
    1027                 self._add_default(transition_map, desc, desc_idx,
    1028                                   skip_post_cond)
    1029         return transition_map
    1030 
    1031     def _get_entry(self, ident: str, variant: Transition) -> str:
    1032         text = "{ " + ", ".join(
    1033             itertools.chain(
    1034                 map(str, (int(variant.skip != 0), ) + variant.pre_cond_na),
    1035                 ((f"{ident}_Post_{self._post_co_idx_to_co_name[co_idx]}"
    1036                   f"_{self._post_co_idx_st_idx_to_st_name[co_idx][st_idx]}")
    1037                  for co_idx, st_idx in enumerate(variant.post_cond))))
    1038         wrapper = textwrap.TextWrapper()
    1039         wrapper.initial_indent = "  "
    1040         wrapper.subsequent_indent = "    "
    1041         wrapper.width = 79
    1042         return "\n".join(wrapper.wrap(text)) + " },"
    1043 
    1044     def _get_entry_bits(self) -> int:
    1045         bits = self._pre_co_count + 1
    1046         for st_idx_to_st_name in self._post_co_idx_st_idx_to_st_name:
    1047             bits += math.ceil(math.log2(len(st_idx_to_st_name)))
    1048         return 2**max(math.ceil(math.log2(bits)), 3)
    1049 
    1050     def add_map(self, content: CContent, ident: str) -> None:
    1051         """ Adds the transition map definitions to the content. """
    1052         entries = []
    1053         mapper = ExpressionMapper()
    1054         for entry in self.entries():
    1055             transitions = entry[2]
    1056             if len(transitions) == 1:
    1057                 entries.append(self._get_entry(ident, transitions[0]))
    1058             else:
    1059                 ifelse = "#if "
    1060                 enumerators = []  # type: List[str]
    1061                 for variant in transitions[1:]:
    1062                     enumerators.append(
    1063                         ifelse + enabled_by_to_exp(variant.enabled_by, mapper))
    1064                     enumerators.append(self._get_entry(ident, variant))
    1065                     ifelse = "#elif "
    1066                 enumerators.append("#else")
    1067                 enumerators.append(self._get_entry(ident, transitions[0]))
    1068                 enumerators.append("#endif")
    1069                 entries.append("\n".join(enumerators))
    1070         bits = self._get_entry_bits()
    1071         content.add("typedef struct {")
    1072         with content.indent():
    1073             content.append(f"uint{bits}_t Skip : 1;")
    1074             for condition in self["pre-conditions"]:
    1075                 content.append(f"uint{bits}_t Pre_{condition['name']}_NA : 1;")
    1076             for condition in self["post-conditions"]:
    1077                 state_bits = math.ceil(math.log2(len(condition["states"]) + 1))
    1078                 content.append(
    1079                     f"uint{bits}_t Post_{condition['name']} : {state_bits};")
    1080         content.add(f"}} {ident}_Entry;")
    1081         content.add([f"static const {ident}_Entry", f"{ident}_Entries[] = {{"])
    1082         entries[-1] = entries[-1].replace("},", "}")
    1083         content.append(entries)
    1084         bits = max(8, math.ceil(math.log2(len(self._entries)) / 8) * 8)
    1085         content.append(
    1086             ["};", "", f"static const uint{bits}_t", f"{ident}_Map[] = {{"])
    1087         text = ", ".join(
    1088             str(self._entries[transitions.key][1])
    1089             for transitions in self._map)
    1090         wrapper = textwrap.TextWrapper()
    1091         wrapper.initial_indent = "  "
    1092         wrapper.subsequent_indent = "  "
    1093         wrapper.width = 79
    1094         content.append(wrapper.wrap(text))
    1095         content.append("};")
    1096 
    1097     def get_post_entry_member(self, co_idx: int) -> str:
    1098         """
    1099         Gets the post-condition entry member name for the post-condition index.
    1100         """
    1101         return f"Post_{self._post_co_idx_to_co_name[co_idx]}"
    1102467
    1103468
  • specview.py

    r45b1ab5 rcdb62c9  
    3535from rtemsspec.sphinxcontent import SphinxContent
    3636from rtemsspec.util import load_config
    37 from rtemsspec.validation import Transition, TransitionMap
     37from rtemsspec.transitionmap import Transition, TransitionMap
    3838
    3939_CHILD_ROLES = [
Note: See TracChangeset for help on using the changeset viewer.