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 Product
13
14 class Tuple < Abstract
15 alias values objs
16
17
18 def to_s
19 format "(%s)", self.map(&:to_s).join(', ')
20 end
21
22
23 def pretty_print(q)
24 PRT.group_for_enum q, self, bb:'(', eb:')', join:', '
25 end
26
27
28 define_instance_method(
29 :meth_to_string,
30 :'to-s', [],
31 [], VCA::String
32 )
33 def meth_to_string(loc, env, event)
34 VC.make_string(
35 format("(%s)",
36 self.map { |elem|
37 elem.meth_to_string(loc, env, event).val
38 }.join(', ')
39 )
40 )
41 end
42
43
44 define_instance_method(
45 :meth_is_equal,
46 :'==', [],
47 [VC::Top], VCA::Bool
48 )
49 def meth_is_equal(loc, env, event, other)
50 ASSERT.kind_of other, VC::Top
51
52 unless other.kind_of?(self.class) && self.arity == other.arity
53 return VC.make_false
54 end
55
56 VC.make_bool(
57 self.values.zip(other.values).all? {
58 |self_value, other_value|
59
60 other_value.kind_of?(self_value.class) &&
61 self_value.meth_is_equal(loc, env, event, other_value).true?
62 }
63 )
64 end
65
66
67 define_instance_method(
68 :meth_is_less_than,
69 :'<', [],
70 [self], VCA::Bool
71 )
72 def meth_is_less_than(loc, env, event, other)
73 ASSERT.kind_of other, VCP::Tuple
74
75 unless other.kind_of?(self.class) && self.arity == other.arity
76 raise X::TypeError.new(
77 loc,
78 env,
79 "Expected a tuple of %d element, but %d: %s",
80 self.arity, other.arity, other.to_s
81 )
82 end
83
84 result, _index = self.values
85 .zip(other.values)
86 .inject([VC.make_false, 0]) {
87 |(res, index), (self_value, other_value)|
88 ASSERT.kind_of res, VCA::Bool
89 ASSERT.kind_of index, ::Integer
90 ASSERT.kind_of self_value, VC::Top
91 ASSERT.kind_of other_value, VC::Top
92
93 unless other_value.kind_of?(self_value.class)
94 raise X::TypeError.new(
95 loc,
96 env,
97 "In %d's element of tuple, " +
98 "expected a %s, but %s : %s",
99 index + 1,
100 self_value.type_sym,
101 other_value.to_s,
102 other_value.type_sym
103 )
104 end
105
106 if self_value.meth_is_less_than( # self < other
107 loc, env, event, other_value
108 ).true?
109 break VC.make_true
110 elsif self_value.meth_is_equal( # self = other
111 loc, env, event, other_value
112 ).true?
113 [res, index + 1]
114 elsif other_value.meth_is_less_than( # self > other
115 loc, env, event, self_value
116 ).true?
117 break VC.make_false
118 else
119 ASSERT.abort 'No case'
120 end
121 }
122
123 ASSERT.kind_of result, VCA::Bool
124 end
125 end
126 Tuple.freeze
127
128 end # Umu::Value::Core::Product
129
130
131 module_function
132
133 def make_tuple(fst_value, snd_value, *tail_values)
134 ASSERT.kind_of fst_value, ::Object
135 ASSERT.kind_of snd_value, ::Object
136 ASSERT.kind_of tail_values, ::Array
137
138 Product::Tuple.new(
139 fst_value, snd_value, tail_values.freeze
140 ).freeze
141 end
142
143 end # Umu::Value::Core
144
145 end # Umu::Value
146
147 end # Umu