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

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