OILS / builtin / method_dict.py View on Github | oils.pub

180 lines, 108 significant
1"""Methods on YSH Dict"""
2
3from __future__ import print_function
4
5from _devbuild.gen.value_asdl import (value, value_e, value_t, Obj)
6from _devbuild.gen.runtime_asdl import coerced_e
7
8from core import error
9from core import vm
10from frontend import typed_args
11from mycpp import mylib, mops
12from mycpp.mylib import log, tagswitch
13from ysh import expr_eval
14
15from typing import cast, List
16
17_ = log
18
19
20class Keys(vm._Callable):
21
22 def __init__(self):
23 # type: () -> None
24 pass
25
26 def Call(self, rd):
27 # type: (typed_args.Reader) -> value_t
28
29 dictionary = rd.PosDict()
30 rd.Done()
31
32 keys = [value.Str(k) for k in dictionary.keys()] # type: List[value_t]
33 return value.List(keys)
34
35
36class Values(vm._Callable):
37
38 def __init__(self):
39 # type: () -> None
40 pass
41
42 def Call(self, rd):
43 # type: (typed_args.Reader) -> value_t
44
45 dictionary = rd.PosDict()
46 rd.Done()
47
48 values = dictionary.values() # type: List[value_t]
49 return value.List(values)
50
51
52class Erase(vm._Callable):
53
54 def __init__(self):
55 # type: () -> None
56 pass
57
58 def Call(self, rd):
59 # type: (typed_args.Reader) -> value_t
60
61 dictionary = rd.PosDict()
62 key = rd.PosStr()
63 rd.Done()
64
65 mylib.dict_erase(dictionary, key)
66 return value.Null
67
68
69class Clear(vm._Callable):
70
71 def __init__(self):
72 # type: () -> None
73 pass
74
75 def Call(self, rd):
76 # type: (typed_args.Reader) -> value_t
77
78 dictionary = rd.PosDict()
79 rd.Done()
80
81 dictionary.clear()
82 return value.Null
83
84
85class Add(vm._Callable):
86
87 def __init__(self):
88 # type: () -> None
89 pass
90
91 def Call(self, rd):
92 # type: (typed_args.Reader) -> value_t
93
94 dictionary = rd.PosDict()
95 key = rd.PosStr()
96 inc_val = rd.OptionalValue()
97 rd.Done()
98
99 # If inc_val is provided, we treat it as the definitive type of the
100 # value to be incremented, if it isn't, we rely on the existing
101 # value in the dictionary (if that doesn't exist, the default is 0)
102 if inc_val is None:
103 right = value.Int(mops.ONE) # type: value_t
104 else:
105 right = inc_val
106
107 if key in dictionary:
108 left = dictionary[key]
109 else:
110 left = value.Int(mops.ZERO)
111
112 c, i1, i2, f1, f2 = expr_eval.ConvertForBinaryOp(left, right)
113
114 if c == coerced_e.Int:
115 res = value.Int(mops.Add(i1, i2)) # type: value_t
116 elif c == coerced_e.Float:
117 res = value.Float(f1 + f2)
118
119 dictionary[key] = res
120
121 return value.Null
122
123
124class Append(vm._Callable):
125
126 def __init__(self):
127 # type: () -> None
128 pass
129
130 def Call(self, rd):
131 # type: (typed_args.Reader) -> value_t
132
133 dictionary = rd.PosDict()
134 key = rd.PosStr()
135 append_val = rd.PosValue()
136 rd.Done()
137
138 if key in dictionary:
139 UP_obj = dictionary[key]
140 if UP_obj.tag() == value_e.List:
141 lst = cast(value.List, UP_obj)
142 lst.items.append(append_val)
143 else:
144 raise error.TypeErr(UP_obj, 'append() expected the key to point to List',
145 rd.BlamePos())
146 else:
147 dictionary[key] = value.List([append_val])
148
149 return value.Null
150
151
152class Get(vm._Callable):
153
154 def __init__(self):
155 # type: () -> None
156 pass
157
158 def Call(self, rd):
159 # type: (typed_args.Reader) -> value_t
160
161 obj = rd.PosValue()
162 key = rd.PosStr()
163 default_value = rd.OptionalValue()
164 rd.Done()
165
166 UP_obj = obj
167 with tagswitch(obj) as case:
168 if case(value_e.Dict):
169 obj = cast(value.Dict, UP_obj)
170 d = obj.d
171 elif case(value_e.Obj):
172 obj = cast(Obj, UP_obj)
173 d = obj.d
174 else:
175 raise error.TypeErr(obj, 'get() expected Dict or Obj',
176 rd.BlamePos())
177
178 if default_value is None:
179 default_value = value.Null
180 return d.get(key, default_value)