Exemple #1
0
  def _SetInScope(self, scope, pairs):
    for lhs, val in pairs:
      #log('SETTING %s -> %s', lhs, value)
      assert val.tag in (value_e.Str, value_e.StrArray)

      name = lhs.name
      if name in scope:
        # Preserve cell flags.  For example, could be Undef and exported!
        scope[name].val = val
      else:
        scope[name] = runtime.cell(val, False, False)
Exemple #2
0
  def _SetLocalOrGlobal(self, name, val):
    # TODO:
    # - Use _FindInScope helper?  So we preserve flags.
    # - Optionally disable dynamic scope
    # - Implement readonly, etc.  Test the readonly flag!
    cell = runtime.cell(val, False, False)

    for i in range(len(self.var_stack) - 1, -1, -1):  # This implements dynamic scope.
      scope = self.var_stack[i]
      if name in scope:
        scope[name] = cell
        break
    else:
      global_scope = self.var_stack[0]
      global_scope[name] = cell
Exemple #3
0
  def SetExportFlag(self, name, b):
    """
    First look for local, then global
    """
    found = False
    for i in range(len(self.var_stack) - 1, -1, -1):
      scope = self.var_stack[i]
      if name in scope:
        cell = scope[name]
        cell.exported = b
        found = True
        break

    if not found:
      # You can export an undefined variable!
      scope[name] = runtime.cell(runtime.Undef(), True, False)
Exemple #4
0
  def SetVar(self, lval, value, new_flags, lookup_mode):
    """
    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:
      # 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 value is not None:
          if cell.readonly:
            # TODO: error context
            e_die("Can't assign to readonly value %r", lval.name)
          cell.val = value
        if var_flags.Exported in new_flags:
          cell.exported = True
        if var_flags.ReadOnly in new_flags:
          cell.readonly = True
      else:
        if value is None:
          value = runtime.Str('')  # export foo, readonly foo
        cell = runtime.cell(value,
                            var_flags.Exported in new_flags ,
                            var_flags.ReadOnly 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:
      # a[1]=(1 2 3)
      if value.tag == value_e.StrArray:
        e_die("Can't assign array to array member")  # TODO: error context

      cell, namespace = self._FindCellAndNamespace(lval.name, lookup_mode)
      if cell:
        if cell.val.tag != value_e.StrArray:
          # s=x
          # s[1]=y
          e_die("Can't index non-array")  # TODO: error context

        if cell.readonly:
          e_die("Can't assign to readonly value")

        strs = cell.val.strs
        try:
          strs[lval.index] = value.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 = len(strs) - lval.index + 1
          strs.extend([None] * n)
          strs[lval.index] = value.s
      else:
        # TODO:
        # - This is a bug, because a[2]=2 creates an array of length ONE, even
        # though the index is two.
        # - Maybe represent as hash table?  Then it's not an ASDL type?

        # representations:
        # - array_item.Str array_item.Undef
        # - parallel array: val.strs, val.undefs
        # - or change ASDL type checking
        #   - ASDL language does not allow: StrArray(string?* strs)
        # - or add dict to ASDL?  Didn't it support obj?
        #   - finding the max index is linear time?
        #     - also you have to sort the indices
        #
        # array ops:
        # a=(1 2)
        # a[1]=x
        # a+=(1 2)
        # ${a[@]}  - get all
        # ${#a[@]} - length
        # ${!a[@]} - keys
        # That seems pretty minimal.

        items = [''] * lval.index
        items.append(value.s)
        new_value = runtime.StrArray(items)
        # arrays can't be exported
        cell = runtime.cell(new_value, False,
                            var_flags.ReadOnly in new_flags)
        namespace[lval.name] = cell

    else:
      raise AssertionError