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)
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
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)
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