1 # Configuration
2 #
3 # Hay: Hay Ain't YAML
4
5 #### use bin
6 use
7 echo status=$?
8 use z
9 echo status=$?
10
11 use bin
12 echo bin status=$?
13 use bin sed grep
14 echo bin status=$?
15
16 ## STDOUT:
17 status=2
18 status=2
19 bin status=0
20 bin status=0
21 ## END
22
23 #### use dialect
24 shopt --set parse_brace
25
26 use dialect
27 echo status=$?
28
29 use dialect ninja
30 echo status=$?
31
32 shvar _DIALECT=oops {
33 use dialect ninja
34 echo status=$?
35 }
36
37 shvar _DIALECT=ninja {
38 use dialect ninja
39 echo status=$?
40 }
41
42 ## STDOUT:
43 status=2
44 status=1
45 status=1
46 status=0
47 ## END
48
49 #### hay builtin usage
50
51 hay define
52 echo status=$?
53
54 hay define -- package user
55 echo status=$?
56
57 hay pp | wc -l | read n
58 echo read $?
59 test $n -gt 0
60 echo greater $?
61
62 ## STDOUT:
63 status=2
64 status=0
65 read 0
66 greater 0
67 ## END
68
69 #### hay reset
70 shopt --set parse_brace
71
72 hay define package
73
74 hay eval :a {
75 package foo
76 echo "package $?"
77 }
78
79 hay reset # no more names
80
81 echo "reset $?"
82
83 hay eval :b {
84 package foo
85 echo "package $?"
86 }
87
88 ## status: 127
89 ## STDOUT:
90 package 0
91 reset 0
92 ## END
93
94
95 #### hay eval can't be nested
96 shopt --set parse_brace
97
98 hay eval :foo {
99 echo foo
100 hay eval :bar {
101 echo bar
102 }
103 }
104 ## status: 127
105 ## STDOUT:
106 foo
107 ## END
108
109 #### hay names at top level
110 shopt --set parse_brace parse_at
111 shopt --unset errexit
112
113 hay define Package
114
115 Package one
116 echo status=$?
117
118 setvar args = _hay()['children'][0]['args']
119 write --sep ' ' $[len(_hay()['children'])] @args
120
121 hay eval :result {
122 Package two
123 echo status=$?
124 }
125
126 setvar args = result['children'][0]['args']
127 write --sep ' ' $[len(result['children'])] @args
128
129 Package three
130 echo status=$?
131
132 setvar args = _hay()['children'][0]['args']
133 write --sep ' ' $[len(_hay()['children'])] $[_hay()['children'][0]['args'][0]]
134
135 ## STDOUT:
136 status=0
137 1 one
138 status=0
139 1 two
140 status=0
141 1 three
142 ## END
143
144 #### Parsing Nested Attributes nodes (bug fix)
145
146 shopt --set parse_brace parse_equals
147
148 hay define Package/License
149
150 Package glibc {
151 version = '1.0'
152
153 License {
154 path = 'LICENSE.txt'
155 }
156
157 other = 'foo'
158 }
159
160 json write (_hay()) | jq '.children[0].children[0].attrs' > actual.txt
161
162 diff -u - actual.txt <<EOF
163 {
164 "path": "LICENSE.txt"
165 }
166 EOF
167
168 invalid = 'syntax' # parse error
169
170 ## status: 2
171 ## STDOUT:
172 ## END
173
174
175 #### hay eval attr node, and JSON
176 shopt --set parse_brace parse_equals
177
178 hay define Package User
179
180 hay eval :result {
181 Package foo {
182 # not doing floats now
183 int = 42
184 bool = true
185 mynull = null
186 mystr = $'spam\n'
187
188 mylist = [5, 'foo', {}]
189 # TODO: Dict literals need to be in insertion order!
190 #mydict = {alice: 10, bob: 20}
191 }
192
193 User alice
194 }
195
196 # Note: using jq to normalize
197 json write (result) | jq . > out.txt
198
199 diff -u - out.txt <<EOF
200 {
201 "source": null,
202 "children": [
203 {
204 "type": "Package",
205 "args": [
206 "foo"
207 ],
208 "children": [],
209 "attrs": {
210 "int": 42,
211 "bool": true,
212 "mynull": null,
213 "mystr": "spam\n",
214 "mylist": [
215 5,
216 "foo",
217 {}
218 ]
219 }
220 },
221 {
222 "type": "User",
223 "args": [
224 "alice"
225 ]
226 }
227 ]
228 }
229 EOF
230
231 echo "diff $?"
232
233 ## STDOUT:
234 diff 0
235 ## END
236
237 #### hay eval shell node, and JSON
238 shopt --set parse_brace parse_equals
239
240 hay define TASK
241
242 hay eval :result {
243 TASK { echo hi }
244
245 TASK {
246 echo one
247 echo two
248 }
249 }
250
251 #= result
252 json write (result) | jq . > out.txt
253
254 diff -u - out.txt <<'EOF'
255 {
256 "source": null,
257 "children": [
258 {
259 "type": "TASK",
260 "args": [],
261 "location_str": "[ stdin ]",
262 "location_start_line": 6,
263 "code_str": " echo hi "
264 },
265 {
266 "type": "TASK",
267 "args": [],
268 "location_str": "[ stdin ]",
269 "location_start_line": 8,
270 "code_str": " \n echo one\n echo two\n "
271 }
272 ]
273 }
274 EOF
275
276 ## STDOUT:
277 ## END
278
279
280 #### _hay() register
281 shopt --set parse_paren parse_brace parse_equals parse_proc
282
283 hay define user
284
285 var result = {}
286
287 hay eval :result {
288
289 user alice
290 # = _hay()
291 write -- $[len(_hay()['children'])]
292
293 user bob
294 setvar result = _hay()
295 write -- $[len(_hay()['children'])]
296
297 }
298
299 # TODO: Should be cleared here
300 setvar result = _hay()
301 write -- $[len(_hay()['children'])]
302
303 ## STDOUT:
304 1
305 2
306 0
307 ## END
308
309
310 #### haynode builtin can define nodes
311 shopt --set parse_paren parse_brace parse_equals parse_proc
312
313 # It prints JSON by default? What about the code blocks?
314 # Or should there be a --json flag?
315
316 hay eval :result {
317
318 # note that 'const' is required because haynode isn't capitalized
319 haynode parent alice {
320 const age = '50'
321
322 haynode child bob {
323 const age = '10'
324 }
325
326 haynode child carol {
327 const age = '20'
328 }
329
330 const other = 'str'
331 }
332 }
333
334 #= result
335 write -- 'level 0 children' $[len(result['children'])]
336 write -- 'level 1 children' $[len(result['children'][0]['children'])]
337
338 hay eval :result {
339 haynode parent foo
340 haynode parent bar
341 }
342 write -- 'level 0 children' $[len(result['children'])]
343
344
345 ## STDOUT:
346 level 0 children
347 1
348 level 1 children
349 2
350 level 0 children
351 2
352 ## END
353
354
355 #### haynode: usage errors (name or block required)
356 shopt --set parse_brace parse_equals parse_proc
357
358 # should we make it name or block required?
359 # license { ... } might be useful?
360
361 try {
362 hay eval :result {
363 haynode package
364 }
365 }
366 echo "haynode attr $_status"
367 var result = _hay()
368 echo "LEN $[len(result['children'])]"
369
370 # requires block arg
371 try {
372 hay eval :result {
373 haynode TASK build
374 }
375 }
376 echo "haynode code $_status"
377 echo "LEN $[len(result['children'])]"
378
379 echo ---
380 hay define package TASK
381
382 try {
383 hay eval :result {
384 package
385 }
386 }
387 echo "define attr $_status"
388 echo "LEN $[len(result['children'])]"
389
390 try {
391 hay eval :result {
392 TASK build
393 }
394 }
395 echo "define code $_status"
396 echo "LEN $[len(result['children'])]"
397
398 ## STDOUT:
399 haynode attr 2
400 LEN 0
401 haynode code 2
402 LEN 0
403 ---
404 define attr 2
405 LEN 0
406 define code 2
407 LEN 0
408 ## END
409
410 #### haynode: shell nodes require block args; attribute nodes don't
411
412 shopt --set parse_brace parse_equals parse_proc
413
414 hay define package TASK
415
416 try {
417 hay eval :result {
418 package glibc > /dev/null
419 }
420 }
421 echo "status $_status"
422
423
424 try {
425 hay eval :result {
426 TASK build
427 }
428 }
429 echo "status $_status"
430
431 ## STDOUT:
432 status 0
433 status 2
434 ## END
435
436
437 #### hay eval with shopt -s oil:all
438 shopt --set parse_brace parse_equals parse_proc
439
440 hay define Package
441
442 const x = 'foo bar'
443
444 hay eval :result {
445 Package foo {
446 # set -e should be active!
447 #false
448
449 version = '1.0'
450
451 # simple_word_eval should be active!
452 write -- $x
453 }
454 }
455
456 ## STDOUT:
457 foo bar
458 ## END
459
460
461 #### Scope of Variables Inside Hay Blocks
462
463 shopt --set oil:all
464
465 hay define package
466 hay define deps/package
467
468 hay eval :result {
469
470 const URL_PATH = 'downloads/foo.tar.gz'
471
472 package foo {
473 echo "location = https://example.com/$URL_PATH"
474 echo "backup = https://archive.example.com/$URL_PATH"
475 }
476
477 # Note: PushTemp() happens here
478 deps spam {
479 # OVERRIDE
480 const URL_PATH = 'downloads/spam.tar.gz'
481
482 const URL2 = 'downloads/spam.tar.xz'
483
484 package foo {
485 # this is a global
486 echo "deps location https://example.com/$URL_PATH"
487 echo "deps backup https://archive.example.com/$URL2"
488 }
489 }
490
491 echo "AFTER $URL_PATH"
492
493 }
494
495 ## STDOUT:
496 location = https://example.com/downloads/foo.tar.gz
497 backup = https://archive.example.com/downloads/foo.tar.gz
498 deps location https://example.com/downloads/spam.tar.gz
499 deps backup https://archive.example.com/downloads/spam.tar.xz
500 AFTER downloads/foo.tar.gz
501 ## END
502
503
504 #### hay define and then an error
505 shopt --set parse_brace parse_equals parse_proc
506
507 hay define Package/License User TASK
508
509 hay pp defs > /dev/null
510
511 hay eval :result {
512 User bob
513 echo "user $?"
514
515 Package cppunit
516 echo "package $?"
517
518 TASK build {
519 configure
520 }
521 echo "TASK $?"
522
523 Package unzip {
524 version = '1.0'
525
526 License FOO {
527 echo 'inside'
528 }
529 echo "license $?"
530
531 License BAR
532 echo "license $?"
533
534 zz foo
535 echo 'should not get here'
536 }
537 }
538
539 echo 'ditto'
540
541 ## status: 127
542 ## STDOUT:
543 user 0
544 package 0
545 TASK 0
546 inside
547 license 0
548 license 0
549 ## END
550
551 #### parse_hay()
552 shopt --set parse_proc
553
554 const config_path = "$REPO_ROOT/spec/testdata/config/ci.oil"
555 const block = parse_hay(config_path)
556
557 # Are blocks opaque?
558 {
559 = block
560 } | wc -l | read n
561
562 # Just make sure we got more than one line?
563 if test "$n" -gt 1; then
564 echo "OK"
565 fi
566
567 ## STDOUT:
568 OK
569 ## END
570
571
572 #### Code Blocks: parse_hay() then shvar _DIALECT= { eval_hay() }
573 shopt --set parse_brace parse_proc
574
575 hay define TASK
576
577 const config_path = "$REPO_ROOT/spec/testdata/config/ci.oil"
578 const block = parse_hay(config_path)
579
580 shvar _DIALECT=sourcehut {
581 const d = eval_hay(block)
582 }
583
584 const children = d['children']
585 write 'level 0 children' $[len(children)] ---
586
587 # TODO: Do we need @[] for array expression sub?
588 write 'child 0' $[children[0].type] $[join(children[0].args)] ---
589 write 'child 1' $[children[1].type] $[join(children[1].args)] ---
590
591 ## STDOUT:
592 level 0 children
593 2
594 ---
595 child 0
596 TASK
597 cpp
598 ---
599 child 1
600 TASK
601 publish-html
602 ---
603 ## END
604
605
606 #### Attribute / Data Blocks (package-manager)
607 shopt --set parse_proc
608
609 const path = "$REPO_ROOT/spec/testdata/config/package-manager.oil"
610
611 const block = parse_hay(path)
612
613 hay define Package
614 const d = eval_hay(block)
615 write 'level 0 children' $[len(d['children'])]
616 write 'level 1 children' $[len(d['children'][1]['children'])]
617
618 ## STDOUT:
619 level 0 children
620 3
621 level 1 children
622 0
623 ## END
624
625
626 #### Typed Args to Hay Node
627
628 shopt --set oil:all
629
630 hay define when
631
632 # Hm I get 'too many typed args'
633 # Ah this is because of 'haynode'
634 # 'haynode' could silently pass through blocks and typed args?
635
636 when NAME (x > 0) {
637 const version = '1.0'
638 const other = 'str'
639 }
640
641 = _hay()
642
643 ## STDOUT:
644 ## END
645
646
647 #### OSH and hay (dynamic parsing)
648
649 source $REPO_ROOT/spec/testdata/config/osh-hay.osh
650
651
652 ## STDOUT:
653 backticks
654 eval
655 TYPE TASK
656 CODE
657 echo `echo task backticks`
658 eval 'echo task eval'
659 ___
660 ## END
661