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

194 lines, 116 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 Inc(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.PosValue()
97 rd.Done()
98
99 # default value for the dictionary entry is zero
100 if key in dictionary:
101 left = dictionary[key]
102 else:
103 left = value.Int(mops.ZERO)
104
105 c, i1, i2, f1, f2 = expr_eval.ConvertForBinaryOp(left, inc_val)
106
107 if c == coerced_e.Int:
108 res = value.Int(mops.Add(i1, i2)) # type: value_t
109 elif c == coerced_e.Float:
110 res = value.Float(f1 + f2)
111 else:
112 raise error.TypeErr(left, 'inc() expected Int/Float value in dict',
113 rd.BlamePos())
114
115 dictionary[key] = res
116
117 return value.Null
118
119
120class Append(vm._Callable):
121
122 def __init__(self):
123 # type: () -> None
124 pass
125
126 def Call(self, rd):
127 # type: (typed_args.Reader) -> value_t
128
129 dictionary = rd.PosDict()
130 key = rd.PosStr()
131 append_val = rd.PosValue()
132 rd.Done()
133
134 if key in dictionary:
135 UP_obj = dictionary[key]
136 if UP_obj.tag() == value_e.List:
137 lst = cast(value.List, UP_obj)
138 lst.items.append(append_val)
139 else:
140 raise error.TypeErr(UP_obj, 'append() expected List value in dict',
141 rd.BlamePos())
142 else:
143 dictionary[key] = value.List([append_val])
144
145 return value.Null
146
147
148class Update(vm._Callable):
149
150 def __init__(self):
151 # type: () -> None
152 pass
153
154 def Call(self, rd):
155 # type: (typed_args.Reader) -> value_t
156
157 dict_to_update = rd.PosDict()
158 other_dict = rd.PosDict()
159 rd.Done()
160
161 dict_to_update.update(other_dict)
162
163 return value.Null
164
165
166class Get(vm._Callable):
167
168 def __init__(self):
169 # type: () -> None
170 pass
171
172 def Call(self, rd):
173 # type: (typed_args.Reader) -> value_t
174
175 obj = rd.PosValue()
176 key = rd.PosStr()
177 default_value = rd.OptionalValue()
178 rd.Done()
179
180 UP_obj = obj
181 with tagswitch(obj) as case:
182 if case(value_e.Dict):
183 obj = cast(value.Dict, UP_obj)
184 d = obj.d
185 elif case(value_e.Obj):
186 obj = cast(Obj, UP_obj)
187 d = obj.d
188 else:
189 raise error.TypeErr(obj, 'get() expected Dict or Obj',
190 rd.BlamePos())
191
192 if default_value is None:
193 default_value = value.Null
194 return d.get(key, default_value)