OILS / spec / hay.test.sh View on Github | oilshell.org

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