def _preprocess_once()

in contrib/freestanding_lib/freestanding.py [0:0]


    def _preprocess_once(self):
        outlines = []
        idx = 0
        changed = False
        while idx < len(self._inlines):
            line = self._inlines[idx]
            sline = self._strip_comments(line)
            m = self._ifdef.fullmatch(sline)
            if_true = False
            if m is None:
                m = self._if_defined_value.fullmatch(sline)
            if m is None:
                m = self._if_defined.match(sline)
            if m is None:
                m = self._if_true.match(sline)
                if_true = (m is not None)
            if m is None:
                outlines.append(line)
                idx += 1
                continue

            groups = m.groupdict()
            macro = groups['macro']
            op = groups.get('op')

            if not (macro in self._defs or macro in self._undefs):
                outlines.append(line)
                idx += 1
                continue

            defined = macro in self._defs

            # Needed variables set:
            # resolved: Is the statement fully resolved?
            # is_true: If resolved, is the statement true?
            ifdef = False
            if if_true:
                if not defined:
                    outlines.append(line)
                    idx += 1
                    continue

                defined_value = self._defs[macro]
                is_int = True
                try:
                    defined_value = int(defined_value)
                except TypeError:
                    is_int = False
                except ValueError:
                    is_int = False

                resolved = is_int
                is_true = (defined_value != 0)

                if resolved and op is not None:
                    if op == '&&':
                        resolved = not is_true
                    else:
                        assert op == '||'
                        resolved = is_true

            else:
                ifdef = groups.get('not') is None
                elseif = groups.get('elif') is not None

                macro2 = groups.get('macro2')
                cmp = groups.get('cmp')
                value = groups.get('value')
                openp = groups.get('openp')
                closep = groups.get('closep')

                is_true = (ifdef == defined)
                resolved = True
                if op is not None:
                    if op == '&&':
                        resolved = not is_true
                    else:
                        assert op == '||'
                        resolved = is_true

                if macro2 is not None and not resolved:
                    assert ifdef and defined and op == '&&' and cmp is not None
                    # If the statment is true, but we have a single value check, then
                    # check the value.
                    defined_value = self._defs[macro]
                    are_ints = True
                    try:
                        defined_value = int(defined_value)
                        value = int(value)
                    except TypeError:
                        are_ints = False
                    except ValueError:
                        are_ints = False
                    if (
                            macro == macro2 and
                            ((openp is None) == (closep is None)) and
                            are_ints
                    ):
                        resolved = True
                        if cmp == '<':
                            is_true = defined_value < value
                        elif cmp == '<=':
                            is_true = defined_value <= value
                        elif cmp == '==':
                            is_true = defined_value == value
                        elif cmp == '!=':
                            is_true = defined_value != value
                        elif cmp == '>=':
                            is_true = defined_value >= value
                        elif cmp == '>':
                            is_true = defined_value > value
                        else:
                            resolved = False

                if op is not None and not resolved:
                    # Remove the first op in the line + spaces
                    if op == '&&':
                        opre = op
                    else:
                        assert op == '||'
                        opre = r'\|\|'
                    needle = re.compile(fr"(?P<if>\s*#\s*(el)?if\s+).*?(?P<op>{opre}\s*)")
                    match = needle.match(line)
                    assert match is not None
                    newline = line[:match.end('if')] + line[match.end('op'):]

                    self._log(f"\tHardwiring partially resolved {macro}")
                    self._log(f"\t\t- {line[:-1]}")
                    self._log(f"\t\t+ {newline[:-1]}")

                    outlines.append(newline)
                    idx += 1
                    continue

            # Skip any statements we cannot fully compute
            if not resolved:
                outlines.append(line)
                idx += 1
                continue

            prepend = []
            if macro in self._replaces:
                assert not ifdef
                assert op is None
                value = self._replaces.pop(macro)
                prepend = [f"#define {macro} {value}\n"]

            idx, replace = self._handle_if_block(macro, idx, is_true, prepend)
            outlines += replace
            changed = True

        return changed, outlines