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

165 lines, 104 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
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 val_ops
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.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 if key in dictionary:
104 typed_val = dictionary[key]
105 else:
106 typed_val = value.Int(mops.BigInt(0))
107 else:
108 typed_val = inc_val
109
110 with tagswitch(typed_val) as case:
111 if case(value_e.Int):
112 if inc_val is None:
113 inc_int = 1
114 else:
115 inc_int = val_ops.ToInt(inc_val, '', loc.Missing)
116 original_int = val_ops.ToInt(dictionary.get(key, value.Int(mops.ZERO)),
117 'Inc() expected int',
118 loc.Missing)
119 dictionary[key] = value.Int(mops.BigInt(original_int + inc_int))
120
121 elif case(value_e.Float):
122 if inc_val is None:
123 inc_float = 1.0
124 else:
125 inc_float = val_ops.ToFloat(inc_val, '', loc.Missing)
126 original_float = val_ops.ToFloat(dictionary.get(key, value.Float(0.0)),
127 'Inc() expected int',
128 loc.Missing)
129 dictionary[key] = value.Float(original_float + inc_float)
130 else:
131 raise error.TypeErr(typed_val, 'inc() expected Int or float',
132 rd.BlamePos())
133
134 return value.Null
135
136
137class Get(vm._Callable):
138
139 def __init__(self):
140 # type: () -> None
141 pass
142
143 def Call(self, rd):
144 # type: (typed_args.Reader) -> value_t
145
146 obj = rd.PosValue()
147 key = rd.PosStr()
148 default_value = rd.OptionalValue()
149 rd.Done()
150
151 UP_obj = obj
152 with tagswitch(obj) as case:
153 if case(value_e.Dict):
154 obj = cast(value.Dict, UP_obj)
155 d = obj.d
156 elif case(value_e.Obj):
157 obj = cast(Obj, UP_obj)
158 d = obj.d
159 else:
160 raise error.TypeErr(obj, 'get() expected Dict or Obj',
161 rd.BlamePos())
162
163 if default_value is None:
164 default_value = value.Null
165 return d.get(key, default_value)