1 #!/usr/bin/env python2
2 """
3 func_misc.py
4 """
5 from __future__ import print_function
6
7 from _devbuild.gen.runtime_asdl import value, value_str, value_t, value_e, scope_e
8 from _devbuild.gen.syntax_asdl import loc
9 from core import error
10 from core import ui
11 from core import vm
12 from frontend import match
13 from frontend import typed_args
14 from mycpp.mylib import NewDict, iteritems, log, tagswitch
15 from ysh import expr_eval, val_ops
16
17 from typing import TYPE_CHECKING, Dict, List, cast
18 if TYPE_CHECKING:
19 from core import state
20 from osh import glob_
21 from osh import split
22
23 _ = log
24
25
26 class Append(vm._Callable):
27
28 def __init__(self):
29 # type: () -> None
30 pass
31
32 def Call(self, args):
33 # type: (typed_args.Reader) -> value_t
34
35 items = args.PosList()
36 to_append = args.PosValue()
37 args.Done()
38
39 items.append(to_append)
40
41 # Equivalent to no return value?
42 return value.Null
43
44
45 class Extend(vm._Callable):
46
47 def __init__(self):
48 # type: () -> None
49 pass
50
51 def Call(self, args):
52 # type: (typed_args.Reader) -> value_t
53
54 a = args.PosList()
55 b = args.PosList()
56 args.Done()
57
58 a.extend(b)
59 return value.Null
60
61
62 class Pop(vm._Callable):
63
64 def __init__(self):
65 # type: () -> None
66 pass
67
68 def Call(self, args):
69 # type: (typed_args.Reader) -> value_t
70
71 items = args.PosList()
72 args.Done()
73
74 return items.pop()
75
76
77 class StartsWith(vm._Callable):
78
79 def __init__(self):
80 # type: () -> None
81 pass
82
83 def Call(self, args):
84 # type: (typed_args.Reader) -> value_t
85
86 string = args.PosStr()
87 match = args.PosStr()
88 args.Done()
89
90 res = string.startswith(match)
91 return value.Bool(res)
92
93
94 class Strip(vm._Callable):
95
96 def __init__(self):
97 # type: () -> None
98 pass
99
100 def Call(self, args):
101 # type: (typed_args.Reader) -> value_t
102
103 string = args.PosStr()
104 args.Done()
105
106 res = string.strip()
107 return value.Str(res)
108
109
110 class Upper(vm._Callable):
111
112 def __init__(self):
113 # type: () -> None
114 pass
115
116 def Call(self, args):
117 # type: (typed_args.Reader) -> value_t
118
119 string = args.PosStr()
120 args.Done()
121
122 res = string.upper()
123 return value.Str(res)
124
125
126 class Keys(vm._Callable):
127
128 def __init__(self):
129 # type: () -> None
130 pass
131
132 def Call(self, args):
133 # type: (typed_args.Reader) -> value_t
134
135 dictionary = args.PosDict()
136 args.Done()
137
138 keys = [value.Str(k) for k in dictionary.keys()] # type: List[value_t]
139 return value.List(keys)
140
141
142 class Len(vm._Callable):
143
144 def __init__(self):
145 # type: () -> None
146 pass
147
148 def Call(self, args):
149 # type: (typed_args.Reader) -> value_t
150
151 x = args.PosValue()
152 args.Done()
153
154 UP_x = x
155 with tagswitch(x) as case:
156 if case(value_e.List):
157 x = cast(value.List, UP_x)
158 return value.Int(len(x.items))
159
160 elif case(value_e.Dict):
161 x = cast(value.Dict, UP_x)
162 return value.Int(len(x.d))
163
164 elif case(value_e.Str):
165 x = cast(value.Str, UP_x)
166 return value.Int(len(x.s))
167
168 raise error.TypeErr(x, 'len() expected Str, List, or Dict',
169 loc.Missing)
170
171
172 class Reverse(vm._Callable):
173
174 def __init__(self):
175 # type: () -> None
176 pass
177
178 def Call(self, args):
179 # type: (typed_args.Reader) -> value_t
180
181 li = args.PosList()
182 args.Done()
183
184 li.reverse()
185
186 return value.Null
187
188
189 class Join(vm._Callable):
190
191 def __init__(self):
192 # type: () -> None
193 pass
194
195 def Call(self, args):
196 # type: (typed_args.Reader) -> value_t
197
198 li = args.PosList()
199
200 # TODO: see if we can incorporate positional defaults into typed_args.Reader
201 delim = ''
202 if args.NumPos():
203 delim = args.PosStr()
204
205 args.Done()
206
207 strs = [] # type: List[str]
208 for i, el in enumerate(li):
209 strs.append(val_ops.Stringify(el, loc.Missing))
210
211 return value.Str(delim.join(strs))
212
213
214 class Maybe(vm._Callable):
215
216 def __init__(self):
217 # type: () -> None
218 pass
219
220 def Call(self, args):
221 # type: (typed_args.Reader) -> value_t
222
223 val = args.PosValue()
224 args.Done()
225
226 if val == value.Null:
227 return value.List([])
228
229 s = val_ops.ToStr(
230 val, 'maybe() expected Str, but got %s' % value_str(val.tag()),
231 loc.Missing)
232 if len(s):
233 return value.List([val]) # use val to avoid needlessly copy
234
235 return value.List([])
236
237
238 class Type(vm._Callable):
239
240 def __init__(self):
241 # type: () -> None
242 pass
243
244 def Call(self, args):
245 # type: (typed_args.Reader) -> value_t
246
247 val = args.PosValue()
248 args.Done()
249
250 tname = ui.ValType(val)
251 return value.Str(tname[6:]) # strip "value." prefix
252
253
254 class Bool(vm._Callable):
255
256 def __init__(self):
257 # type: () -> None
258 pass
259
260 def Call(self, args):
261 # type: (typed_args.Reader) -> value_t
262
263 val = args.PosValue()
264 args.Done()
265
266 return value.Bool(val_ops.ToBool(val))
267
268
269 class Int(vm._Callable):
270
271 def __init__(self):
272 # type: () -> None
273 pass
274
275 def Call(self, args):
276 # type: (typed_args.Reader) -> value_t
277
278 val = args.PosValue()
279 args.Done()
280
281 UP_val = val
282 with tagswitch(val) as case:
283 if case(value_e.Int):
284 return val
285
286 elif case(value_e.Bool):
287 val = cast(value.Bool, UP_val)
288 return value.Int(int(val.b))
289
290 elif case(value_e.Float):
291 val = cast(value.Float, UP_val)
292 return value.Int(int(val.f))
293
294 elif case(value_e.Str):
295 val = cast(value.Str, UP_val)
296 if not match.LooksLikeInteger(val.s):
297 raise error.Expr('Cannot convert %s to Int' % val.s,
298 loc.Missing)
299
300 return value.Int(int(val.s))
301
302 raise error.TypeErr(val, 'Int() expected Bool, Int, Float, or Str',
303 loc.Missing)
304
305
306 class Float(vm._Callable):
307
308 def __init__(self):
309 # type: () -> None
310 pass
311
312 def Call(self, args):
313 # type: (typed_args.Reader) -> value_t
314
315 val = args.PosValue()
316 args.Done()
317
318 UP_val = val
319 with tagswitch(val) as case:
320 if case(value_e.Int):
321 val = cast(value.Int, UP_val)
322 return value.Float(float(val.i))
323
324 elif case(value_e.Float):
325 return val
326
327 elif case(value_e.Str):
328 val = cast(value.Str, UP_val)
329 if not match.LooksLikeFloat(val.s):
330 raise error.Expr('Cannot convert %s to Float' % val.s,
331 loc.Missing)
332
333 return value.Float(float(val.s))
334
335 raise error.TypeErr(val, 'Float() expected Int, Float, or Str',
336 loc.Missing)
337
338
339 class Str_(vm._Callable):
340
341 def __init__(self):
342 # type: () -> None
343 pass
344
345 def Call(self, args):
346 # type: (typed_args.Reader) -> value_t
347
348 val = args.PosValue()
349 args.Done()
350
351 # TODO: Should we call Stringify here? That would handle Eggex.
352
353 UP_val = val
354 with tagswitch(val) as case:
355 if case(value_e.Int):
356 val = cast(value.Int, UP_val)
357 return value.Str(str(val.i))
358
359 elif case(value_e.Float):
360 val = cast(value.Float, UP_val)
361 return value.Str(str(val.f))
362
363 elif case(value_e.Str):
364 return val
365
366 raise error.TypeErr(val, 'Str() expected Str, Int, or Float',
367 loc.Missing)
368
369
370 class List_(vm._Callable):
371
372 def __init__(self):
373 # type: () -> None
374 pass
375
376 def Call(self, args):
377 # type: (typed_args.Reader) -> value_t
378
379 val = args.PosValue()
380 args.Done()
381
382 l = [] # type: List[value_t]
383 it = None # type: val_ops._ContainerIter
384 UP_val = val
385 with tagswitch(val) as case:
386 if case(value_e.List):
387 val = cast(value.List, UP_val)
388 it = val_ops.ListIterator(val)
389
390 elif case(value_e.Dict):
391 val = cast(value.Dict, UP_val)
392 it = val_ops.DictIterator(val)
393
394 elif case(value_e.Range):
395 val = cast(value.Range, UP_val)
396 it = val_ops.RangeIterator(val)
397
398 else:
399 raise error.TypeErr(val,
400 'List() expected Dict, List, or Range',
401 loc.Missing)
402
403 assert it is not None
404 while not it.Done():
405 l.append(it.FirstValue())
406 it.Next()
407
408 return value.List(l)
409
410
411 class Dict_(vm._Callable):
412
413 def __init__(self):
414 # type: () -> None
415 pass
416
417 def Call(self, args):
418 # type: (typed_args.Reader) -> value_t
419
420 val = args.PosValue()
421 args.Done()
422
423 UP_val = val
424 with tagswitch(val) as case:
425 if case(value_e.Dict):
426 d = NewDict() # type: Dict[str, value_t]
427 val = cast(value.Dict, UP_val)
428 for k, v in iteritems(val.d):
429 d[k] = v
430
431 return value.Dict(d)
432
433 raise error.TypeErr(val, 'Dict() expected List or Dict', loc.Missing)
434
435
436 class Split(vm._Callable):
437
438 def __init__(self, splitter):
439 # type: (split.SplitContext) -> None
440 vm._Callable.__init__(self)
441 self.splitter = splitter
442
443 def Call(self, args):
444 # type: (typed_args.Reader) -> value_t
445 s = args.PosStr()
446
447 ifs = None # type: str
448 if args.NumPos():
449 ifs = args.PosStr()
450
451 args.Done()
452
453 l = [
454 value.Str(elem)
455 for elem in self.splitter.SplitForWordEval(s, ifs=ifs)
456 ] # type: List[value_t]
457 return value.List(l)
458
459
460 class Glob(vm._Callable):
461
462 def __init__(self, globber):
463 # type: (glob_.Globber) -> None
464 vm._Callable.__init__(self)
465 self.globber = globber
466
467 def Call(self, args):
468 # type: (typed_args.Reader) -> value_t
469 s = args.PosStr()
470 args.Done()
471
472 out = [] # type: List[str]
473 self.globber._Glob(s, out)
474
475 l = [value.Str(elem) for elem in out] # type: List[value_t]
476 return value.List(l)
477
478
479 class Shvar_get(vm._Callable):
480 """Look up with dynamic scope."""
481
482 def __init__(self, mem):
483 # type: (state.Mem) -> None
484 vm._Callable.__init__(self)
485 self.mem = mem
486
487 def Call(self, args):
488 # type: (typed_args.Reader) -> value_t
489 name = args.PosStr()
490 args.Done()
491 return expr_eval.LookupVar(self.mem, name, scope_e.Dynamic,
492 loc.Missing)
493
494
495 class Assert(vm._Callable):
496
497 def __init__(self):
498 # type: () -> None
499 pass
500
501 def Call(self, args):
502 # type: (typed_args.Reader) -> value_t
503
504 val = args.PosValue()
505
506 msg = ''
507 if args.NumPos():
508 msg = args.PosStr()
509
510 args.Done()
511
512 if not val_ops.ToBool(val):
513 raise error.AssertionErr(msg, loc.Missing)
514
515 return value.Null