def _ReconcileTypes(rval, flag_a, flag_A, span_id): # type: (Optional[value_t], bool, bool, int) -> value_t """Check that -a and -A flags are consistent with RHS. Special case: () is allowed to mean empty indexed array or empty assoc array if the context is clear. Shared between NewVar and Readonly. """ if flag_a and rval is not None and rval.tag_() != value_e.MaybeStrArray: e_usage("Got -a but RHS isn't an array", span_id=span_id) if flag_A and rval: # Special case: declare -A A=() is OK. The () is changed to mean an empty # associative array. if rval.tag_() == value_e.MaybeStrArray: array_val = cast(value__MaybeStrArray, rval) if len(array_val.strs) == 0: return value.AssocArray({}) #return value.MaybeStrArray([]) if rval.tag_() != value_e.AssocArray: e_usage("Got -A but RHS isn't an associative array", span_id=span_id) return rval
def __call__(self, cmd_val): arg_r = args.Reader(cmd_val.argv, spids=cmd_val.arg_spids) arg_r.Next() arg, arg_index = READONLY_SPEC.Parse(arg_r) for pair in cmd_val.pairs: if pair.rval is None: if arg.a: rval = value.MaybeStrArray([]) elif arg.A: rval = value.AssocArray({}) else: rval = None else: rval = pair.rval if not _CheckType(rval, arg, self.errfmt, pair.spid): return 1 # NOTE: # - when rval is None, only flags are changed # - dynamic scope because flags on locals can be changed, etc. self.mem.SetVar(pair.lval, rval, (var_flags_e.ReadOnly,), scope_e.Dynamic) return 0
def Run(self, cmd_val): # type: (cmd_value__Assign) -> int arg_r = args.Reader(cmd_val.argv, spids=cmd_val.arg_spids) arg_r.Next() attrs = flag_spec.Parse('readonly', arg_r) arg = arg_types.readonly(attrs.attrs) if arg.p or len(cmd_val.pairs) == 0: return _PrintVariables(self.mem, cmd_val, attrs, True, builtin=_READONLY) for pair in cmd_val.pairs: if pair.rval is None: if arg.a: rval = value.MaybeStrArray([]) # type: value_t elif arg.A: rval = value.AssocArray({}) else: rval = None else: rval = pair.rval rval = _ReconcileTypes(rval, arg.a, arg.A, pair.spid) # NOTE: # - when rval is None, only flags are changed # - dynamic scope because flags on locals can be changed, etc. self.mem.SetVar(lvalue.Named(pair.var_name), rval, scope_e.Dynamic, flags=state.SetReadOnly) return 0
def _BindNewAssocArrayWithEntry(self, namespace, lval, val, new_flags): """Fill 'namespace' with a new indexed array entry.""" d = {lval.index: val.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)
def __call__(self, cmd_val): arg_r = args.Reader(cmd_val.argv, spids=cmd_val.arg_spids) arg_r.Next() arg, arg_index = NEW_VAR_SPEC.Parse(arg_r) status = 0 # NOTE: in bash, -f shows the function body, while -F shows the name. In # osh, they're identical and behave like -F. if arg.f or arg.F: # Lookup and print functions. names = [pair.lval.name for pair in cmd_val.pairs] if names: for name in names: if name in self.funcs: print(name) # TODO: Could print LST, or render LST. Bash does this. 'trap' too. #print(funcs[name]) else: status = 1 elif arg.F: for func_name in sorted(self.funcs): print('declare -f %s' % (func_name)) else: raise args.UsageError('declare/typeset -f without args') return status if arg.p: # Lookup and print variables. names = [pair.lval.name for pair in cmd_val.pairs] if names: for name in names: val = self.mem.GetVar(name) if val.tag != value_e.Undef: # TODO: Print flags. print(name) else: status = 1 else: raise args.UsageError('declare/typeset -p without args') return status # # Set variables # #raise args.UsageError("doesn't understand %s" % cmd_val.argv[1:]) if cmd_val.builtin_id == builtin_e.LOCAL: lookup_mode = scope_e.LocalOnly else: # declare/typeset if arg.g: lookup_mode = scope_e.GlobalOnly else: lookup_mode = scope_e.LocalOnly flags_to_set = [] if arg.x == '-': flags_to_set.append(var_flags_e.Exported) if arg.r == '-': flags_to_set.append(var_flags_e.ReadOnly) flags_to_clear = [] if arg.x == '+': flags_to_clear.append(var_flags_e.Exported) if arg.r == '+': flags_to_clear.append(var_flags_e.ReadOnly) for pair in cmd_val.pairs: if pair.rval is None: if arg.a: rval = value.MaybeStrArray([]) elif arg.A: rval = value.AssocArray({}) else: rval = None else: rval = pair.rval if not _CheckType(rval, arg, self.errfmt, pair.spid): return 1 self.mem.SetVar(pair.lval, rval, flags_to_set, lookup_mode, flags_to_clear=flags_to_clear) return status
def Run(self, cmd_val): # type: (cmd_value__Assign) -> int arg_r = args.Reader(cmd_val.argv, spids=cmd_val.arg_spids) arg_r.Next() attrs = flag_spec.Parse('new_var', arg_r) arg = arg_types.new_var(attrs.attrs) status = 0 if arg.f: names = arg_r.Rest() if len(names): # NOTE: in bash, -f shows the function body, while -F shows the name. # Right now we just show the name. status = self._PrintFuncs(names) else: e_usage('passed -f without args') return status if arg.F: names = arg_r.Rest() if len(names): status = self._PrintFuncs(names) else: # weird bash quirk: they're printed in a different format! for func_name in sorted(self.funcs): print('declare -f %s' % (func_name)) return status if arg.p: # Lookup and print variables. return _PrintVariables(self.mem, cmd_val, attrs, True) elif len(cmd_val.pairs) == 0: return _PrintVariables(self.mem, cmd_val, attrs, False) # # Set variables # #raise error.Usage("doesn't understand %s" % cmd_val.argv[1:]) if cmd_val.builtin_id == builtin_i.local: lookup_mode = scope_e.LocalOnly else: # declare/typeset if arg.g: lookup_mode = scope_e.GlobalOnly else: lookup_mode = scope_e.LocalOnly flags = 0 if arg.x == '-': flags |= state.SetExport if arg.r == '-': flags |= state.SetReadOnly if arg.n == '-': flags |= state.SetNameref flags_to_clear = 0 if arg.x == '+': flags |= state.ClearExport if arg.r == '+': flags |= state.ClearReadOnly if arg.n == '+': flags |= state.ClearNameref for pair in cmd_val.pairs: rval = pair.rval # declare -a foo=(a b); declare -a foo; should not reset to empty array if rval is None and (arg.a or arg.A): old_val = self.mem.GetVar(pair.var_name) if arg.a: if old_val.tag_() != value_e.MaybeStrArray: rval = value.MaybeStrArray([]) elif arg.A: if old_val.tag_() != value_e.AssocArray: rval = value.AssocArray({}) rval = _ReconcileTypes(rval, arg.a, arg.A, pair.spid) self.mem.SetVar(lvalue.Named(pair.var_name), rval, lookup_mode, flags=flags) return status
def Run(self, cmd_val): # type: (cmd_value__Assign) -> int arg_r = args.Reader(cmd_val.argv, spids=cmd_val.arg_spids) arg_r.Next() attrs = flag_spec.Parse('new_var', arg_r) arg = arg_types.new_var(attrs.attrs) status = 0 if arg.f: names = arg_r.Rest() if len(names): # This is only used for a STATUS QUERY now. We only show the name, # not the body. status = self._PrintFuncs(names) else: # Disallow this since it would be incompatible. e_usage('with -f expects function names') return status if arg.F: names = arg_r.Rest() if len(names): status = self._PrintFuncs(names) else: # bash quirk: with no names, they're printed in a different format! for func_name in sorted(self.funcs): print('declare -f %s' % (func_name)) return status if arg.p: # Lookup and print variables. return _PrintVariables(self.mem, cmd_val, attrs, True) elif len(cmd_val.pairs) == 0: return _PrintVariables(self.mem, cmd_val, attrs, False) # # Set variables # #raise error.Usage("doesn't understand %s" % cmd_val.argv[1:]) if cmd_val.builtin_id == builtin_i.local: which_scopes = scope_e.LocalOnly else: # declare/typeset if arg.g: which_scopes = scope_e.GlobalOnly else: which_scopes = scope_e.LocalOnly flags = 0 if arg.x == '-': flags |= state.SetExport if arg.r == '-': flags |= state.SetReadOnly if arg.n == '-': flags |= state.SetNameref flags_to_clear = 0 if arg.x == '+': flags |= state.ClearExport if arg.r == '+': flags |= state.ClearReadOnly if arg.n == '+': flags |= state.ClearNameref for pair in cmd_val.pairs: rval = pair.rval # declare -a foo=(a b); declare -a foo; should not reset to empty array if rval is None and (arg.a or arg.A): old_val = self.mem.GetValue(pair.var_name) if arg.a: if old_val.tag_() != value_e.MaybeStrArray: rval = value.MaybeStrArray([]) elif arg.A: if old_val.tag_() != value_e.AssocArray: rval = value.AssocArray({}) rval = _ReconcileTypes(rval, arg.a, arg.A, pair.spid) self.mem.SetValue(lvalue.Named(pair.var_name), rval, which_scopes, flags=flags) return status