1 # coding: utf-8
2 # frozen_string_literal: true
3
4
5
6 module Umu
7
8 module ConcreteSyntax
9
10 module Core
11
12 module Expression
13
14 module Unary
15
16 module Container
17
18 module Named
19
20 class Label < Unary::Abstract
21 alias sym obj
22
23
24 def initialize(loc, sym)
25 ASSERT.kind_of sym, ::Symbol
26
27 super
28 end
29
30
31 def hash
32 self.sym.hash
33 end
34
35
36 def eql?(other)
37 self.sym.eql? other.sym
38 end
39
40
41 def to_s
42 self.sym.to_s + ':'
43 end
44
45
46 private
47
48 def __desugar__(_env, _event)
49 ASCE.make_named_tuple_label self.loc, self.sym
50 end
51 end
52
53
54
55 class Entry < Abstract
56 attr_reader :index_by_label
57
58
59 def initialize(loc, fields)
60 ASSERT.kind_of fields, ::Array
61 ASSERT.assert fields.size >= 2
62
63 index_by_label, exprs = fields.each_with_index.inject([{}, []]) {
64 |(hash, array), (pair, index)|
65 ASSERT.kind_of hash, ::Hash
66 ASSERT.kind_of array, ::Array
67 ASSERT.kind_of pair, ::Array
68 ASSERT.kind_of index, ::Integer
69
70 label, opt_expr = pair
71 ASSERT.kind_of label, Label
72 ASSERT.opt_kind_of opt_expr, CSCE::Abstract
73
74 [
75 hash.merge(label => index) {
76 raise X::SyntaxError.new(
77 label.loc,
78 format("Duplicated label in named tuple: '%s'",
79 label.sym
80 )
81 )
82 },
83
84 array + [opt_expr]
85 ]
86 }
87
88 @index_by_label = index_by_label.freeze
89
90 super(loc, exprs.freeze)
91 end
92
93
94 def to_s
95 format("(%s)",
96 self.index_by_label.map { |label, index|
97 opt_expr = self.exprs[index]
98
99 format("%s%s",
100 label.to_s,
101 opt_expr ? opt_expr.to_s : ''
102 )
103 }.join(' ')
104 )
105 end
106
107
108 def pretty_print(q)
109 PRT.group_for_enum(
110 q, self.index_by_label, bb:'(', eb:')', join:' '
111 ) do |label, index|
112
113 opt_expr = self.exprs[index]
114
115 q.text label.to_s
116 if opt_expr
117 q.pp opt_expr
118 end
119 end
120 end
121
122
123 private
124
125 def __desugar__(env, event)
126 new_env = env.enter event
127
128 exprs = self.index_by_label.inject([]) { |array, (label, index)|
129 opt_expr = self.exprs[index]
130
131 array + [
132 if opt_expr
133 opt_expr.desugar(new_env)
134 else
135 ASCE.make_identifier label.loc, label.sym
136 end
137 ]
138 }
139
140 index_by_label = self.index_by_label.inject({}) {
141 |hash, (label, index)|
142
143 hash.merge(label.desugar(new_env) => index)
144 }
145
146 ASCE.make_named_tuple self.loc, exprs, index_by_label
147 end
148 end
149
150 end # Umu::ConcreteSyntax::Core::Expression::Unary::Container::Named
151
152 end # Umu::ConcreteSyntax::Core::Expression::Unary::Container
153
154 end # Umu::ConcreteSyntax::Core::Expression::Unary
155
156
157 module_function
158
159 def make_named_tuple_label(loc, sym)
160 ASSERT.kind_of loc, LOC::Entry
161 ASSERT.kind_of sym, ::Symbol
162
163 Unary::Container::Named::Label.new(loc, sym).freeze
164 end
165
166
167 def make_named_tuple(loc, fields)
168 ASSERT.kind_of loc, LOC::Entry
169 ASSERT.kind_of fields, ::Array
170
171 Unary::Container::Named::Entry.new(loc, fields.freeze).freeze
172 end
173
174 end # Umu::ConcreteSyntax::Core::Expression
175
176 end # Umu::ConcreteSyntax::Core
177
178 end # Umu::ConcreteSyntax
179
180 end # Umu