56
56
ClearExport = 1 << 3
57
57
SetNameref = 1 << 4
58
58
ClearNameref = 1 << 5
59
+
60
+ # For SetNamedYsh
59
61
YshDecl = 1 << 6
60
62
61
63
@@ -1228,14 +1230,17 @@ def _FrameLookup(frame, name, ysh_decl):
1228
1230
if cell :
1229
1231
return cell , frame
1230
1232
1233
+ # var, const are declarations
1234
+ # TODO: what about proc, func?
1231
1235
if not ysh_decl :
1232
1236
rear_cell = frame .get ('__E__' ) # ctx_EnclosedFrame() sets this
1233
1237
if rear_cell :
1234
1238
rear_val = rear_cell .val
1235
1239
assert rear_val , rear_val
1236
1240
if rear_val .tag () == value_e .Frame :
1237
1241
to_enclose = cast (value .Frame , rear_val ).frame
1238
- return _FrameLookup (to_enclose , name , ysh_decl ) # recursive call
1242
+ return _FrameLookup (to_enclose , name ,
1243
+ ysh_decl ) # recursive call
1239
1244
1240
1245
return None , None
1241
1246
@@ -1721,43 +1726,57 @@ def GetSpecialVar(self, op_id):
1721
1726
# Named Vars
1722
1727
#
1723
1728
1724
- def _ResolveNameOnly (self , name , which_scopes , flags ):
1725
- # type: (str, scope_t, int) -> Tuple[Optional[Cell], Dict[str, Cell]]
1726
- """Given a variable name, and scope rule, return a Cell and Frame.
1729
+ def _ResolveNameForYshMutation (self , name , which_scopes , ysh_decl ):
1730
+ # type: (str, scope_t, bool) -> Tuple[Optional[Cell], Dict[str, Cell]]
1731
+ """Simpler version of _ResolveNameOnly for YSH.
1732
+
1733
+ YSH has no namerefs, and it only has local and global mutation (setvar
1734
+ and setglobal).
1735
+ """
1736
+ if which_scopes == scope_e .LocalOnly :
1737
+ var_frame = self .var_stack [- 1 ]
1738
+ cell , result_frame = _FrameLookup (var_frame , name , ysh_decl )
1739
+ if cell :
1740
+ return cell , result_frame
1741
+ return None , var_frame
1742
+
1743
+ if which_scopes == scope_e .GlobalOnly :
1744
+ var_frame = self .var_stack [0 ]
1745
+ cell , result_frame = _FrameLookup (var_frame , name , ysh_decl )
1746
+ if cell :
1747
+ return cell , result_frame
1748
+
1749
+ return None , var_frame
1750
+
1751
+ raise AssertionError ()
1727
1752
1728
- This function does not resolve 'nameref'. It's used to get and set
1729
- variables.
1753
+ def _ResolveNameOnly (self , name , which_scopes ):
1754
+ # type: (str, scope_t) -> Tuple[Optional[Cell], Dict[str, Cell]]
1755
+ """Helper for getting and setting variable.
1730
1756
1731
1757
Returns:
1732
- cell: The cell corresponding to looking up 'name' with the given scope , or
1758
+ cell: The cell corresponding to looking up 'name' with the given mode , or
1733
1759
None if it's not found.
1734
1760
var_frame: The frame it should be set to or deleted from.
1735
1761
"""
1736
1762
if which_scopes == scope_e .Dynamic :
1737
1763
for i in xrange (len (self .var_stack ) - 1 , - 1 , - 1 ):
1738
1764
var_frame = self .var_stack [i ]
1739
- cell , result_frame = _FrameLookup (var_frame , name , bool ( flags & YshDecl ) )
1765
+ cell , result_frame = _FrameLookup (var_frame , name , False )
1740
1766
if cell :
1741
1767
return cell , result_frame
1742
1768
return None , self .var_stack [0 ] # set in global var_frame
1743
1769
1744
1770
if which_scopes == scope_e .LocalOnly :
1745
- # Stack:
1746
- # CommandEvaluator::_DoVarDecl
1747
- # Mem::SetNamed - do we need a flag for 'var'?
1748
- # Mem::_ResolveNameOrRef
1749
- # Mem::_ResolveNameOnly
1750
- #raise AssertionError()
1751
-
1752
1771
var_frame = self .var_stack [- 1 ]
1753
- cell , result_frame = _FrameLookup (var_frame , name , bool ( flags & YshDecl ) )
1772
+ cell , result_frame = _FrameLookup (var_frame , name , False )
1754
1773
if cell :
1755
1774
return cell , result_frame
1756
1775
return None , var_frame
1757
1776
1758
1777
if which_scopes == scope_e .GlobalOnly :
1759
1778
var_frame = self .var_stack [0 ]
1760
- cell , result_frame = _FrameLookup (var_frame , name , bool ( flags & YshDecl ) )
1779
+ cell , result_frame = _FrameLookup (var_frame , name , False )
1761
1780
if cell :
1762
1781
return cell , result_frame
1763
1782
@@ -1766,13 +1785,13 @@ def _ResolveNameOnly(self, name, which_scopes, flags):
1766
1785
if which_scopes == scope_e .LocalOrGlobal :
1767
1786
# Local
1768
1787
var_frame = self .var_stack [- 1 ]
1769
- cell , result_frame = _FrameLookup (var_frame , name , bool ( flags & YshDecl ) )
1788
+ cell , result_frame = _FrameLookup (var_frame , name , False )
1770
1789
if cell :
1771
1790
return cell , result_frame
1772
1791
1773
1792
# Global
1774
1793
var_frame = self .var_stack [0 ]
1775
- cell , result_frame = _FrameLookup (var_frame , name , bool ( flags & YshDecl ) )
1794
+ cell , result_frame = _FrameLookup (var_frame , name , False )
1776
1795
if cell :
1777
1796
return cell , result_frame
1778
1797
@@ -1784,15 +1803,14 @@ def _ResolveNameOrRef(
1784
1803
self ,
1785
1804
name , # type: str
1786
1805
which_scopes , # type: scope_t
1787
- flags , # type: int
1788
1806
ref_trail = None , # type: Optional[List[str]]
1789
1807
):
1790
1808
# type: (...) -> Tuple[Optional[Cell], Dict[str, Cell], str]
1791
- """Look up a cell and frame , but respect the nameref flag.
1809
+ """Look up a cell and namespace , but respect the nameref flag.
1792
1810
1793
1811
Resolving namerefs does RECURSIVE calls.
1794
1812
"""
1795
- cell , var_frame = self ._ResolveNameOnly (name , which_scopes , flags )
1813
+ cell , var_frame = self ._ResolveNameOnly (name , which_scopes )
1796
1814
1797
1815
if cell is None or not cell .nameref :
1798
1816
return cell , var_frame , name # not a nameref
@@ -1840,7 +1858,7 @@ def _ResolveNameOrRef(
1840
1858
1841
1859
# 'declare -n' uses dynamic scope.
1842
1860
cell , var_frame , cell_name = self ._ResolveNameOrRef (
1843
- new_name , scope_e .Dynamic , flags , ref_trail = ref_trail )
1861
+ new_name , scope_e .Dynamic , ref_trail = ref_trail )
1844
1862
return cell , var_frame , cell_name
1845
1863
1846
1864
def IsBashAssoc (self , name ):
@@ -1850,7 +1868,7 @@ def IsBashAssoc(self, name):
1850
1868
We need to know this to evaluate the index expression properly
1851
1869
-- should it be coerced to an integer or not?
1852
1870
"""
1853
- cell , _ , _ = self ._ResolveNameOrRef (name , self .ScopesForReading (), 0 )
1871
+ cell , _ , _ = self ._ResolveNameOrRef (name , self .ScopesForReading ())
1854
1872
# foo=([key]=value)
1855
1873
return cell is not None and cell .val .tag () == value_e .BashAssoc
1856
1874
@@ -1903,8 +1921,6 @@ def SetLocalName(self, lval, val):
1903
1921
1904
1922
# Equivalent to
1905
1923
# self._ResolveNameOnly(lval.name, scope_e.LocalOnly)
1906
-
1907
- # Note: doesn't use _FrameLookup
1908
1924
var_frame = self .var_stack [- 1 ]
1909
1925
cell = var_frame .get (lval .name )
1910
1926
@@ -1917,11 +1933,55 @@ def SetLocalName(self, lval, val):
1917
1933
cell = Cell (False , False , False , val )
1918
1934
var_frame [lval .name ] = cell
1919
1935
1920
- def SetNamed (self , lval , val , which_scopes , flags = 0 ):
1936
+ def SetNamedYsh (self , lval , val , which_scopes , flags = 0 ):
1921
1937
# type: (LeftName, value_t, scope_t, int) -> None
1938
+ """Set the value of a named variable, for YSH.
1939
+
1940
+ This has simpler logic than Mem.SetNamed(). It also handles 'const'
1941
+ and 'var' in closures, via the YshDecl flag.
1942
+ """
1943
+ # Scopes to handle: LocalOnly (setvar), GlobalOnly (setglobal)
1944
+ assert which_scopes in (scope_e .LocalOnly ,
1945
+ scope_e .GlobalOnly ), which_scopes
1946
+
1947
+ # Flags to handle: SetReadOnly (const), YshDecl (const, var)
1948
+ assert flags & ClearReadOnly == 0 , flags
1949
+
1950
+ assert flags & SetExport == 0 , flags
1951
+ assert flags & ClearExport == 0 , flags
1952
+
1953
+ assert flags & SetNameref == 0 , flags
1954
+ assert flags & ClearNameref == 0 , flags
1955
+
1956
+ cell , var_frame = self ._ResolveNameForYshMutation (
1957
+ lval .name , which_scopes , bool (flags & YshDecl ))
1958
+
1959
+ if cell :
1960
+ # Note: this DYNAMIC check means we can't have 'const' in a loop.
1961
+ # But that's true for 'readonly' too, and hoisting it makes more
1962
+ # sense anyway.
1963
+ if cell .readonly :
1964
+ e_die ("Can't assign to readonly value %r" % lval .name ,
1965
+ lval .blame_loc )
1966
+ cell .val = val # CHANGE VAL
1967
+
1968
+ if flags & SetReadOnly :
1969
+ cell .readonly = True
1970
+
1971
+ else :
1972
+ cell = Cell (False , bool (flags & SetReadOnly ), False , val )
1973
+ var_frame [lval .name ] = cell
1974
+
1975
+ # Maintain invariant that only strings and undefined cells can be
1976
+ # exported.
1977
+ assert cell .val is not None , cell
1978
+
1979
+ def SetNamed (self , lval , val , which_scopes , flags = 0 ):
1980
+ # type: (LeftName, Optional[value_t], scope_t, int) -> None
1981
+ """Set the value of a named variable."""
1922
1982
if flags & SetNameref or flags & ClearNameref :
1923
1983
# declare -n ref=x # refers to the ref itself
1924
- cell , var_frame = self ._ResolveNameOnly (lval .name , which_scopes , flags )
1984
+ cell , var_frame = self ._ResolveNameOnly (lval .name , which_scopes )
1925
1985
cell_name = lval .name
1926
1986
else :
1927
1987
# ref=x # mutates THROUGH the reference
@@ -1933,7 +1993,7 @@ def SetNamed(self, lval, val, which_scopes, flags=0):
1933
1993
# 3. Turn BracedVarSub into an sh_lvalue, and call
1934
1994
# self.unsafe_arith.SetValue() wrapper with ref_trail
1935
1995
cell , var_frame , cell_name = self ._ResolveNameOrRef (
1936
- lval .name , which_scopes , flags )
1996
+ lval .name , which_scopes )
1937
1997
1938
1998
if cell :
1939
1999
# Clear before checking readonly bit.
@@ -2036,7 +2096,7 @@ def SetValue(self, lval, val, which_scopes, flags=0):
2036
2096
# Undef, which then turns into an INDEXED array. (Undef means that set
2037
2097
# -o nounset fails.)
2038
2098
cell , var_frame , _ = self ._ResolveNameOrRef (
2039
- lval .name , which_scopes , flags )
2099
+ lval .name , which_scopes )
2040
2100
if not cell :
2041
2101
self ._BindNewArrayWithEntry (var_frame , lval , rval , flags ,
2042
2102
left_loc )
@@ -2098,7 +2158,7 @@ def SetValue(self, lval, val, which_scopes, flags=0):
2098
2158
left_loc = lval .blame_loc
2099
2159
2100
2160
cell , var_frame , _ = self ._ResolveNameOrRef (
2101
- lval .name , which_scopes , flags )
2161
+ lval .name , which_scopes )
2102
2162
if cell .readonly :
2103
2163
e_die ("Can't assign to readonly associative array" ,
2104
2164
left_loc )
@@ -2310,7 +2370,7 @@ def GetValue(self, name, which_scopes=scope_e.Shopt):
2310
2370
# 1. Call self.unsafe_arith.ParseVarRef() -> BracedVarSub
2311
2371
# 2. Call self.unsafe_arith.GetNameref(bvs_part), and get a value_t
2312
2372
# We still need a ref_trail to detect cycles.
2313
- cell , _ , _ = self ._ResolveNameOrRef (name , which_scopes , 0 )
2373
+ cell , _ , _ = self ._ResolveNameOrRef (name , which_scopes )
2314
2374
if cell :
2315
2375
return cell .val
2316
2376
@@ -2336,7 +2396,7 @@ def GetCell(self, name, which_scopes=scope_e.Shopt):
2336
2396
if which_scopes == scope_e .Shopt :
2337
2397
which_scopes = self .ScopesForReading ()
2338
2398
2339
- cell , _ = self ._ResolveNameOnly (name , which_scopes , 0 )
2399
+ cell , _ = self ._ResolveNameOnly (name , which_scopes )
2340
2400
return cell
2341
2401
2342
2402
def GetCellDeref (self , name , which_scopes = scope_e .Shopt ):
@@ -2347,7 +2407,7 @@ def GetCellDeref(self, name, which_scopes=scope_e.Shopt):
2347
2407
if which_scopes == scope_e .Shopt :
2348
2408
which_scopes = self .ScopesForReading ()
2349
2409
2350
- cell , _ , _ = self ._ResolveNameOrRef (name , which_scopes , 0 )
2410
+ cell , _ , _ = self ._ResolveNameOrRef (name , which_scopes )
2351
2411
return cell
2352
2412
2353
2413
def Unset (self , lval , which_scopes ):
@@ -2376,7 +2436,7 @@ def Unset(self, lval, which_scopes):
2376
2436
which_scopes = self .ScopesForWriting ()
2377
2437
2378
2438
cell , var_frame , cell_name = self ._ResolveNameOrRef (
2379
- var_name , which_scopes , 0 )
2439
+ var_name , which_scopes )
2380
2440
if not cell :
2381
2441
return False # 'unset' builtin falls back on functions
2382
2442
if cell .readonly :
@@ -2460,7 +2520,7 @@ def ClearFlag(self, name, flag):
2460
2520
We don't use SetValue() because even if rval is None, it will make an
2461
2521
Undef value in a scope.
2462
2522
"""
2463
- cell , var_frame = self ._ResolveNameOnly (name , self .ScopesForReading (), 0 )
2523
+ cell , var_frame = self ._ResolveNameOnly (name , self .ScopesForReading ())
2464
2524
if cell :
2465
2525
if flag & ClearExport :
2466
2526
cell .exported = False
0 commit comments