1 # coding: utf-8
2 # frozen_string_literal: true
3
4
5
6 module Umu
7
8 module Value
9
10 module Core
11
12 module Atom
13
14 module Number
15
16 class Abstract < Atom::Abstract
17 def initialize(val)
18 ASSERT.kind_of val, ::Numeric
19
20 super
21 end
22
23
24 def to_s
25 val = self.val
26
27 if val < 0
28 format "-%s", val.abs.inspect
29 else
30 val.inspect
31 end
32 end
33
34
35 define_instance_method(
36 :meth_is_zero,
37 :zero?, [],
38 [], VCA::Bool
39 )
40 def meth_is_zero(_loc, _env, _event)
41 VC.make_bool self.val.zero?
42 end
43
44
45 define_instance_method(
46 :meth_is_positive,
47 :positive?, [],
48 [], VCA::Bool
49 )
50 def meth_is_positive(_loc, _env, _event)
51 VC.make_bool(self.val > 0)
52 end
53
54
55 define_instance_method(
56 :meth_is_negative,
57 :negative?, [],
58 [], VCA::Bool
59 )
60 def meth_is_negative(_loc, _env, _event)
61 VC.make_bool(self.val < 0)
62 end
63
64
65 define_instance_method(
66 :meth_to_int,
67 :'to-i', [],
68 [], VCAN::Int
69 )
70 def meth_to_int(loc, env, _event)
71 begin
72 VC.make_integer self.val.to_i
73 rescue ::FloatDomainError
74 raise X::ArgumentError.new(
75 loc,
76 env,
77 "Domain error on float number %s : %s",
78 self.to_s,
79 self.type_sym.to_s
80 )
81 end
82 end
83
84
85 define_instance_method(
86 :meth_to_float,
87 :'to-f', [],
88 [], VCAN::Float
89 )
90 def meth_to_float(_loc, _env, _event)
91 VC.make_float self.val.to_f
92 end
93
94
95 define_instance_method(
96 :meth_negate,
97 :negate, [],
98 [], self
99 )
100 def meth_negate(_loc, _env, _event)
101 VC.make_number self.class, - self.val
102 end
103
104
105 define_instance_method(
106 :meth_absolute,
107 :abs, [],
108 [], self
109 )
110 def meth_absolute(_loc, _env, _event)
111 VC.make_number self.class, self.val.abs
112 end
113
114
115 def +(other)
116 ASSERT.kind_of other, Number::Abstract
117
118 VC.make_number self.class, self.val + other.val
119 end
120
121
122 define_instance_method(
123 :meth_add,
124 :'+', [],
125 [self], self
126 )
127 def meth_add(_loc, _env, _event, other)
128 ASSERT.kind_of other, Number::Abstract
129
130 self.+ other
131 end
132
133
134 define_instance_method(
135 :meth_sub,
136 :'-', [],
137 [self], self
138 )
139 def meth_sub(_loc, _env, _event, other)
140 ASSERT.kind_of other, Number::Abstract
141
142 VC.make_number self.class, self.val - other.val
143 end
144
145
146 define_instance_method(
147 :meth_multiply,
148 :'*', [],
149 [self], self
150 )
151 def meth_multiply(_loc, _env, _event, other)
152 ASSERT.kind_of other, Number::Abstract
153
154 VC.make_number self.class, self.val * other.val
155 end
156
157
158 define_instance_method(
159 :meth_divide,
160 :'/', [],
161 [self], self
162 )
163 def meth_divide(loc, env, _event, other)
164 ASSERT.kind_of other, Number::Abstract
165
166 begin
167 VC.make_number self.class, self.val / other.val
168 rescue ::ZeroDivisionError
169 raise X::ZeroDivisionError.new(
170 loc,
171 env,
172 "Zero devision error"
173 )
174 end
175 end
176
177
178 define_instance_method(
179 :meth_modulo,
180 :mod, [],
181 [self], self
182 )
183 def meth_modulo(loc, env, _event, other)
184 ASSERT.kind_of other, Number::Abstract
185
186 begin
187 VC.make_number self.class, self.val % other.val
188 rescue ::ZeroDivisionError
189 raise X::ZeroDivisionError.new(
190 loc,
191 env,
192 "Zero devision error"
193 )
194 end
195 end
196
197
198 define_instance_method(
199 :meth_power,
200 :pow, [],
201 [self], self
202 )
203 def meth_power(loc, env, _event, other)
204 ASSERT.kind_of other, Number::Abstract
205
206 begin
207 VC.make_number self.class, self.val ** other.val
208 rescue ::ZeroDivisionError
209 raise X::ZeroDivisionError.new(
210 loc,
211 env,
212 "Zero devision error"
213 )
214 end
215 end
216
217
218 define_instance_method(
219 :meth_random,
220 :random, [],
221 [], self
222 )
223 def meth_random(loc, env, _event)
224 value = if self.val > 0
225 begin
226 VC.make_number self.class, ::Random.rand(self.val)
227 rescue Errno::EDOM
228 raise X::ArgumentError.new(
229 loc,
230 env,
231 "Domain error on float number %s : %s",
232 self.to_s,
233 self.type_sym.to_s
234 )
235 end
236 elsif self.val < 0
237 raise X::ArgumentError.new(
238 loc,
239 env,
240 "Invalid argument %s : %s",
241 self.to_s,
242 self.type_sym.to_s
243 )
244 else
245 self
246 end
247
248 ASSERT.kind_of value, Number::Abstract
249 end
250 end
251 Abstract.freeze
252
253 end # Umu::Value::Core::Atom::Number
254
255 end # Umu::Value::Core::Atom
256
257
258 module_function
259
260 def make_number(klass, val)
261 ASSERT.subclass_of klass, VCAN::Abstract
262 ASSERT.kind_of val, ::Numeric
263
264 klass.new(val).freeze
265 end
266
267 end # Umu::Value::Core
268
269 end # Umu::Value
270
271 end # Umu