def _EvalLhsArith(node, mem, arith_ev): # type: (sh_lhs_expr_t, Mem, ArithEvaluator) -> lvalue_t """sh_lhs_expr -> lvalue. Very similar to EvalLhs above in core/cmd_exec. """ assert isinstance(node, sh_lhs_expr_t), node UP_node = node with tagswitch(node) as case: if case(sh_lhs_expr_e.Name): # (( i = 42 )) node = cast(sh_lhs_expr__Name, UP_node) lval = lvalue.Named(node.name) # type: lvalue_t # TODO: location info. Use the = token? #lval.spids.append(spid) elif case(sh_lhs_expr_e.IndexedName): # (( a[42] = 42 )) node = cast(sh_lhs_expr__IndexedName, UP_node) # The index of MaybeStrArray needs to be coerced to int, but not the # index of an AssocArray. if mem.IsAssocArray(node.name, scope_e.Dynamic): key = arith_ev.EvalWordToString(node.index) lval = lvalue.Keyed(node.name, key) else: index = arith_ev.EvalToInt(node.index) lval = lvalue.Indexed(node.name, index) # TODO: location info. Use the = token? #lval.spids.append(node.spids[0]) else: raise AssertionError(node.tag_()) return lval
def EvalArithLhs(self, anode, span_id): # type: (arith_expr_t, int) -> lvalue_t """ For (( a[x] = 1 )) etc. """ UP_anode = anode if anode.tag_() == arith_expr_e.Binary: anode = cast(arith_expr__Binary, UP_anode) if anode.op_id == Id.Arith_LBracket: var_name, span_id = self._VarRefOrWord(anode.left) if var_name is not None: if self.mem.IsAssocArray(var_name, scope_e.Dynamic): key = self.EvalWordToString(anode.right) lval2 = lvalue.Keyed(var_name, key) lval2.spids.append(span_id) lval = lval2 # type: lvalue_t return lval else: index = self.EvalToInt(anode.right) lval3 = lvalue.Indexed(var_name, index) lval3.spids.append(span_id) lval = lval3 return lval var_name, span_id = self._VarRefOrWord(anode) if var_name is not None: lval1 = lvalue.Named(var_name) lval1.spids.append(span_id) lval = lval1 return lval # e.g. unset 'x-y'. status 2 for runtime parse error e_die('Invalid place to modify', span_id=span_id, status=2)
def _EvalLhsArith(node, mem, arith_ev): """sh_lhs_expr -> lvalue. Very similar to EvalLhs above in core/cmd_exec. """ assert isinstance(node, sh_lhs_expr_t), node if node.tag == sh_lhs_expr_e.Name: # (( i = 42 )) lval = lvalue.Named(node.name) # TODO: location info. Use the = token? #lval.spids.append(spid) return lval elif node.tag == sh_lhs_expr_e.IndexedName: # (( a[42] = 42 )) # The index of MaybeStrArray needs to be coerced to int, but not the index of # an AssocArray. if mem.IsAssocArray(node.name, scope_e.Dynamic): key = arith_ev.EvalWordToString(node.index) lval = lvalue.Keyed(node.name, key) else: index = arith_ev.EvalToIndex(node.index) lval = lvalue.Indexed(node.name, index) # TODO: location info. Use the = token? #lval.spids.append(node.spids[0]) else: raise AssertionError(node.tag) return lval
def EvalLhs(node, arith_ev, mem, spid, lookup_mode): """sh_lhs_expr -> lvalue. Used for a=b and a[x]=b """ assert isinstance(node, sh_lhs_expr_t), node if node.tag == sh_lhs_expr_e.Name: # a=x lval = lvalue.Named(node.name) lval.spids.append(spid) elif node.tag == sh_lhs_expr_e.IndexedName: # a[1+2]=x if mem.IsAssocArray(node.name, lookup_mode): key = arith_ev.EvalWordToString(node.index) lval = lvalue.Keyed(node.name, key) lval.spids.append(node.spids[0]) # copy left-most token over else: index = arith_ev.EvalToIndex(node.index) lval = lvalue.Indexed(node.name, index) lval.spids.append(node.spids[0]) # copy left-most token over else: raise AssertionError(node.tag) return lval
def _EvalLhsAndLookupArith(self, node): # type: (arith_expr_t) -> Tuple[int, lvalue_t] """ For x = y and x += y and ++x """ lval = self.EvalArithLhs(node, runtime.NO_SPID) val = OldValue(lval, self.mem, self.exec_opts) # BASH_LINENO, arr (array name with shopt -s compat_array), etc. if val.tag_() in (value_e.MaybeStrArray, value_e.AssocArray ) and lval.tag_() == lvalue_e.Named: named_lval = cast(lvalue__Named, lval) if word_eval.CheckCompatArray(named_lval.name, self.exec_opts): if val.tag_() == value_e.MaybeStrArray: lval = lvalue.Indexed(named_lval.name, 0) elif val.tag_() == value_e.AssocArray: lval = lvalue.Keyed(named_lval.name, '0') val = word_eval.ResolveCompatArray(val) # This error message could be better, but we already have one #if val.tag_() == value_e.MaybeStrArray: # e_die("Can't use assignment like ++ or += on arrays") span_id = location.SpanForArithExpr(node) i = self._ValToIntOrError(val, span_id=span_id) return i, lval
def EvalLhs(node, arith_ev, mem, spid, lookup_mode): # type: (sh_lhs_expr_t, ArithEvaluator, Mem, int, scope_t) -> lvalue_t """sh_lhs_expr -> lvalue. Used for a=b and a[x]=b """ assert isinstance(node, sh_lhs_expr_t), node UP_node = node lval = None # type: lvalue_t with tagswitch(node) as case: if case(sh_lhs_expr_e.Name): # a=x node = cast(sh_lhs_expr__Name, UP_node) # Note: C++ constructor doesn't take spids directly. Should we add that? lval1 = lvalue.Named(node.name) lval1.spids.append(spid) lval = lval1 elif case(sh_lhs_expr_e.IndexedName): # a[1+2]=x node = cast(sh_lhs_expr__IndexedName, UP_node) if mem.IsAssocArray(node.name, lookup_mode): key = arith_ev.EvalWordToString(node.index) # copy left-mode spid lval2 = lvalue.Keyed(node.name, key) lval2.spids.append(node.spids[0]) lval = lval2 else: index = arith_ev.EvalToInt(node.index) # copy left-mode spid lval3 = lvalue.Indexed(node.name, index) lval3.spids.append(node.spids[0]) lval = lval3 else: raise AssertionError(node.tag_()) return lval
def EvalShellLhs(self, node, spid, lookup_mode): # type: (sh_lhs_expr_t, int, scope_t) -> lvalue_t """Evaluate a shell LHS expression, i.e. place expression. For a=b and a[x]=b etc. """ assert isinstance(node, sh_lhs_expr_t), node UP_node = node lval = None # type: lvalue_t with tagswitch(node) as case: if case(sh_lhs_expr_e.Name): # a=x node = cast(sh_lhs_expr__Name, UP_node) # Note: C++ constructor doesn't take spids directly. Should we add that? lval1 = lvalue.Named(node.name) lval1.spids.append(spid) lval = lval1 elif case(sh_lhs_expr_e.IndexedName): # a[1+2]=x node = cast(sh_lhs_expr__IndexedName, UP_node) if self.mem.IsAssocArray(node.name, lookup_mode): key = self.EvalWordToString(node.index) lval2 = lvalue.Keyed(node.name, key) lval2.spids.append(node.spids[0]) lval = lval2 else: index = self.EvalToInt(node.index) lval3 = lvalue.Indexed(node.name, index) lval3.spids.append(node.spids[0]) lval = lval3 else: raise AssertionError(node.tag_()) return lval
def EvalLhsAndLookup(node, arith_ev, mem, exec_opts, lookup_mode=scope_e.Dynamic): # type: (sh_lhs_expr_t, ArithEvaluator, Mem, optview.Exec, scope_t) -> Tuple[value_t, lvalue_t] """Evaluate the operand for i++, a[0]++, i+=2, a[0]+=2 as an R-value. Also used by the Executor for s+='x' and a[42]+='x'. Args: node: syntax_asdl.sh_lhs_expr Returns: value_t, lvalue_t """ #log('sh_lhs_expr NODE %s', node) assert isinstance(node, sh_lhs_expr_t), node UP_node = node with tagswitch(node) as case: if case(sh_lhs_expr_e.Name): # a = b node = cast(sh_lhs_expr__Name, UP_node) # Problem: It can't be an array? # a=(1 2) # (( a++ )) lval = lvalue.Named(node.name) # type: lvalue_t val = _LookupVar(node.name, mem, exec_opts) elif case(sh_lhs_expr_e.IndexedName): # a[1] = b node = cast(sh_lhs_expr__IndexedName, UP_node) # See tdop.IsIndexable for valid values: # - VarRef (not Name): a[1] # - FuncCall: f(x), 1 # - Binary LBracket: f[1][1] -- no semantics for this? val = mem.GetVar(node.name) UP_val = val with tagswitch(val) as case2: if case2(value_e.Str): e_die("Can't assign to characters of string %r", node.name) elif case2(value_e.Undef): # compatible behavior: Treat it like an array. # TODO: Does this code ever get triggered? It seems like the error is # caught earlier. index = arith_ev.EvalToInt(node.index) lval = lvalue.Indexed(node.name, index) if exec_opts.nounset(): e_die("Undefined variable can't be indexed") else: val = value.Str('') elif case2(value_e.MaybeStrArray): array_val = cast(value__MaybeStrArray, UP_val) #log('ARRAY %s -> %s, index %d', node.name, array, index) index = arith_ev.EvalToInt(node.index) lval = lvalue.Indexed(node.name, index) # NOTE: Similar logic in RHS Arith_LBracket try: s = array_val.strs[index] except IndexError: s = None if s is None: val = value.Str( '') # NOTE: Other logic is value.Undef()? 0? else: assert isinstance(s, str), s val = value.Str(s) elif case2(value_e.AssocArray): # declare -A a; a['x']+=1 assoc_val = cast(value__AssocArray, UP_val) key = arith_ev.EvalWordToString(node.index) lval = lvalue.Keyed(node.name, key) s = assoc_val.d.get(key) if s is None: val = value.Str('') else: val = value.Str(s) else: raise AssertionError(val.tag_()) else: raise AssertionError(node.tag_()) return val, lval
def EvalLhsAndLookup(node, arith_ev, mem, exec_opts, lookup_mode=scope_e.Dynamic): """Evaluate the operand for i++, a[0]++, i+=2, a[0]+=2 as an R-value. Also used by the Executor for s+='x' and a[42]+='x'. Args: node: syntax_asdl.lhs_expr Returns: value_t, lvalue_t """ #log('lhs_expr NODE %s', node) assert isinstance(node, lhs_expr_t), node if node.tag == lhs_expr_e.LhsName: # a = b # Problem: It can't be an array? # a=(1 2) # (( a++ )) lval = lvalue.Named(node.name) val = _LookupVar(node.name, mem, exec_opts) elif node.tag == lhs_expr_e.LhsIndexedName: # a[1] = b # See tdop.IsIndexable for valid values: # - ArithVarRef (not LhsName): a[1] # - FuncCall: f(x), 1 # - ArithBinary LBracket: f[1][1] -- no semantics for this? val = mem.GetVar(node.name) if val.tag == value_e.Str: e_die("Can't assign to characters of string %r", node.name) elif val.tag == value_e.Undef: # compatible behavior: Treat it like an array. # TODO: Does this code ever get triggered? It seems like the error is # caught earlier. index = arith_ev.Eval(node.index) lval = lvalue.Indexed(node.name, index) if exec_opts.nounset: e_die("Undefined variable can't be indexed") else: val = value.Str('') elif val.tag == value_e.StrArray: #log('ARRAY %s -> %s, index %d', node.name, array, index) array = val.strs index = arith_ev.Eval(node.index) lval = lvalue.Indexed(node.name, index) # NOTE: Similar logic in RHS Arith_LBracket try: s = array[index] except IndexError: s = None if s is None: val = value.Str('') # NOTE: Other logic is value.Undef()? 0? else: assert isinstance(s, str), s val = value.Str(s) elif val.tag == value_e.AssocArray: # declare -A a; a['x']+=1 key = arith_ev.EvalWordToString(node.index) lval = lvalue.Keyed(node.name, key) s = val.d.get(key) if s is None: val = value.Str('') else: val = value.Str(s) else: raise AssertionError(val.tag) else: raise AssertionError(node.tag) return val, lval