Ejemplo n.º 1
0
Archivo: state.py Proyecto: bsa3/oil
    def _BindNewAssocArrayWithEntry(self, namespace, lval, value, new_flags):
        """Fill 'namespace' with a new indexed array entry."""
        d = {lval.index: value.s}  # TODO: RHS has to be string?
        new_value = value.AssocArray(d)

        # associative arrays can't be exported; don't need AssocArray flag
        readonly = var_flags_e.ReadOnly in new_flags
        namespace[lval.name] = runtime_asdl.cell(new_value, False, readonly,
                                                 False)
Ejemplo n.º 2
0
Archivo: state.py Proyecto: bsa3/oil
    def _BindNewArrayWithEntry(self, namespace, lval, value, new_flags):
        """Fill 'namespace' with a new indexed array entry."""
        items = [None] * lval.index
        items.append(value.s)
        new_value = value.StrArray(items)

        # arrays can't be exported; can't have AssocArray flag
        readonly = var_flags_e.ReadOnly in new_flags
        namespace[lval.name] = runtime_asdl.cell(new_value, False, readonly,
                                                 False)
Ejemplo n.º 3
0
Archivo: state.py Proyecto: bsa3/oil
    def SetVar(self, lval, val, new_flags, lookup_mode, strict_array=False):
        """
    Args:
      lval: lvalue
      val: value, or None if only changing flags
      new_flags: tuple of flags to set: ReadOnly | Exported
        () means no flags to start with
        None means unchanged?
      scope:
        Local | Global | Dynamic - for builtins, PWD, etc.

      NOTE: in bash, PWD=/ changes the directory.  But not in dash.
    """
        # STRICTNESS / SANENESS:
        #
        # 1) Don't create arrays automatically, e.g. a[1000]=x
        # 2) Never change types?  yeah I think that's a good idea, at least for oil
        # (not sh, for compatibility).  set -o strict-types or something.  That
        # means arrays have to be initialized with let arr = [], which is fine.
        # This helps with stuff like IFS.  It starts off as a string, and assigning
        # it to a list is en error.  I guess you will have to turn this no for
        # bash?

        assert new_flags is not None

        if lval.tag == lvalue_e.LhsName:
            #if lval.name == 'ldflags':
            # TODO: Turn this into a tracing feature.  Like osh --tracevar ldflags
            # --tracevar foo.  Has to respect environment variables too.
            if 0:
                util.log('--- SETTING ldflags to %s', val)
                if lval.spids:
                    span_id = lval.spids[0]
                    line_span = self.arena.GetLineSpan(span_id)
                    line_id = line_span.line_id
                    #line = arena.GetLine(line_id)
                    path, line_num = self.arena.GetDebugInfo(line_id)
                    col = line_span.col
                    #length = line_span.length
                    util.log('--- spid %s: %s, line %d, col %d', span_id, path,
                             line_num + 1, col)

                    # TODO: Need the arena to look it up the line spid and line number.

            # Maybe this should return one of (cell, scope).  existing cell, or the
            # scope to put it in?
            # _FindCellOrScope

            cell, namespace = self._FindCellAndNamespace(
                lval.name, lookup_mode)
            if cell:
                if val is not None:
                    if cell.readonly:
                        # TODO: error context
                        e_die("Can't assign to readonly value %r", lval.name)
                    cell.val = val
                if var_flags_e.Exported in new_flags:
                    cell.exported = True
                if var_flags_e.ReadOnly in new_flags:
                    cell.readonly = True
                if var_flags_e.AssocArray in new_flags:
                    cell.is_assoc_array = True
            else:
                if val is None:
                    # set -o nounset; local foo; echo $foo  # It's still undefined!
                    val = value.Undef()  # export foo, readonly foo
                cell = runtime_asdl.cell(val, var_flags_e.Exported
                                         in new_flags, var_flags_e.ReadOnly
                                         in new_flags, var_flags_e.AssocArray
                                         in new_flags)
                namespace[lval.name] = cell

            if (cell.val is not None and cell.val.tag == value_e.StrArray
                    and cell.exported):
                e_die("Can't export array")  # TODO: error context

        elif lval.tag == lvalue_e.LhsIndexedName:
            # TODO: All paths should have this?  We can get here by a[x]=1 or
            # (( a[ x ] = 1 )).  Maybe we should make them different?
            if lval.spids:
                left_spid = lval.spids[0]
            else:
                left_spid = const.NO_INTEGER

            # TODO: This is a parse error!
            # a[1]=(1 2 3)
            if val.tag == value_e.StrArray:
                e_die("Can't assign array to array member", span_id=left_spid)

            cell, namespace = self._FindCellAndNamespace(
                lval.name, lookup_mode)
            if not cell:
                self._BindNewArrayWithEntry(namespace, lval, val, new_flags)
                return

            # bash/mksh have annoying behavior of letting you do LHS assignment to
            # Undef, which then turns into an array.  (Undef means that set -o
            # nounset fails.)
            cell_tag = cell.val.tag
            if (cell_tag == value_e.Str
                    or (cell_tag == value_e.Undef and strict_array)):
                # s=x
                # s[1]=y  # invalid
                e_die("Entries in value of type %s can't be assigned to",
                      cell.val.__class__.__name__,
                      span_id=left_spid)

            if cell.readonly:
                e_die("Can't assign to readonly value", span_id=left_spid)

            if cell_tag == value_e.Undef:
                if cell.is_assoc_array:
                    self._BindNewAssocArrayWithEntry(namespace, lval, val,
                                                     new_flags)
                else:
                    self._BindNewArrayWithEntry(namespace, lval, val,
                                                new_flags)
                return

            if cell_tag == value_e.StrArray:
                strs = cell.val.strs
                try:
                    strs[lval.index] = val.s
                except IndexError:
                    # Fill it in with None.  It could look like this:
                    # ['1', 2, 3, None, None, '4', None]
                    # Then ${#a[@]} counts the entries that are not None.
                    #
                    # TODO: strict-array for Oil arrays won't auto-fill.
                    n = lval.index - len(strs) + 1
                    strs.extend([None] * n)
                    strs[lval.index] = val.s
                return

            if cell_tag == value_e.AssocArray:
                cell.val.d[lval.index] = val.s
                return

        else:
            raise AssertionError(lval.__class__.__name__)