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 Morph
13
14 module List
15
16 class Abstract < Morph::Abstract
17 def self.make(xs)
18 ASSERT.kind_of xs, ::Array
19
20 VC.make_list xs
21 end
22
23
24 define_class_method(
25 :meth_make_empty,
26 :empty, [],
27 [], self
28 )
29 def self.meth_make_empty(_loc, _env, _event)
30 VC.make_nil
31 end
32
33
34 include Enumerable
35
36 def each
37 return self.to_enum unless block_given?
38
39 xs = self
40 while xs.kind_of? Cons
41 yield xs.head
42
43 xs = xs.tail
44 end
45
46 nil
47 end
48
49
50 def to_s
51 format "[%s]", self.map(&:to_s).join(', ')
52 end
53
54
55 def pretty_print(q)
56 PRT.group_for_enum q, self, bb:'[', eb:']', join:', '
57 end
58
59
60 define_instance_method(
61 :meth_cons,
62 :cons, [],
63 [VC::Top], self
64 )
65 def meth_cons(_loc, _env, _event, value)
66 ASSERT.kind_of value, VC::Top
67
68 VC.make_cons value, self
69 end
70
71
72 def meth_to_string(loc, env, event)
73 VC.make_string(
74 format("[%s]",
75 self.map { |elem|
76 elem.meth_to_string(loc, env, event).val
77 }.join(', ')
78 )
79 )
80 end
81
82
83 def meth_to_list(loc, env, event)
84 self
85 end
86 end
87 Abstract.freeze
88
89
90
91 class Nil < Abstract
92 def meth_head(loc, env, _event)
93 raise X::EmptyError.new loc, env, "head: Empty morph"
94 end
95
96
97 def meth_tail(loc, env, _event)
98 raise X::EmptyError.new loc, env, "rail: Empty morph"
99 end
100
101
102 def meth_is_empty(_loc, _env, _event)
103 VC.make_true
104 end
105
106
107 def meth_dest(_loc, _env, _event)
108 VC.make_none
109 end
110
111
112 def meth_dest!(loc, env, _event)
113 raise X::EmptyError.new loc, env, "dest!: Empty morph"
114 end
115 end
116 Nil.freeze
117
118 NIL = Nil.new.freeze
119
120
121
122 class Cons < Abstract
123 attr_reader :head, :tail
124
125
126 def initialize(head, tail)
127 ASSERT.kind_of head, VC::Top
128 ASSERT.kind_of tail, List::Abstract
129
130 super()
131
132 @head = head
133 @tail = tail
134 end
135
136
137 def meth_head(_loc, _env, _event)
138 self.head
139 end
140
141
142 def meth_tail(_loc, _env, _event)
143 self.tail
144 end
145
146
147 def meth_is_empty(_loc, _env, _event)
148 VC.make_false
149 end
150
151
152 def meth_dest(_loc, _env, _event)
153 VC.make_some self.contents
154 end
155
156
157 def contents
158 VC.make_tuple self.head, self.tail
159 end
160
161
162 define_instance_method(
163 :meth_contents,
164 :contents, [],
165 [], VCP::Tuple
166 )
167 alias meth_contents meth_dest!
168 end
169 Cons.freeze
170
171 end # Umu::Value::Core::Morph::List
172
173 end # Umu::Value::Core::Morph
174
175
176 module_function
177
178 def make_nil
179 Morph::List::NIL
180 end
181
182
183 def make_cons(head, tail)
184 ASSERT.kind_of head, VC::Top
185 ASSERT.kind_of tail, Morph::List::Abstract
186
187 Morph::List::Cons.new(head, tail).freeze
188 end
189
190
191 def make_list(xs, tail = VC.make_nil)
192 ASSERT.kind_of xs, ::Array
193 ASSERT.kind_of tail, Morph::List::Abstract
194
195 xs.reverse_each.inject(tail) { |ys, x|
196 VC.make_cons x, ys
197 }
198 end
199
200 end # Umu::Value::Core
201
202 end # Umu::Value
203
204 end # Umu