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
8 var b = ^(echo obj)
9 eval (b)
10
11 eval (^(echo command literal))
12
13 # Doesn't work because it's a positional arg
14 eval { echo block }
15
16 ## status: 3
17 ## STDOUT:
18 obj
19 command literal
20 ## END
21
22
23 #### Eval a block within a proc
24 proc run (;;; block) {
25 eval (block)
26 }
27
28 run {
29 echo 'In a block!'
30 }
31 ## STDOUT:
32 In a block!
33 ## END
34
35 #### Eval block created by calling a proc
36 proc lazy-block ( ; out; ; block) {
37 call out->setValue(block)
38 }
39
40 var myglobal = 0
41
42 lazy-block (&my_block) {
43 json write (myglobal)
44 }
45
46 eval (my_block)
47 setvar myglobal = 1
48 eval (my_block)
49 ## STDOUT:
50 0
51 1
52 ## END
53
54 #### eval (block) can read variables like eval ''
55
56 proc p2(code_str) {
57 var mylocal = 42
58 eval $code_str
59 }
60
61 p2 'echo mylocal=$mylocal'
62
63 proc p (;;; block) {
64 var mylocal = 99
65 eval (block)
66 }
67
68 p {
69 echo mylocal=$mylocal
70 }
71
72
73 ## STDOUT:
74 mylocal=42
75 mylocal=99
76 ## END
77
78 #### eval should have a sandboxed mode
79
80 proc 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
92 p {
93 echo $this
94 }
95
96 ## status: 1
97 ## STDOUT:
98 TODO
99 ## END
100
101 #### eval with argv bindings
102 eval (^(echo "$@"), pos_args=:| foo bar baz |)
103 eval (^(pp test_ (:| $1 $2 $3 |)), pos_args=:| foo bar baz |)
104 ## STDOUT:
105 foo bar baz
106 (List) ["foo","bar","baz"]
107 ## END
108
109 #### eval lines with argv bindings
110 proc lines (;;; block) {
111 while read --raw-line {
112 var cols = _reply => split()
113 eval (block, pos_args=cols)
114 }
115 }
116
117 printf 'a b\nc d\n' | lines { echo $1 }
118
119 ## STDOUT:
120 a
121 c
122 ## END
123
124 #### eval with custom dollar0
125 eval (^(write $0), dollar0="my arg0")
126 ## STDOUT:
127 my arg0
128 ## END
129
130 #### eval with vars bindings
131 var myVar = "abc"
132 eval (^(pp test_ (myVar)))
133 eval (^(pp test_ (myVar)), vars={ 'myVar': '123' })
134
135 # eval doesn't modify it's environment
136 eval (^(pp test_ (myVar)))
137
138 ## STDOUT:
139 (Str) "abc"
140 (Str) "123"
141 (Str) "abc"
142 ## END
143
144 #### dynamic binding names and mutation
145 proc 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
155 var mydicts = [{'a': 1}, {'b': 2}, {'c': 3}]
156 foreach mydict in (mydicts) {
157 pp test_ (mydict)
158 setvar mydict.d = 0
159 }
160
161 pp 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
171 proc __flag (short, long) {
172 echo "flag $short $long"
173 }
174
175 proc __arg (name) {
176 echo "arg $name"
177 }
178
179 proc parser (; spec ;; block) {
180 eval (block, vars={ 'flag': __flag, 'arg': __arg })
181 }
182
183 parser (&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
191 try { flag }
192 if (_error.code !== 127) { error 'expected failure' }
193
194 try { arg }
195 if (_error.code !== 127) { error 'expected failure' }
196
197 ## STDOUT:
198 flag -h --help
199 arg file
200 ## END
201
202 #### vars initializes the variable frame, but does not remember it
203 var vars = { 'foo': 123 }
204 eval (^(var bar = 321;), vars=vars)
205 pp test_ (vars)
206
207 ## STDOUT:
208 (Dict) {"foo":123}
209 ## END
210
211 #### eval pos_args must be strings
212 eval (^(true), pos_args=[1, 2, 3])
213 ## status: 3
214
215 #### eval 'mystring' vs. eval (myblock)
216
217 eval 'echo plain'
218 echo plain=$?
219 var b = ^(echo plain)
220 eval (b)
221 echo plain=$?
222
223 echo
224
225 # This calls main_loop.Batch(), which catches
226 # - error.Parse
227 # - error.ErrExit
228 # - error.FatalRuntime - glob errors, etc.?
229
230 try {
231 eval 'echo one; false; echo two'
232 }
233 pp test_ (_error)
234
235 # This calls CommandEvaluator.EvalCommand(), as blocks do
236
237 var b = ^(echo one; false; echo two)
238 try {
239 eval (b)
240 }
241 pp test_ (_error)
242
243 ## STDOUT:
244 plain
245 plain=0
246 plain
247 plain=0
248
249 one
250 (Dict) {"code":1}
251 one
252 (Dict) {"code":1}
253 ## END