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