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 Nary
15
16 module Branch
17
18 module Rule
19
20 module Case
21
22 class Datum < Abstract
23 alias tag_sym obj
24 attr_reader :opt_contents_pat
25
26 def initialize(loc, tag_sym, opt_contents_pat)
27 ASSERT.kind_of tag_sym, ::Symbol
28 ASSERT.opt_kind_of opt_contents_pat, CSCP::Abstract
29
30 super(loc, tag_sym)
31
32 @opt_contents_pat = opt_contents_pat
33 end
34
35
36 def type_sym
37 :Datum
38 end
39
40
41 def to_s
42 format("%s%s",
43 self.tag_sym.to_s,
44
45 if self.opt_contents_pat
46 ' ' + self.opt_contents_pat.to_s
47 else
48 ''
49 end
50 )
51 end
52
53
54 def pretty_print(q)
55 q.text self.tag_sym.to_s
56
57 if self.opt_contents_pat
58 q.text ' '
59 q.pp self.opt_contents_pat
60 end
61 end
62
63
64 def desugar_for_rule(env, case_expr)
65 ASSERT.kind_of case_expr, Branch::Case
66
67 source_expr = case_expr.expr.desugar env
68
69 leafs = case_expr.rules.inject({}) { |leafs, rule|
70 ASSERT.kind_of leafs, ::Hash
71 ASSERT.kind_of rule, Rule::Abstraction::Abstract
72
73 head = rule.head
74 ASSERT.kind_of head, Rule::Case::Abstract
75 unless head.kind_of? Rule::Case::Datum
76 raise X::SyntaxError.new(
77 rule.loc,
78 format("Inconsistent rule categories " +
79 "in case-expression, " +
80 "1st is %s : %s(#%d), " +
81 "but another is %s : %s(#%d)",
82 self.to_s,
83 self.type_sym.to_s,
84 self.loc.line_num + 1,
85 __escape_string_format__(head.to_s),
86 head.type_sym.to_s,
87 head.loc.line_num + 1
88 )
89 )
90 end
91
92 body_expr = if head.opt_contents_pat
93 contents_decl = head.opt_contents_pat.desugar_value(
94 ASCE.make_send(
95 case_expr.expr.loc,
96
97 if source_expr.simple?
98 source_expr
99 else
100 ASCE.make_identifier(
101 source_expr.loc, :'%x'
102 )
103 end,
104
105 ASCE.make_message(
106 case_expr.expr.loc, :contents
107 )
108 ),
109
110 env
111 )
112 ASSERT.kind_of contents_decl, ASCD::Abstract
113
114 ASCE.make_let(
115 rule.loc,
116
117 ASCD.make_seq_of_declaration(
118 rule.loc,
119 [contents_decl]
120 ),
121
122 rule.body_expr.desugar(env)
123 )
124 else
125 case_expr.desugar_body_expr env, rule
126 end
127
128 leafs.merge(head.tag_sym => body_expr) {
129 raise X::SyntaxError.new(
130 rule.loc,
131 format("Duplicated rules in case-expression: %s",
132 head.to_s
133 )
134 )
135 }
136 }
137
138 if source_expr.simple?
139 ASCE.make_switch(
140 case_expr.loc,
141 ASCE.make_send(
142 source_expr.loc,
143 source_expr,
144 ASCE.make_message(source_expr.loc, :tag),
145 [],
146 :Datum
147 ),
148 :Symbol,
149 leafs,
150 case_expr.desugar_else_expr(env)
151 )
152 else
153 ASCE.make_let(
154 case_expr.loc,
155
156 ASCD.make_seq_of_declaration(
157 source_expr.loc,
158 [ASCD.make_value(source_expr.loc, :'%x', source_expr)]
159 ),
160
161 ASCE.make_switch(
162 case_expr.loc,
163 ASCE.make_send(
164 source_expr.loc,
165 ASCE.make_identifier(source_expr.loc, :'%x'),
166 ASCE.make_message(source_expr.loc, :tag)
167 ),
168 :Symbol,
169 leafs,
170 case_expr.desugar_else_expr(env)
171 )
172 )
173 end
174 end
175 end
176
177 end # Umu::ConcreteSyntax::Core::Expression::Nary::Branch::Rule::Case
178
179 end # Umu::ConcreteSyntax::Core::Expression::Nary::Branch::Rule
180
181 end # Umu::ConcreteSyntax::Core::Expression::Nary::Branch
182
183 end # Umu::ConcreteSyntax::Core::Expression::Nary
184
185
186 module_function
187
188 def make_case_rule_datum(loc, tag_sym, opt_contents_pat)
189 ASSERT.kind_of loc, LOC::Entry
190 ASSERT.kind_of tag_sym, ::Symbol
191 ASSERT.opt_kind_of opt_contents_pat, CSCP::Abstract
192
193 Nary::Branch::Rule::Case::Datum.new(
194 loc, tag_sym, opt_contents_pat
195 ).freeze
196 end
197
198 end # Umu::ConcreteSyntax::Core::Expression
199
200 end # Umu::ConcreteSyntax::Core
201
202 end # Umu::ConcreteSyntax
203
204 end # Umu