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

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