Esempio n. 1
0
    def EvalWordToString(self, word, do_fnmatch=False, do_ere=False):
        """
    Args:
      word: CompoundWord

    Used for redirect arg, ControlFlow arg, ArithWord, BoolWord, etc.

    do_fnmatch is true for case $pat and RHS of [[ == ]].

    pat="*.py"
    case $x in
      $pat) echo 'matches glob pattern' ;;
      "$pat") echo 'equal to glob string' ;;  # must be glob escaped
    esac

    TODO: Raise AssertionError if it has ExtGlobPart.
    """
        if word.tag == word_e.EmptyWord:
            return value.Str('')

        part_vals = []
        for p in word.parts:
            self._EvalWordPart(p, part_vals, quoted=False)

        strs = []
        for part_val in part_vals:
            if part_val.tag == part_value_e.String:
                # [[ foo == */"*".py ]] or case *.py) ... esac
                if do_fnmatch and not part_val.do_split_glob:
                    s = glob_.GlobEscape(part_val.s)
                elif do_ere and not part_val.do_split_glob:
                    s = glob_.ExtendedRegexEscape(part_val.s)
                else:
                    s = part_val.s
            else:
                if self.exec_opts.strict_array:
                    # Examples: echo f > "$@"; local foo="$@"

                    # TODO: This attributes too coarsely, to the word rather than the
                    # parts.  Problem: the word is a TREE of parts, but we only have a
                    # flat list of part_vals.  The only case where we really get arrays
                    # is "$@", "${a[@]}", "${a[@]//pat/replace}", etc.
                    e_die(
                        "This word should evaluate to a string, but part of it was an "
                        "array",
                        word=word)

                    # TODO: Maybe add detail like this.
                    #e_die('RHS of assignment should only have strings.  '
                    #      'To assign arrays, use b=( "${a[@]}" )')
                else:
                    # It appears to not respect IFS
                    s = ' '.join(s for s in part_val.strs if s is not None)

            strs.append(s)

        return value.Str(''.join(strs))
Esempio n. 2
0
def AsPosixEre(node, parts):
    # type: (re_t) -> List[str]
    """Translate an Oil regex to a POSIX ERE.

  Appends to a list of parts that you hvae to join.
  """
    tag = node.tag
    if tag == re_e.Primitive:
        if node.id == Id.Re_Dot:
            parts.append('.')
        elif node.id == Id.Re_Start:
            parts.append('^')
        elif node.id == Id.Re_End:
            parts.append('$')
        else:
            raise AssertionError(node)
        return

    if tag == re_e.LiteralChars:
        # The bash [[ x =~ "." ]] construct also has to do this

        # TODO: What about \0 and unicode escapes?
        # Those won't be as LiteralChars I don't think?
        # Unless you put them there through \0
        # Maybe DISALLOW those.
        # "Unprintable chars should be written as \0 or \x00 or \u0000"

        parts.append(glob_.ExtendedRegexEscape(node.s))
        return

    if tag == re_e.Seq:
        for c in node.children:
            AsPosixEre(c, parts)
        return

    if tag == re_e.Alt:
        for i, c in enumerate(node.children):
            if i != 0:
                parts.append('|')
            AsPosixEre(c, parts)
        return

    if tag == re_e.Repeat:
        # 'foo' or "foo" or $x or ${x} evaluated to too many chars
        if node.child.tag == re_e.LiteralChars:
            if len(node.child.s) > 1:
                # Note: Other regex dialects have non-capturing groups since we don't
                # need this.
                e_die(
                    "POSIX EREs don't have groups without capture, so this node "
                    "needs () around it.",
                    span_id=node.child.spid)

        AsPosixEre(node.child, parts)
        op = node.op
        op_tag = op.tag

        if op_tag == re_repeat_e.Op:
            op_id = op.op.id
            if op_id == Id.Arith_Plus:
                parts.append('+')
            elif op_id == Id.Arith_Star:
                parts.append('*')
            elif op_id == Id.Arith_QMark:
                parts.append('?')
            else:
                raise AssertionError(op_id)
            return

        if op_tag == re_repeat_e.Num:
            parts.append('{%s}' % op.times.val)
            return

        if op_tag == re_repeat_e.Range:
            lower = op.lower.val if op.lower else ''
            upper = op.upper.val if op.upper else ''
            parts.append('{%s,%s}' % (lower, upper))
            return

        raise NotImplementedError(node.op)

    if tag == re_e.Group:
        parts.append('(')
        AsPosixEre(node.child, parts)
        parts.append(')')
        return

    if tag == re_e.PerlClass:
        n = node.name
        chars = PERL_CLASS[node.name]  # looks like [:digit:]
        if node.negated:
            pat = '[^%s]' % chars
        else:
            pat = '[%s]' % chars
        parts.append(pat)
        return

    if tag == re_e.PosixClass:
        n = node.name  # looks like 'digit'
        if node.negated:
            pat = '[^[:%s:]]' % n
        else:
            pat = '[[:%s:]]' % n
        parts.append(pat)
        return

    if tag == re_e.ClassLiteral:
        parts.append('[')
        if node.negated:
            parts.append('^')
        for term in node.terms:
            _ClassLiteralToPosixEre(term, parts)
        parts.append(']')
        return

    raise NotImplementedError(node.__class__.__name__)