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 module If
17
18 class Rule < Abstraction::Model
19 attr_reader :head_expr, :body_expr
20
21
22 def initialize(loc, head_expr, body_expr)
23 ASSERT.kind_of head_expr, ASCE::Abstract
24 ASSERT.kind_of body_expr, ASCE::Abstract
25
26 super(loc)
27
28 @head_expr = head_expr
29 @body_expr = body_expr
30 end
31
32
33 def to_s
34 format "%s %%THEN %s", self.head_expr, self.body_expr
35 end
36
37
38 def pretty_print(q)
39 q.pp self.head_expr
40
41 q.breakable ' '
42
43 q.text '%THEN'
44
45 q.breakable ' '
46
47 q.pp self.body_expr
48 end
49 end
50
51
52
53 class Entry < Expression::Abstract
54 attr_reader :rules, :else_expr
55
56
57 def initialize(loc, rules, else_expr)
58 ASSERT.kind_of rules, ::Array
59 ASSERT.kind_of else_expr, ASCE::Abstract
60
61 super(loc)
62
63 @rules = rules
64 @else_expr = else_expr
65 end
66
67
68 def to_s
69 rules_string = case self.rules.size
70 when 0
71 ''
72 when 1
73 self.rules[0].to_s + ' '
74 else
75 head_rule, *tail_rules = self.rules
76
77 format("%s %s ",
78 head_rule.to_s,
79
80 tail_rules.map { |rule|
81 '%ELSIF ' + rule.to_s
82 }.join(' ')
83 )
84 end
85
86 format("(%%IF %s%%ELSE %s)",
87 rules_string,
88 self.else_expr.to_s
89 )
90 end
91
92
93 def pretty_print(q)
94 q.text '('
95 PRT.group q do
96 q.breakable ''
97
98 case self.rules.size
99 when 0
100 q.text '%IF'
101 when 1
102 PRT.group q, bb:'%IF ' do
103 q.pp self.rules[0]
104 end
105 else
106 hd_rule, *tl_rules = self.rules
107
108 PRT.group q, bb:'%IF ' do
109 q.pp hd_rule
110 end
111
112 tl_rules.each do |rule|
113 q.breakable
114
115 PRT.group q, bb:'%ELSIF ' do
116 q.pp rule
117 end
118 end
119 end
120
121 q.breakable
122
123 PRT.group q, bb:'%ELSE ' do
124 q.pp self.else_expr
125 end
126 end
127 q.text ')'
128 end
129
130
131 private
132
133 def __evaluate__(env, event)
134 ASSERT.kind_of env, E::Entry
135 ASSERT.kind_of event, E::Tracer::Event
136
137 new_env = env.enter event
138
139 result = self.rules.inject(self.else_expr) { |expr, rule|
140 ASSERT.kind_of expr, ASCE::Abstract
141 ASSERT.kind_of rule, Rule
142
143 head_result = rule.head_expr.evaluate new_env
144 ASSERT.kind_of head_result, ASR::Value
145
146 head_value = head_result.value
147 unless head_value.kind_of? VCA::Bool
148 raise X::TypeError.new(
149 rule.loc,
150 env,
151 "Expected a Bool, but %s : %s",
152 head_value.to_s,
153 head_value.type_sym.to_s
154 )
155 end
156
157 if head_value.true?
158 break rule.body_expr
159 end
160
161 expr
162 }.evaluate new_env
163 ASSERT.kind_of result, ASR::Value
164
165 result.value
166 end
167 end
168
169 end # Umu::AbstractSyntax::Core::Expression::Nary::If
170
171 end # Umu::AbstractSyntax::Core::Expression::Nary
172
173
174 module_function
175
176 def make_rule(loc, head_expr, body_expr)
177 ASSERT.kind_of loc, LOC::Entry
178 ASSERT.kind_of head_expr, ASCE::Abstract
179 ASSERT.kind_of body_expr, ASCE::Abstract
180
181 Nary::If::Rule.new(loc, head_expr, body_expr).freeze
182 end
183
184
185 def make_if(loc, rules, else_expr)
186 ASSERT.kind_of loc, LOC::Entry
187 ASSERT.kind_of rules, ::Array
188 ASSERT.kind_of else_expr, ASCE::Abstract
189
190 Nary::If::Entry.new(loc, rules, else_expr).freeze
191 end
192
193 end # Umu::AbstractSyntax::Core::Expression
194
195 end # Umu::AbstractSyntax::Core
196
197 end # Umu::AbstractSyntax
198
199 end # Umu