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 #### setlocal works (with bin/osh, no shopt)
118 proc p {
119 var x = 5
120 echo $x
121 setlocal x = 42
122 echo $x
123 }
124 p
125 ## STDOUT:
126 5
127 42
128 ## END
129
130 #### setlocal at top level
131 var x = 1
132 setlocal x = 42
133 echo $x
134 setlocal y = 50 # error because it's not declared
135 ## status: 1
136 ## STDOUT:
137 42
138 ## END
139
140 #### setlocal doesn't mutate globals
141 proc p() {
142 var g = 1
143 setlocal g = 2
144 }
145 var g = 42
146 p
147 echo $g
148 ## STDOUT:
149 42
150 ## END
151
152 #### setglobal
153 f() {
154 var x = 'local'
155 echo x=$x
156 setglobal x = 'mutated'
157 }
158 var x = 'global'
159 echo x=$x
160 f
161 echo x=$x
162 ## STDOUT:
163 x=global
164 x=local
165 x=mutated
166 ## END
167
168 #### setglobal of undeclared var is an error
169 var x = 'XX'
170 echo x=$x
171 setglobal x = 'xx'
172 echo x=$x
173
174 # fatal error
175 setglobal y = 'YY'
176
177 ## status: 1
178 ## STDOUT:
179 x=XX
180 x=xx
181 ## END
182
183
184
185
186 #### var/setvar x, y = 1, 2
187
188 # Python doesn't allow you to have annotation on each variable!
189 # https://www.python.org/dev/peps/pep-0526/#where-annotations-aren-t-allowed
190 var x Int, y Int = 3, 4
191 echo x=$x y=$y
192
193 setvar x, y = 1, 9
194 echo x=$x y=$y
195
196 setvar y, x = x, y
197 echo x=$x y=$y
198
199 ## STDOUT:
200 x=3 y=4
201 x=1 y=9
202 x=9 y=1
203 ## END
204
205 #### setvar d->key = 42 (setitem)
206 shopt -s oil:all
207
208 var d = {}
209 setvar d['f2'] = 42
210 setvar d->f3 = 43
211
212 # Use the opposite thing to retrieve
213 var f3 = d['f3']
214 var f2 = d->f2
215 echo f3=$f3
216 echo f2=$f2
217 ## STDOUT:
218 f3=43
219 f2=42
220 ## END
221
222 #### setvar mylist[1] = 42 (setitem)
223 shopt -s oil:all
224 var mylist = [1,2,3]
225 setvar mylist[1] = 42
226
227 write -sep ' ' @mylist
228 ## STDOUT:
229 1 42 3
230 ## END
231
232 #### setvar obj.attr = 42 (setattr)
233 shopt -s oil:all
234
235 # TODO: dicts and list can't have arbitrary attributes set. But right now
236 # regex objects can. Should we change that?
237
238 var myobj = /d+/
239
240 setvar myobj.x = 42
241 var val = myobj.x
242 echo val=$val
243 ## STDOUT:
244 val=42
245 ## END
246
247 #### setvar f()[2] = 42 (setitem)
248 shopt -s oil:all
249
250 var mylist = [1,2,3]
251 func f() {
252 return mylist
253 }
254 setvar f()[2] = 42
255 write @mylist
256 ## STDOUT:
257 1
258 2
259 42
260 ## END
261
262 #### duplicate var def results in fatal error
263 var x = "global"
264 f() {
265 var x = "local"
266 echo x=$x
267 }
268 f
269 var x = "redeclaration is an error"
270 ## status: 1
271 ## STDOUT:
272 x=local
273 ## END
274
275 #### setvar modified local or global scope
276 modify_with_shell_assignment() {
277 f=shell
278 }
279
280 modify_with_setvar() {
281 setvar f = "setvar"
282 }
283
284 f() {
285 var f = 1
286 echo f=$f
287 modify_with_shell_assignment
288 echo f=$f
289
290 # modifies the GLOBAL, not the one in parent scope
291 modify_with_setvar
292 echo f=$f
293 setvar f = 'local'
294 echo f=$f
295 }
296 var f = 'outer'
297 echo f=$f
298 f
299 echo f=$f
300 ## STDOUT:
301 f=outer
302 f=1
303 f=shell
304 f=shell
305 f=local
306 f=setvar
307 ## END
308
309 #### setref (not implemented)
310
311 # TODO: should be :out (rather than out Ref, because procs have no types?)
312 # or (out Ref, b Block) ?
313 proc p (s, out) {
314 setref out = 'YY'
315 }
316 var x = 'XX'
317 echo x=$x
318 p abcd :x
319 echo x=$x
320 ## STDOUT:
321 x=XX
322 x=YY
323 ## END
324
325 #### circular dict
326 var d = {name: 'foo'}
327 = d
328 setvar d['name'] = 123
329 = d
330 setvar d['name'] = 'mystr'
331 = d
332 setvar d['name'] = d
333 = d
334 ## STDOUT:
335 (Dict) {'name': 'foo'}
336 (Dict) {'name': 123}
337 (Dict) {'name': 'mystr'}
338 (Dict) {'name': {...}}
339 ## END
340
341 #### circular list
342 var L = [1,2,3]
343 = L
344 setvar L[0] = L
345 = L
346 ## STDOUT:
347 (List) [1, 2, 3]
348 (List) [[...], 2, 3]
349 ## END
350
351