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 SExpression
15
16 class Abstract < Expression::Abstract; end
17
18
19
20 class Nil < Abstract
21 def to_s
22 '()'
23 end
24
25
26 def __evaluate__(_env, _event)
27 VC.make_s_expr_nil
28 end
29 end
30
31
32
33 class Atom < Abstract
34 attr_reader :val
35
36 def initialize(loc, val)
37 ASSERT.kind_of val, VCA::Abstract
38
39 super(loc)
40
41 @val = val
42 end
43
44
45 def to_s
46 self.val.to_s
47 end
48
49
50 def __evaluate__(_env, _event)
51 VC.make_s_expr_value self.val
52 end
53 end
54
55
56
57 class Embeded < Abstract
58 attr_reader :expr
59
60 def initialize(loc, expr)
61 ASSERT.kind_of expr, ASCE::Abstract
62
63 super(loc)
64
65 @expr = expr
66 end
67
68
69 def to_s
70 self.expr.to_s
71 end
72
73
74 def pretty_print(q)
75 q.pp self.expr
76 end
77
78
79 def __evaluate__(env, event)
80 value = self.expr.evaluate(env.enter(event)).value
81
82 VC.validate_s_expr value, '<Embeded S-Expr>', self.loc, env
83
84 value
85 end
86 end
87
88
89
90 class List < Abstract
91 attr_reader :fst_expr, :snd_exprs, :opt_expr
92
93 def initialize(loc, fst_expr, snd_exprs, opt_expr)
94 ASSERT.kind_of fst_expr, SExpression::Abstract
95 ASSERT.kind_of snd_exprs, ::Array
96 ASSERT.opt_kind_of opt_expr, SExpression::Abstract
97 snd_exprs.each do |expr|
98 ASSERT.kind_of expr, SExpression::Abstract
99 end
100
101 super(loc)
102
103 @fst_expr = fst_expr
104 @snd_exprs = snd_exprs
105 @opt_expr = opt_expr
106 end
107
108
109 def exprs
110 [self.fst_expr] + self.snd_exprs
111 end
112
113
114 def to_s
115 format("%%S(%s%s)",
116 self.exprs.map(&:to_s).join(' '),
117
118 if self.opt_expr
119 format " . %s", self.opt_expr.to_s
120 else
121 ''
122 end
123 )
124 end
125
126
127 def pretty_print(q)
128 PRT.group_for_enum q, self.exprs, bb:'%S(', join:' '
129
130 q.breakable
131
132 if self.opt_expr
133 PRT.group q, bb:'.', sep:' ' do
134 q.pp self.opt_expr
135 end
136 end
137 q.text ')'
138 end
139
140
141 def __evaluate__(env, event)
142 new_env = env.enter event
143
144 head_vals = self.exprs.map { |expr|
145 val = expr.evaluate(new_env).value
146
147 VC.validate_s_expr val, '<S-Expr>', self.loc, env
148
149 val
150 }
151
152 tail_val = if self.opt_expr
153 val = self.opt_expr.evaluate(new_env).value
154
155 VC.validate_s_expr val, '<S-Expr>', self.loc, env
156
157 val
158 else
159 VC.make_s_expr_nil
160 end
161
162 head_vals.reverse.inject(tail_val) { |xs, x|
163 VC.make_s_expr_cons x, xs
164 }
165 end
166 end
167
168 end # Umu::AbstractSyntax::Core::Expression::SExpression
169
170
171 module_function
172
173 def make_s_expr_nil(loc)
174 ASSERT.kind_of loc, LOC::Entry
175
176 SExpression::Nil.new(loc).freeze
177 end
178
179
180 def make_s_expr_atom(loc, val)
181 ASSERT.kind_of loc, LOC::Entry
182 ASSERT.kind_of val, VCA::Abstract
183
184 SExpression::Atom.new(loc, val).freeze
185 end
186
187
188 def make_s_expr_embeded(loc, expr)
189 ASSERT.kind_of loc, LOC::Entry
190 ASSERT.kind_of expr, ASCE::Abstract
191
192 SExpression::Embeded.new(loc, expr).freeze
193 end
194
195
196 def make_s_expr_list(loc, fst_expr, snd_exprs, opt_expr = nil)
197 ASSERT.kind_of loc, LOC::Entry
198 ASSERT.kind_of fst_expr, SExpression::Abstract
199 ASSERT.kind_of snd_exprs, ::Array
200 ASSERT.opt_kind_of opt_expr, SExpression::Abstract
201
202 SExpression::List.new(
203 loc, fst_expr, snd_exprs.freeze, opt_expr
204 ).freeze
205 end
206
207 end # Umu::AbstractSyntax::Core::Expression
208
209 end # Umu::AbstractSyntax::Core
210
211 end # Umu::AbstractSyntax
212
213 end # Umu