1 # Test var / setvar / etc.
2
3 # TODO: GetVar needs a mode where Obj[str] gets translated to value.Str?
4 # Then all code will work.
5 #
6 # word_eval:
7 #
8 # val = self.mem.GetVar(var_name) ->
9 # val = GetWordVar(self.mem, var_name)
10 #
11 # Conversely, in oil_lang/expr_eval.py:
12 # LookupVar gives you a plain Python object. I don't think there's any
13 # downside here.
14 #
15 # repr exposes the differences.
16 #
17 # Notes:
18 #
19 # - osh/cmd_exec.py handles OilAssign, which gets wrapped in value.Obj()
20 # - osh/word_eval.py _ValueToPartValue handles 3 value types. Used in:
21 # - _EvalBracedVarSub
22 # - SimpleVarSub in _EvalWordPart
23 # - osh/expr_eval.py: _LookupVar wrapper should disallow using Oil values
24 # - this is legacy stuff. Both (( )) and [[ ]]
25 # - LhsIndexedName should not reference Oil vars either
26
27
28 #### integers expression and augmented assignment
29 var x = 1 + 2 * 3
30 echo x=$x
31
32 setvar x += 4
33 echo x=$x
34 ## STDOUT:
35 x=7
36 x=11
37 ## END
38
39 #### const can't be mutated
40 proc f {
41 const x = 'local'
42 echo x=$x
43 setvar x = 'mutated'
44 echo x=$x
45 }
46 var x = 'global'
47 echo x=$x
48 f
49 echo x=$x
50 ## status: 1
51 ## STDOUT:
52 x=global
53 x=local
54 ## END
55
56 #### const can't be redeclared
57 shopt -s oil:all
58
59 x = 'foo'
60 echo x=$x
61 const x = 'bar'
62 echo x=$x
63 ## status: 1
64 ## STDOUT:
65 x=foo
66 ## END
67
68 #### 'setvar' mutates local
69 proc f {
70 var x = 'local'
71 echo x=$x
72 setvar x = 'mutated'
73 echo x=$x
74 }
75
76 var x = 'global'
77 echo x=$x
78 f
79 echo x=$x
80 ## STDOUT:
81 x=global
82 x=local
83 x=mutated
84 x=global
85 ## END
86
87 #### 'setvar' CREATES global
88 setvar x = 'global'
89 echo x=$x
90 ## STDOUT:
91 x=global
92 ## END
93
94 #### 'set' when variable isn't declared results in fatal error
95 shopt -s oil:all
96
97 var x = 1
98 f() {
99 # setting global is OK
100 setglobal x = 'XX'
101 echo x=$x
102
103 # setvar CREATES a variable
104 setvar y = 'YY'
105 echo y=$y
106
107 set z = 3 # NOT DECLARED
108 echo z=$z
109 }
110 f
111 ## status: 1
112 ## STDOUT:
113 x=XX
114 y=YY
115 ## END
116
117 #### setglobal
118 f() {
119 var x = 'local'
120 echo x=$x
121 setglobal x = 'mutated'
122 }
123 var x = 'global'
124 echo x=$x
125 f
126 echo x=$x
127 ## STDOUT:
128 x=global
129 x=local
130 x=mutated
131 ## END
132
133 #### setglobal of undeclared var is an error
134 var x = 'XX'
135 echo x=$x
136 setglobal x = 'xx'
137 echo x=$x
138
139 # fatal error
140 setglobal y = 'YY'
141
142 ## status: 1
143 ## STDOUT:
144 x=XX
145 x=xx
146 ## END
147
148
149
150
151 #### var/setvar x, y = 1, 2
152
153 # Python doesn't allow you to have annotation on each variable!
154 # https://www.python.org/dev/peps/pep-0526/#where-annotations-aren-t-allowed
155 var x Int, y Int = 3, 4
156 echo x=$x y=$y
157
158 setvar x, y = 1, 9
159 echo x=$x y=$y
160
161 setvar y, x = x, y
162 echo x=$x y=$y
163
164 ## STDOUT:
165 x=3 y=4
166 x=1 y=9
167 x=9 y=1
168 ## END
169
170 #### setvar d->key = 42 (setitem)
171 shopt -s oil:all
172
173 var d = {}
174 setvar d['f2'] = 42
175 setvar d->f3 = 43
176
177 # Use the opposite thing to retrieve
178 var f3 = d['f3']
179 var f2 = d->f2
180 echo f3=$f3
181 echo f2=$f2
182 ## STDOUT:
183 f3=43
184 f2=42
185 ## END
186
187 #### setvar mylist[1] = 42 (setitem)
188 shopt -s oil:all
189 var mylist = [1,2,3]
190 setvar mylist[1] = 42
191
192 write -sep ' ' @mylist
193 ## STDOUT:
194 1 42 3
195 ## END
196
197 #### setvar obj.attr = 42 (setattr)
198 shopt -s oil:all
199
200 # TODO: dicts and list can't have arbitrary attributes set. But right now
201 # regex objects can. Should we change that?
202
203 var myobj = /d+/
204
205 setvar myobj.x = 42
206 var val = myobj.x
207 echo val=$val
208 ## STDOUT:
209 val=42
210 ## END
211
212 #### setvar f()[2] = 42 (setitem)
213 shopt -s oil:all
214
215 var mylist = [1,2,3]
216 func f() {
217 return mylist
218 }
219 setvar f()[2] = 42
220 write @mylist
221 ## STDOUT:
222 1
223 2
224 42
225 ## END
226
227 #### duplicate var def results in fatal error
228 var x = "global"
229 f() {
230 var x = "local"
231 echo x=$x
232 }
233 f
234 var x = "redeclaration is an error"
235 ## status: 1
236 ## STDOUT:
237 x=local
238 ## END
239
240 #### setvar modified local or global scope
241 modify_with_shell_assignment() {
242 f=shell
243 }
244
245 modify_with_setvar() {
246 setvar f = "setvar"
247 }
248
249 f() {
250 var f = 1
251 echo f=$f
252 modify_with_shell_assignment
253 echo f=$f
254
255 # modifies the GLOBAL, not the one in parent scope
256 modify_with_setvar
257 echo f=$f
258 setvar f = 'local'
259 echo f=$f
260 }
261 var f = 'outer'
262 echo f=$f
263 f
264 echo f=$f
265 ## STDOUT:
266 f=outer
267 f=1
268 f=shell
269 f=shell
270 f=local
271 f=setvar
272 ## END
273
274 #### setref (not implemented)
275
276 # TODO: should be :out (rather than out Ref, because procs have no types?)
277 # or (out Ref, b Block) ?
278 proc p (s, out) {
279 setref out = 'YY'
280 }
281 var x = 'XX'
282 echo x=$x
283 p abcd :x
284 echo x=$x
285 ## STDOUT:
286 x=XX
287 x=YY
288 ## END
289
290 #### circular dict
291 var d = {name: 'foo'}
292 = d
293 setvar d['name'] = 123
294 = d
295 setvar d['name'] = 'mystr'
296 = d
297 setvar d['name'] = d
298 = d
299 ## STDOUT:
300 (Dict) {'name': 'foo'}
301 (Dict) {'name': 123}
302 (Dict) {'name': 'mystr'}
303 (Dict) {'name': {...}}
304 ## END
305
306 #### circular list
307 var L = [1,2,3]
308 = L
309 setvar L[0] = L
310 = L
311 ## STDOUT:
312 (List) [1, 2, 3]
313 (List) [[...], 2, 3]
314 ## END
315
316