1 # Oil Blocks
2
3
4 #### cd with block
5 shopt -s oil:all
6
7 const saved = "$PWD"
8
9 # OLDPWD is NOT defined
10 cd / { echo $PWD; echo OLDPWD=${OLDPWD:-} }; echo done
11
12 if ! test "$saved" = $PWD; then
13 echo FAIL
14 fi
15
16 cd /tmp {
17 write PWD=$PWD
18 write --sep ' ' pwd builtin: $(pwd)
19 }
20
21 if ! test "$saved" = $PWD; then
22 echo FAIL
23 fi
24
25 ## STDOUT:
26 /
27 OLDPWD=
28 done
29 PWD=/tmp
30 pwd builtin: /tmp
31 ## END
32
33 #### cd with block: fatal error in block
34 shopt -s oil:all
35 cd / {
36 echo one
37 false
38 echo two
39 }
40 ## status: 1
41 ## STDOUT:
42 one
43 ## END
44
45
46 #### cd with block: return in block
47 shopt -s oil:all
48 f() {
49 cd / {
50 echo one
51 return
52 echo two
53 }
54 echo 'end func'
55 }
56 f
57 ## STDOUT:
58 one
59 end func
60 ## END
61
62 #### cd with block: break in block
63 shopt -s oil:all
64 f() {
65 cd / {
66 echo one
67 for i in 1 2; do
68 echo $i
69 break # break out of loop
70 done
71
72 break # break out of block isn't valid
73 echo two
74 }
75 echo end func
76 }
77 f
78 ## status: 1
79 ## STDOUT:
80 one
81 1
82 ## END
83
84 #### cd with block exits with status 0
85 shopt -s oil:all
86 cd / {
87 echo block
88
89 # This return value is ignored.
90 # Or maybe this should be a runtime error?
91 return 1
92 }
93 echo status=$?
94 ## STDOUT:
95 block
96 status=0
97 ## END
98
99 #### block doesn't have its own scope
100 shopt -s oil:all
101 var x = 1
102 echo "x=$x"
103 cd / {
104 #set y = 5 # This would be an error because set doesn't do dynamic lookup
105 var x = 42
106 echo "x=$x"
107 }
108 echo "x=$x"
109 ## STDOUT:
110 x=1
111 x=42
112 x=42
113 ## END
114
115 #### block literal in expression mode: ^(echo $PWD)
116 shopt -s oil:all
117
118 const myblock = ^(echo $PWD | wc -l)
119 const b2 = ^(echo one; echo two)
120 = myblock
121 = b2
122
123 # TODO:
124 # Implement something like this?
125 # _ evalexpr(b2, binding_dict) # e.g. to bind to QTSV fields
126 # _ evalblock(b2, binding_dict)
127
128 ## STDOUT:
129 one
130 two
131 ## END
132
133 #### block arg as typed expression
134
135 shopt -s oil:all
136
137 # literal
138 cd /tmp (^(echo $PWD))
139
140 const myblock = ^(echo $PWD)
141 cd /tmp (myblock)
142
143 ## STDOUT:
144 /tmp
145 /tmp
146 ## END
147
148 #### Pass invalid typed args
149
150 cd /tmp (42) # should be a block
151 echo status=$?
152
153 cd /tmp (1, 2)
154 echo status=$?
155
156 ## STDOUT:
157 status=2
158 status=2
159 ## END
160
161 #### 'builtin' and 'command' with block
162 shopt --set oil:upgrade
163 builtin cd / {
164 echo "builtin $PWD"
165 }
166 command cd / {
167 echo "command $PWD"
168 }
169 ## STDOUT:
170 builtin /
171 command /
172 ## END
173
174
175 #### Consistency: Control Flow and Blocks
176 shopt --set parse_brace
177
178 # "Invalid control flow at top level"
179 eval '
180 cd / {
181 echo cd
182 break
183 }
184 '
185 echo cd no loop $?
186
187 # warning: "Unexpected control flow in block" (strict_control_flow)
188 eval '
189 while true {
190 cd / {
191 echo cd
192 break
193 }
194 }
195 '
196 echo cd loop $?
197
198 eval '
199 while true {
200 shopt --unset errexit {
201 echo shopt
202 continue
203 }
204 }
205 '
206 echo shopt continue $?
207
208 eval '
209 while true {
210 shvar FOO=foo {
211 echo shvar
212 continue
213 }
214 }
215 '
216 echo shvar continue $?
217
218
219 eval '
220 while true {
221 try {
222 echo try
223 break
224 }
225 }
226 '
227 echo try break $?
228
229 ## STDOUT:
230 cd
231 cd no loop 0
232 cd
233 cd loop 1
234 shopt
235 shopt continue 1
236 shvar
237 shvar continue 1
238 try
239 try break 1
240 ## END
241
242 #### Consistency: Exit Status and Blocks
243 shopt --set parse_brace
244
245 cd / {
246 false
247 }
248 echo cd=$?
249
250 shopt --unset errexit {
251 false
252 }
253 echo shopt=$?
254
255 shvar FOO=foo {
256 echo " FOO=$FOO"
257 false
258 }
259 echo shvar=$?
260
261 try {
262 false
263 }
264 echo try=$?
265
266 ## STDOUT:
267 cd=0
268 shopt=0
269 FOO=foo
270 shvar=0
271 try=0
272 ## END
273
274 #### Consistency: Unwanted Blocks Are Errors
275 shopt --set parse_brace
276
277 true { echo BAD }
278 echo true $?
279
280 false ( 42, 43 )
281 echo false $?
282
283 echo { echo BAD }
284 echo echo block $?
285
286 echo ( 42, 43 )
287 echo echo args $?
288
289 command echo 'command block' { echo BAD }
290 echo command echo $?
291
292 builtin echo 'builtin block' { echo BAD }
293 echo builtin echo $?
294
295 pushd $TMP { echo BAD }
296 echo pushd $?
297
298 ## STDOUT:
299 true 2
300 false 2
301 echo block 2
302 echo args 2
303 command echo 2
304 builtin echo 2
305 pushd 2
306 ## END
307
308 #### Block with Bare Assignments
309
310 # oil:all has parse_equals
311 # is there any way to turn on parse_equals only in config blocks?
312 # but we don't know what's a block ahead of time
313 # I think we would have to check at runtime. Look at VarChecker
314
315 shopt --set oil:all
316
317 proc Rule(s; ; b) {
318 echo "rule $s"
319 }
320
321 proc myrules(name) {
322 Rule $name-python {
323 kind = 'python'
324 }
325
326 Rule $name-cc {
327 kind = 'cc' # should NOT conflict
328 }
329 }
330
331 myrules foo
332 myrules bar
333
334 ## STDOUT:
335 rule foo-python
336 rule foo-cc
337 rule bar-python
338 rule bar-cc
339 ## END
340
341 #### Block param binding
342 shopt --set parse_brace parse_proc
343
344 proc package(name, b Block) {
345 = b
346
347 var d = eval_hay(b)
348
349 # NAME and TYPE?
350 setvar d->name = name
351 setvar d->type = 'package'
352
353 # Now where does d go?
354 # Every time you do eval_hay, it clears _config?
355 # Another option: HAY_CONFIG
356
357 if ('package_list' not in _config) {
358 setvar _config->package_list = []
359 }
360 _ append(_config->package_list, d)
361 }
362
363 package unzip {
364 version = 1
365 }
366
367 ## STDOUT:
368 ## END
369
370
371 #### Proc that doesn't take a block
372 shopt --set parse_brace parse_proc
373
374 proc task(name) {
375 echo "task name=$name"
376 }
377
378 task foo {
379 echo 'running task foo'
380 }
381 # This should be an error
382 echo status=$?
383
384 ## STDOUT:
385 status=1
386 ## END