1 # coding: utf-8
2 # frozen_string_literal: true
3
4
5
6 module Umu
7
8 module AbstractSyntax
9
10 module Core
11
12 module Expression
13
14 module Nary
15
16 class Switch < Expression::Abstract
17 attr_reader :source_expr, :souce_type_sym, :leafs, :else_expr
18
19
20 def initialize(loc, source_expr, souce_type_sym, leafs, else_expr)
21 ASSERT.kind_of source_expr, ASCE::Abstract
22 ASSERT.kind_of souce_type_sym, ::Symbol
23 ASSERT.kind_of leafs, ::Hash
24 ASSERT.kind_of else_expr, ASCE::Abstract
25
26 super(loc)
27
28 @source_expr = source_expr
29 @souce_type_sym = souce_type_sym
30 @leafs = leafs
31 @else_expr = else_expr
32 end
33
34
35 def to_s
36 format("%%SWITCH %s : %s { %s %%ELSE -> %s}",
37 self.source_expr.to_s,
38
39 self.souce_type_sym.to_s,
40
41 self.leafs.map { |(head, body)|
42 format "%s -> %s", head.to_s, body.to_s
43 }.join(' | '),
44
45 self.else_expr.to_s
46 )
47 end
48
49
50 def pretty_print(q)
51 q.text '%SWITCH '
52 q.pp self.source_expr
53 q.text ' : '
54 q.text self.souce_type_sym.to_s
55 q.text ' {'
56
57 case self.leafs.size
58 when 0
59 # Nothing to do
60 when 1
61 q.breakable ''
62
63 head, body = self.leafs.first
64 __pretty_print_leaf__ q, head, body
65 else
66 q.breakable ''
67
68 q.text '| '
69 fst_head, fst_body = self.leafs.first
70 __pretty_print_leaf__ q, fst_head, fst_body
71
72 not_fst_leafs = self.leafs.reject { |hd, _| hd.eql? fst_head }
73 not_fst_leafs.each do |(head, body)|
74 q.breakable ''
75
76 q.text '| '
77 PRT.group q do
78 __pretty_print_leaf__ q, head, body
79 end
80 end
81 end
82
83 q.breakable ''
84
85 q.text '%ELSE -> '
86 PRT.group q do
87 q.breakable ''
88
89 q.pp self.else_expr
90 end
91
92 q.breakable ''
93
94 q.text '}'
95 end
96
97
98 private
99
100 def __pretty_print_leaf__(q, head, body)
101 q.pp head
102 q.text ' -> '
103 PRT.group q do
104 q.pp body
105 end
106 end
107
108
109 def __evaluate__(env, event)
110 ASSERT.kind_of env, E::Entry
111 ASSERT.kind_of event, E::Tracer::Event
112
113 new_env = env.enter event
114
115 source_result = self.source_expr.evaluate new_env
116 ASSERT.kind_of source_result, ASR::Value
117 source_value = source_result.value
118
119 source_signat = new_env.ty_lookup self.souce_type_sym, self.loc
120 ASSERT.kind_of source_signat, ECTSC::Base
121 unless env.ty_kind_of?(source_value, source_signat)
122 raise X::TypeError.new(
123 self.loc,
124 env,
125 "Type error in case-expression, " +
126 "expected a %s, but %s : %s",
127 self.souce_type_sym,
128 source_value,
129 source_value.type_sym
130 )
131 end
132
133 opt_leaf_expr = self.leafs[source_value.val]
134 ASSERT.opt_kind_of opt_leaf_expr, ASCE::Abstract
135
136 result = (
137 if opt_leaf_expr
138 opt_leaf_expr
139 else
140 self.else_expr
141 end
142 ).evaluate new_env
143 ASSERT.kind_of result, ASR::Value
144
145 result.value
146 end
147 end
148
149 end # Umu::AbstractSyntax::Core::Expression::Nary
150
151
152 module_function
153
154 def make_switch(loc, source_expr, souce_type_sym, leafs, else_expr)
155 ASSERT.kind_of loc, LOC::Entry
156 ASSERT.kind_of source_expr, ASCE::Abstract
157 ASSERT.kind_of souce_type_sym, ::Symbol
158 ASSERT.kind_of leafs, ::Hash
159 ASSERT.kind_of else_expr, ASCE::Abstract
160
161 Nary::Switch.new(
162 loc, source_expr, souce_type_sym, leafs, else_expr
163 ).freeze
164 end
165
166 end # Umu::AbstractSyntax::Core::Expression
167
168 end # Umu::AbstractSyntax::Core
169
170 end # Umu::AbstractSyntax
171
172 end # Umu