OILS / spec / ysh-builtin-eval.test.sh View on Github | oilshell.org

253 lines, 136 significant
1# YSH specific features of eval
2
3## our_shell: ysh
4## oils_failures_allowed: 1
5
6#### Eval does not take a literal block - can restore this later
7
8var b = ^(echo obj)
9eval (b)
10
11eval (^(echo command literal))
12
13# Doesn't work because it's a positional arg
14eval { echo block }
15
16## status: 3
17## STDOUT:
18obj
19command literal
20## END
21
22
23#### Eval a block within a proc
24proc run (;;; block) {
25 eval (block)
26}
27
28run {
29 echo 'In a block!'
30}
31## STDOUT:
32In a block!
33## END
34
35#### Eval block created by calling a proc
36proc lazy-block ( ; out; ; block) {
37 call out->setValue(block)
38}
39
40var myglobal = 0
41
42lazy-block (&my_block) {
43 json write (myglobal)
44}
45
46eval (my_block)
47setvar myglobal = 1
48eval (my_block)
49## STDOUT:
500
511
52## END
53
54#### eval (block) can read variables like eval ''
55
56proc p2(code_str) {
57 var mylocal = 42
58 eval $code_str
59}
60
61p2 'echo mylocal=$mylocal'
62
63proc p (;;; block) {
64 var mylocal = 99
65 eval (block)
66}
67
68p {
69 echo mylocal=$mylocal
70}
71
72
73## STDOUT:
74mylocal=42
75mylocal=99
76## END
77
78#### eval should have a sandboxed mode
79
80proc p (;;; block) {
81 var this = 42
82
83 # like push-registers? Not sure
84 # We could use state.ctx_Temp ? There's also ctx_FuncCall etc.
85 #
86 # I think we want to provide full control over the stack.
87 push-frame {
88 eval (block)
89 }
90}
91
92p {
93 echo $this
94}
95
96## status: 1
97## STDOUT:
98TODO
99## END
100
101#### eval with argv bindings
102eval (^(echo "$@"), pos_args=:| foo bar baz |)
103eval (^(pp test_ (:| $1 $2 $3 |)), pos_args=:| foo bar baz |)
104## STDOUT:
105foo bar baz
106(List) ["foo","bar","baz"]
107## END
108
109#### eval lines with argv bindings
110proc lines (;;; block) {
111 while read --raw-line {
112 var cols = _reply => split()
113 eval (block, pos_args=cols)
114 }
115}
116
117printf 'a b\nc d\n' | lines { echo $1 }
118
119## STDOUT:
120a
121c
122## END
123
124#### eval with custom dollar0
125eval (^(write $0), dollar0="my arg0")
126## STDOUT:
127my arg0
128## END
129
130#### eval with vars bindings
131var myVar = "abc"
132eval (^(pp test_ (myVar)))
133eval (^(pp test_ (myVar)), vars={ 'myVar': '123' })
134
135# eval doesn't modify it's environment
136eval (^(pp test_ (myVar)))
137
138## STDOUT:
139(Str) "abc"
140(Str) "123"
141(Str) "abc"
142## END
143
144#### dynamic binding names and mutation
145proc foreach (binding, in_; list ;; block) {
146 if (in_ !== "in") {
147 error 'Must use the "syntax" `foreach <binding> in (<expr>) { ... }`'
148 }
149
150 for item in (list) {
151 eval (block, vars={ [binding]: item })
152 }
153}
154
155var mydicts = [{'a': 1}, {'b': 2}, {'c': 3}]
156foreach mydict in (mydicts) {
157 pp test_ (mydict)
158 setvar mydict.d = 0
159}
160
161pp test_ (mydicts)
162
163## STDOUT:
164(Dict) {"a":1}
165(Dict) {"b":2}
166(Dict) {"c":3}
167(List) [{"a":1,"d":0},{"b":2,"d":0},{"c":3,"d":0}]
168## END
169
170#### binding procs in the eval-ed namespace
171proc __flag (short, long) {
172 echo "flag $short $long"
173}
174
175proc __arg (name) {
176 echo "arg $name"
177}
178
179proc parser (; spec ;; block) {
180 eval (block, vars={ 'flag': __flag, 'arg': __arg })
181}
182
183parser (&spec) {
184 flag -h --help
185 arg file
186}
187
188# but flag/arg are unavailable outside of `parser`
189# _error.code = 127 is set on "command not found" errors
190
191try { flag }
192if (_error.code !== 127) { error 'expected failure' }
193
194try { arg }
195if (_error.code !== 127) { error 'expected failure' }
196
197## STDOUT:
198flag -h --help
199arg file
200## END
201
202#### vars initializes the variable frame, but does not remember it
203var vars = { 'foo': 123 }
204eval (^(var bar = 321;), vars=vars)
205pp test_ (vars)
206
207## STDOUT:
208(Dict) {"foo":123}
209## END
210
211#### eval pos_args must be strings
212eval (^(true), pos_args=[1, 2, 3])
213## status: 3
214
215#### eval 'mystring' vs. eval (myblock)
216
217eval 'echo plain'
218echo plain=$?
219var b = ^(echo plain)
220eval (b)
221echo plain=$?
222
223echo
224
225# This calls main_loop.Batch(), which catches
226# - error.Parse
227# - error.ErrExit
228# - error.FatalRuntime - glob errors, etc.?
229
230try {
231 eval 'echo one; false; echo two'
232}
233pp test_ (_error)
234
235# This calls CommandEvaluator.EvalCommand(), as blocks do
236
237var b = ^(echo one; false; echo two)
238try {
239 eval (b)
240}
241pp test_ (_error)
242
243## STDOUT:
244plain
245plain=0
246plain
247plain=0
248
249one
250(Dict) {"code":1}
251one
252(Dict) {"code":1}
253## END