1 # YSH specific features of eval
2
3 ## our_shell: ysh
4 ## oils_failures_allowed: 6
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 "$@"] (argv=:| foo bar baz |)
103 eval ^[pp line (:| $1 $2 $3 |)] (argv=:| foo bar baz |)
104
105 ## status: 0
106 ## STDOUT:
107 foo bar baz
108 (List) ["foo","bar","baz"]
109 ## END
110
111 #### eval with vars bindings
112 var myVar = "abc"
113 eval (^(pp line (myVar)))
114 eval (^(pp line (myVar)), vars={ 'myVar': '123' })
115
116 # eval doesn't modify it's environment
117 eval (^(pp line (myVar)))
118
119 ## status: 0
120 ## STDOUT:
121 abc
122 123
123 ## END
124
125 #### dynamic binding names and mutation
126 proc foreach (binding, in_; list ;; block) {
127 if (in_ !== "in") {
128 error 'Must use the "syntax" `foreach <binding> in (<expr>) { ... }`'
129 }
130
131 for _ in (list) {
132 eval (block, vars={ binding: _ })
133 }
134 }
135
136 var mydicts = [{'a': 1}, {'b': 2}, {'c': 3}]
137 foreach mydict in (mydicts) {
138 pp line (mydict)
139 setvar mydict.d = 0
140 }
141
142 pp line (mydicts)
143
144 ## status: 0
145 ## STDOUT:
146 (Dict) {"a":1}
147 (Dict) {"b":2}
148 (Dict) {"c":3}
149 (List) [{"a":1,"d":0},{"b":2,"d":0},{"c":3,"d":0}]
150 ## END
151
152 #### binding procs in the eval-ed namespace
153 proc __flag (short, long) {
154 echo "flag $short $long"
155 }
156
157 proc __arg (name) {
158 echo "arg $name"
159 }
160
161 proc parser (; spec ;; block) {
162 eval (block, vars={ 'flag': __flag, 'arg': __arg })
163 }
164
165 parser (&spec) {
166 flag -h --help
167 arg file
168 }
169
170 # but flag/arg are unavailable outside of `parser`
171 # _error.code = 127 is set on "command not found" errors
172
173 try { flag }
174 if (_error.code !== 127) { error 'expected failure' }
175
176 try { arg }
177 if (_error.code !== 127) { error 'expected failure' }
178
179 ## status: 0
180 ## STDOUT:
181 flag -h --help
182 arg file
183 ## END
184
185 #### vars initializes the variable frame, but does not remember it
186 var vars = { 'foo': 123 }
187 eval (^(var bar = 321), vars=vars)
188 pp line (vars)
189
190 ## status: 0
191 ## STDOUT:
192 (Dict) {"foo":123}
193 ## END