Ejemplo n.º 1
0
    def _patch_special_syntax(self):
        """Takes an fstring (and its prefix, ie "f") that may contain
        xonsh expressions as its field values and substitues them for
        a call to __xonsh__.eval_fstring_field as needed.
        """
        prelen = len(self.prefix)
        quote = self.fstring[prelen]
        if self.fstring[prelen + 1] == quote:
            quote *= 3
        template = self.fstring[prelen + len(quote) : -len(quote)]
        while True:
            repl = self.prefix + quote + template + quote
            try:
                res = pyparse(repl)
                break
            except SyntaxError as e:
                # The e.text attribute is expected to contain the failing
                # expression, e.g. "($HOME)" for f"{$HOME}" string.
                if e.text is None or e.text[0] != "(":
                    raise
                error_expr = e.text[1:-1]
                epos = template.find(error_expr)
                if epos < 0:
                    raise
            # We can olny get here in the case of handled SyntaxError.
            # Patch the last error and start over.
            xonsh_field = (error_expr, self.filename if self.filename else None)
            field_id = id(xonsh_field)
            self.fields[field_id] = xonsh_field
            eval_field = f"__xonsh__.eval_fstring_field({field_id})"
            template = template[:epos] + eval_field + template[epos + len(error_expr) :]

        self.repl = repl
        self.res = res.body[0].value
Ejemplo n.º 2
0
    def _unpatch_strings(self):
        """Reverts false-positive field matches within strings."""
        reparse = False
        for node in ast.walk(self.res):
            if isinstance(node, ast.Constant) and isinstance(node.value, str):
                value = node.value
            elif isinstance(node, ast.Str):
                value = node.s
            else:
                continue

            match = RE_FSTR_FIELD_WRAPPER.search(value)
            if match is None:
                continue
            field = self.fields.pop(int(match.group(2)), None)
            if field is None:
                continue
            self.repl = self.repl.replace(match.group(1), field[0], 1)
            reparse = True

        if reparse:
            self.res = pyparse(self.repl).body[0].value