1 # YSH specific features of eval
2
3 ## our_shell: ysh
4 ## oils_failures_allowed: 8
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 --line {
112 var cols = _reply => split()
113 eval (block, pos_args=cols)
114 }
115 }
116
117 printf 'a b\nc d' | lines { echo $1 }
118
119 ## STDOUT:
120 a
121 c
122 ## END
123
124 #### eval with custom arg0
125 eval (^(write $0)) (arg0="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 abc
140 123
141 ## END
142
143 #### dynamic binding names and mutation
144 proc foreach (binding, in_; list ;; block) {
145 if (in_ !== "in") {
146 error 'Must use the "syntax" `foreach <binding> in (<expr>) { ... }`'
147 }
148
149 for _ in (list) {
150 eval (block, vars={ binding: _ })
151 }
152 }
153
154 var mydicts = [{'a': 1}, {'b': 2}, {'c': 3}]
155 foreach mydict in (mydicts) {
156 pp test_ (mydict)
157 setvar mydict.d = 0
158 }
159
160 pp test_ (mydicts)
161
162 ## STDOUT:
163 (Dict) {"a":1}
164 (Dict) {"b":2}
165 (Dict) {"c":3}
166 (List) [{"a":1,"d":0},{"b":2,"d":0},{"c":3,"d":0}]
167 ## END
168
169 #### binding procs in the eval-ed namespace
170 proc __flag (short, long) {
171 echo "flag $short $long"
172 }
173
174 proc __arg (name) {
175 echo "arg $name"
176 }
177
178 proc parser (; spec ;; block) {
179 eval (block, vars={ 'flag': __flag, 'arg': __arg })
180 }
181
182 parser (&spec) {
183 flag -h --help
184 arg file
185 }
186
187 # but flag/arg are unavailable outside of `parser`
188 # _error.code = 127 is set on "command not found" errors
189
190 try { flag }
191 if (_error.code !== 127) { error 'expected failure' }
192
193 try { arg }
194 if (_error.code !== 127) { error 'expected failure' }
195
196 ## STDOUT:
197 flag -h --help
198 arg file
199 ## END
200
201 #### vars initializes the variable frame, but does not remember it
202 var vars = { 'foo': 123 }
203 eval (^(var bar = 321), vars=vars)
204 pp test_ (vars)
205
206 ## STDOUT:
207 (Dict) {"foo":123}
208 ## END
209
210 #### eval 'mystring' vs. eval (myblock)
211
212 eval 'echo plain'
213 echo plain=$?
214 var b = ^(echo plain)
215 eval (b)
216 echo plain=$?
217
218 echo
219
220 # This calls main_loop.Batch(), which catches
221 # - error.Parse
222 # - error.ErrExit
223 # - error.FatalRuntime - glob errors, etc.?
224
225 try {
226 eval 'echo one; false; echo two'
227 }
228 pp test_ (_error)
229
230 # This calls CommandEvaluator.EvalCommand(), as blocks do
231
232 var b = ^(echo one; false; echo two)
233 try {
234 eval (b)
235 }
236 pp test_ (_error)
237
238 ## STDOUT:
239 plain
240 plain=0
241 plain
242 plain=0
243
244 one
245 (Dict) {"code":1}
246 one
247 (Dict) {"code":1}
248 ## END