def testPushTemp(self): mem = _InitMem() # x=1 mem.SetVar( lvalue.LhsName('x'), value.Str('1'), (), scope_e.Dynamic) self.assertEqual('1', mem.var_stack[-1].vars['x'].val.s) mem.PushTemp() self.assertEqual(2, len(mem.var_stack)) # Temporary frame is immutable self.assertEqual(False, mem.var_stack[-1].mutable) self.assertEqual(True, mem.var_stack[-2].mutable) # x=temp E=3 read x <<< 'line' mem.SetVar( lvalue.LhsName('x'), value.Str('temp'), (), scope_e.TempEnv) mem.SetVar( lvalue.LhsName('E'), value.Str('3'), (), scope_e.TempEnv) mem.SetVar( lvalue.LhsName('x'), value.Str('line'), (), scope_e.LocalOnly) self.assertEqual('3', mem.var_stack[-1].vars['E'].val.s) self.assertEqual('temp', mem.var_stack[-1].vars['x'].val.s) self.assertEqual('line', mem.var_stack[-2].vars['x'].val.s) mem.PopTemp() self.assertEqual(1, len(mem.var_stack)) self.assertEqual('line', mem.var_stack[-1].vars['x'].val.s)
def testPushTemp(self): mem = _InitMem() # x=1 mem.SetVar( lvalue.LhsName('x'), value.Str('1'), (), scope_e.Dynamic) self.assertEqual('1', mem.var_stack[-1]['x'].val.s) mem.PushTemp() self.assertEqual(2, len(mem.var_stack)) # x=temp E=3 read x <<< 'line' mem.SetVar( lvalue.LhsName('x'), value.Str('temp'), (), scope_e.LocalOnly) mem.SetVar( lvalue.LhsName('E'), value.Str('3'), (), scope_e.LocalOnly) mem.SetVar( lvalue.LhsName('x'), value.Str('line'), (), scope_e.LocalOnly) self.assertEqual('3', mem.var_stack[-1]['E'].val.s) self.assertEqual('line', mem.var_stack[-1]['x'].val.s) self.assertEqual('1', mem.var_stack[-2]['x'].val.s) mem.PopTemp() self.assertEqual(1, len(mem.var_stack)) self.assertEqual('1', mem.var_stack[-1]['x'].val.s)
def testExportThenAssign(self): """Regression Test""" mem = _InitMem() # export U mem.SetVar(lvalue.LhsName('U'), None, (var_flags_e.Exported, ), scope_e.Dynamic) print(mem) # U=u mem.SetVar(lvalue.LhsName('U'), value.Str('u'), (), scope_e.Dynamic) print(mem) e = mem.GetExported() self.assertEqual('u', e['U'])
def Export(argv, mem): arg, i = EXPORT_SPEC.Parse(argv) if arg.n: for name in argv[i:]: m = match.IsValidVarName(name) if not m: raise args.UsageError('export: Invalid variable name %r' % name) # NOTE: bash doesn't care if it wasn't found. mem.ClearFlag(name, var_flags_e.Exported, scope_e.Dynamic) else: for arg in argv[i:]: parts = arg.split('=', 1) if len(parts) == 1: name = parts[0] val = None # Creates an empty variable else: name, s = parts val = value.Str(s) m = match.IsValidVarName(name) if not m: raise args.UsageError('export: Invalid variable name %r' % name) #log('%s %s', name, val) mem.SetVar(lvalue.LhsName(name), val, (var_flags_e.Exported, ), scope_e.Dynamic) return 0
def _EvalLhsArith(self, node): """lhs_expr -> lvalue. Very similar to _EvalLhs in core/cmd_exec. """ assert isinstance(node, lhs_expr_t), node if node.tag == lhs_expr_e.LhsName: # (( i = 42 )) lval = lvalue.LhsName(node.name) # TODO: location info. Use the = token? #lval.spids.append(spid) return lval if node.tag == lhs_expr_e.LhsIndexedName: # (( a[42] = 42 )) # The index of StrArray needs to be coerced to int, but not the index of # an AssocArray. int_coerce = not self.mem.IsAssocArray(node.name, scope_e.Dynamic) index = self.Eval(node.index, int_coerce=int_coerce) lval = lvalue.LhsIndexedName(node.name, index) # TODO: location info. Use the = token? #lval.spids.append(node.spids[0]) return lval raise AssertionError(node.tag)
def _EvalTempEnv(self, more_env): """For FOO=1 cmd.""" for env_pair in more_env: val = self.word_ev.EvalWordToString(env_pair.val) # Set each var so the next one can reference it. Example: # FOO=1 BAR=$FOO ls / self.mem.SetVar(lvalue.LhsName(env_pair.name), val, (var_flags_e.Exported,), scope_e.TempEnv)
def testUnset(self): mem = _InitMem() # unset a mem.Unset(lvalue.LhsName('a'), scope_e.Dynamic) return # not implemented yet # unset a[1] mem.Unset(lvalue.LhsIndexedName('a', 1), scope_e.Dynamic)
def testGetVar(self): mem = _InitMem() # readonly a=x mem.SetVar(lvalue.LhsName('a'), value.Str('x'), (var_flags_e.ReadOnly, ), scope_e.Dynamic) val = mem.GetVar('a', scope_e.Dynamic) test_lib.AssertAsdlEqual(self, value.Str('x'), val) val = mem.GetVar('undef', scope_e.Dynamic) test_lib.AssertAsdlEqual(self, value.Undef(), val)
def Unset(argv, mem, funcs): arg, i = UNSET_SPEC.Parse(argv) for name in argv[i:]: if arg.f: if name in funcs: del funcs[name] elif arg.v: ok, _ = mem.Unset(lvalue.LhsName(name), scope_e.Dynamic) if not ok: util.error("Can't unset readonly variable %r", name) return 1 else: # Try to delete var first, then func. ok, found = mem.Unset(lvalue.LhsName(name), scope_e.Dynamic) if not ok: util.error("Can't unset readonly variable %r", name) return 1 #log('%s: %s', name, found) if not found: if name in funcs: del funcs[name] return 0
def _EvalLhs(self, node, spid, lookup_mode): """lhs_expr -> lvalue.""" assert isinstance(node, lhs_expr_t), node if node.tag == lhs_expr_e.LhsName: # a=x lval = lvalue.LhsName(node.name) lval.spids.append(spid) return lval if node.tag == lhs_expr_e.LhsIndexedName: # a[1+2]=x # The index of StrArray needs to be coerced to int, but not the index of # an AssocArray. int_coerce = not self.mem.IsAssocArray(node.name, lookup_mode) index = self.arith_ev.Eval(node.index, int_coerce=int_coerce) lval = lvalue.LhsIndexedName(node.name, index) lval.spids.append(node.spids[0]) # copy left-most token over return lval raise AssertionError(node.tag)
def testSetVarClearFlag(self): mem = _InitMem() print(mem) mem.PushCall('my-func', 0, ['ONE']) self.assertEqual(2, len(mem.var_stack)) # internal details # local x=y mem.SetVar( lvalue.LhsName('x'), value.Str('y'), (), scope_e.LocalOnly) self.assertEqual('y', mem.var_stack[-1]['x'].val.s) # New frame mem.PushCall('my-func', 0, ['TWO']) self.assertEqual(3, len(mem.var_stack)) # internal details # x=y -- test out dynamic scope mem.SetVar( lvalue.LhsName('x'), value.Str('YYY'), (), scope_e.Dynamic) self.assertEqual('YYY', mem.var_stack[-2]['x'].val.s) self.assertEqual(None, mem.var_stack[-1].get('x')) # myglobal=g mem.SetVar( lvalue.LhsName('myglobal'), value.Str('g'), (), scope_e.Dynamic) self.assertEqual('g', mem.var_stack[0]['myglobal'].val.s) self.assertEqual(False, mem.var_stack[0]['myglobal'].exported) # 'export PYTHONPATH=/' mem.SetVar( lvalue.LhsName('PYTHONPATH'), value.Str('/'), (var_flags_e.Exported,), scope_e.Dynamic) self.assertEqual('/', mem.var_stack[0]['PYTHONPATH'].val.s) self.assertEqual(True, mem.var_stack[0]['PYTHONPATH'].exported) ex = mem.GetExported() self.assertEqual('/', ex['PYTHONPATH']) mem.SetVar( lvalue.LhsName('PYTHONPATH'), None, (var_flags_e.Exported,), scope_e.Dynamic) self.assertEqual(True, mem.var_stack[0]['PYTHONPATH'].exported) # 'export myglobal'. None means don't touch it. Undef would be confusing # because it might mean "unset", but we have a separated API for that. mem.SetVar( lvalue.LhsName('myglobal'), None, (var_flags_e.Exported,), scope_e.Dynamic) self.assertEqual(True, mem.var_stack[0]['myglobal'].exported) # export g2 -- define and export empty mem.SetVar( lvalue.LhsName('g2'), None, (var_flags_e.Exported,), scope_e.Dynamic) self.assertEqual(value_e.Undef, mem.var_stack[0]['g2'].val.tag) self.assertEqual(True, mem.var_stack[0]['g2'].exported) # readonly myglobal self.assertEqual(False, mem.var_stack[0]['myglobal'].readonly) mem.SetVar( lvalue.LhsName('myglobal'), None, (var_flags_e.ReadOnly,), scope_e.Dynamic) self.assertEqual(True, mem.var_stack[0]['myglobal'].readonly) mem.SetVar( lvalue.LhsName('PYTHONPATH'), value.Str('/lib'), (), scope_e.Dynamic) self.assertEqual('/lib', mem.var_stack[0]['PYTHONPATH'].val.s) self.assertEqual(True, mem.var_stack[0]['PYTHONPATH'].exported) # COMPREPLY=(1 2 3) # invariant to enforce: arrays can't be exported mem.SetVar( lvalue.LhsName('COMPREPLY'), value.StrArray(['1', '2', '3']), (), scope_e.GlobalOnly) self.assertEqual( ['1', '2', '3'], mem.var_stack[0]['COMPREPLY'].val.strs) # export COMPREPLY try: mem.SetVar( lvalue.LhsName('COMPREPLY'), None, (var_flags_e.Exported,), scope_e.Dynamic) except util.FatalRuntimeError as e: pass else: self.fail("Expected failure") # readonly r=1 mem.SetVar( lvalue.LhsName('r'), value.Str('1'), (var_flags_e.ReadOnly,), scope_e.Dynamic) self.assertEqual('1', mem.var_stack[0]['r'].val.s) self.assertEqual(False, mem.var_stack[0]['r'].exported) self.assertEqual(True, mem.var_stack[0]['r'].readonly) print(mem) # r=newvalue try: mem.SetVar( lvalue.LhsName('r'), value.Str('newvalue'), (), scope_e.Dynamic) except util.FatalRuntimeError as e: pass else: self.fail("Expected failure") # readonly r2 -- define empty readonly mem.SetVar( lvalue.LhsName('r2'), None, (var_flags_e.ReadOnly,), scope_e.Dynamic) self.assertEqual(value_e.Undef, mem.var_stack[0]['r2'].val.tag) self.assertEqual(True, mem.var_stack[0]['r2'].readonly) # export -n PYTHONPATH # Remove the exported property. NOTE: scope is LocalOnly for Oil? self.assertEqual(True, mem.var_stack[0]['PYTHONPATH'].exported) mem.ClearFlag('PYTHONPATH', var_flags_e.Exported, scope_e.Dynamic) self.assertEqual(False, mem.var_stack[0]['PYTHONPATH'].exported) lhs = lvalue.LhsIndexedName('a', 1) lhs.spids.append(0) # a[1]=2 mem.SetVar(lhs, value.Str('2'), (), scope_e.Dynamic) self.assertEqual([None, '2'], mem.var_stack[0]['a'].val.strs) # a[1]=3 mem.SetVar(lhs, value.Str('3'), (), scope_e.Dynamic) self.assertEqual([None, '3'], mem.var_stack[0]['a'].val.strs) # a[1]=(x y z) # illegal try: mem.SetVar(lhs, value.StrArray(['x', 'y', 'z']), (), scope_e.Dynamic) except util.FatalRuntimeError as e: pass else: self.fail("Expected failure") # readonly a mem.SetVar( lvalue.LhsName('a'), None, (var_flags_e.ReadOnly,), scope_e.Dynamic) self.assertEqual(True, mem.var_stack[0]['a'].readonly) try: # a[1]=3 mem.SetVar(lhs, value.Str('3'), (), scope_e.Dynamic) except util.FatalRuntimeError as e: pass else: self.fail("Expected failure")
def EvalLhsAndLookup(node, arith_ev, mem, exec_opts): """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.LhsName(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? index = arith_ev.Eval(node.index) lval = lvalue.LhsIndexedName(node.name, index) 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: # It would make more sense for 'nounset' to control this, but bash # doesn't work that way. #if self.exec_opts.strict_arith: # e_die('Undefined array %r', node.name) val = value.Str('') elif val.tag == value_e.StrArray: #log('ARRAY %s -> %s, index %d', node.name, array, index) array = val.strs # NOTE: Similar logic in RHS Arith_LBracket try: item = array[index] except IndexError: item = None if item is None: val = value.Str('') else: assert isinstance(item, str), item val = value.Str(item) elif val.tag == value_e.AssocArray: # declare -A a; a['x']+=1 # TODO: Also need IsAssocArray() check? index = arith_ev.Eval(node.index, int_coerce=False) lval = lvalue.LhsIndexedName(node.name, index) raise NotImplementedError else: raise AssertionError(val.tag) else: raise AssertionError(node.tag) return val, lval