skeem 0.0.23 → 0.0.24
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/CHANGELOG.md +11 -0
- data/README.md +11 -6
- data/lib/skeem/datum_dsl.rb +139 -0
- data/lib/skeem/element_visitor.rb +91 -0
- data/lib/skeem/grammar.rb +31 -8
- data/lib/skeem/interpreter.rb +1 -1
- data/lib/skeem/primitive/primitive_builder.rb +47 -37
- data/lib/skeem/runtime.rb +28 -4
- data/lib/skeem/s_expr_builder.rb +64 -25
- data/lib/skeem/s_expr_nodes.rb +81 -327
- data/lib/skeem/skm_compound_datum.rb +118 -0
- data/lib/skeem/skm_element.rb +85 -0
- data/lib/skeem/skm_expression.rb +7 -0
- data/lib/skeem/skm_simple_datum.rb +132 -0
- data/lib/skeem/skm_unary_expression.rb +107 -0
- data/lib/skeem/standard/base.skm +3 -3
- data/lib/skeem/tokenizer.rb +8 -1
- data/lib/skeem/version.rb +1 -1
- data/spec/skeem/datum_dsl_spec.rb +191 -0
- data/spec/skeem/element_visitor_spec.rb +170 -0
- data/spec/skeem/interpreter_spec.rb +126 -36
- data/spec/skeem/primitive/primitive_builder_spec.rb +48 -36
- data/spec/skeem/runtime_spec.rb +28 -2
- data/spec/skeem/s_expr_nodes_spec.rb +15 -277
- data/spec/skeem/skm_compound_datum_spec.rb +132 -0
- data/spec/skeem/skm_element_spec.rb +50 -0
- data/spec/skeem/skm_simple_datum_spec.rb +233 -0
- data/spec/skeem/skm_unary_expression_spec.rb +201 -0
- data/spec/skeem/tokenizer_spec.rb +7 -35
- metadata +21 -3
- data/lib/skeem/convertible.rb +0 -23
data/lib/skeem/s_expr_nodes.rb
CHANGED
@@ -1,309 +1,44 @@
|
|
1
1
|
# Classes that implement nodes of Abstract Syntax Trees (AST) representing
|
2
2
|
# Skeem parse results.
|
3
3
|
|
4
|
-
|
4
|
+
require_relative 'skm_simple_datum'
|
5
|
+
require_relative 'skm_compound_datum'
|
6
|
+
require_relative 'skm_unary_expression'
|
5
7
|
|
6
8
|
module Skeem
|
7
9
|
class SkmUndefined
|
8
10
|
def value
|
9
11
|
:UNDEFINED
|
10
12
|
end
|
11
|
-
end # class
|
12
|
-
|
13
|
-
|
14
|
-
# Abstract class. Generalization of any S-expr element.
|
15
|
-
SkmElement = Struct.new(:position) do
|
16
|
-
def initialize(aPosition)
|
17
|
-
self.position = aPosition
|
18
|
-
end
|
19
|
-
|
20
|
-
def evaluate(_runtime)
|
21
|
-
raise NotImplementedError, "Missing implementation of #{self.class.name}"
|
22
|
-
end
|
23
|
-
|
24
|
-
def done!()
|
25
|
-
# Do nothing
|
26
|
-
end
|
27
|
-
|
28
|
-
def number?
|
29
|
-
false
|
30
|
-
end
|
31
|
-
|
32
|
-
def real?
|
33
|
-
false
|
34
|
-
end
|
35
|
-
|
36
|
-
def integer?
|
37
|
-
false
|
38
|
-
end
|
39
|
-
|
40
|
-
def boolean?
|
41
|
-
false
|
42
|
-
end
|
43
|
-
|
44
|
-
def string?
|
45
|
-
false
|
46
|
-
end
|
47
|
-
|
48
|
-
def symbol?
|
49
|
-
false
|
50
|
-
end
|
51
|
-
|
52
|
-
def list?
|
53
|
-
false
|
54
|
-
end
|
55
|
-
|
56
|
-
def null?
|
57
|
-
false
|
58
|
-
end
|
59
|
-
|
60
|
-
def vector?
|
61
|
-
false
|
62
|
-
end
|
63
|
-
|
64
|
-
# Abstract method.
|
65
|
-
# Part of the 'visitee' role in Visitor design pattern.
|
66
|
-
# @param _visitor[ParseTreeVisitor] the visitor
|
67
|
-
def accept(_visitor)
|
68
|
-
raise NotImplementedError
|
69
|
-
end
|
70
|
-
|
71
|
-
def inspect
|
72
|
-
raise NotImplementedError, "Missing #{self.class}#inspect method."
|
73
|
-
end
|
74
|
-
|
75
|
-
protected
|
76
|
-
|
77
|
-
def inspect_prefix
|
78
|
-
"<#{self.class.name}: "
|
79
|
-
end
|
80
|
-
|
81
|
-
def inspect_suffix
|
82
|
-
'>'
|
83
|
-
end
|
84
|
-
end # struct
|
85
|
-
|
86
|
-
# Abstract class. Root of class hierarchy needed for Interpreter
|
87
|
-
# design pattern
|
88
|
-
class SkmTerminal < SkmElement
|
89
|
-
attr_reader :token
|
90
|
-
attr_reader :value
|
91
|
-
|
92
|
-
def initialize(aToken, aPosition)
|
93
|
-
super(aPosition)
|
94
|
-
@token = aToken
|
95
|
-
init_value(aToken.lexeme)
|
96
|
-
end
|
97
|
-
|
98
|
-
def self.create(aValue)
|
99
|
-
lightweight = self.allocate
|
100
|
-
lightweight.init_value(aValue)
|
101
|
-
return lightweight
|
102
|
-
end
|
103
|
-
|
104
|
-
def symbol()
|
105
|
-
token.terminal
|
106
|
-
end
|
107
|
-
|
108
|
-
def evaluate(_runtime)
|
109
|
-
return self
|
110
|
-
end
|
111
|
-
|
112
|
-
def inspect()
|
113
|
-
inspect_prefix + value.to_s + inspect_suffix
|
114
|
-
end
|
115
|
-
|
116
|
-
def done!()
|
117
|
-
# Do nothing
|
118
|
-
end
|
119
|
-
|
120
|
-
# Part of the 'visitee' role in Visitor design pattern.
|
121
|
-
# @param aVisitor[ParseTreeVisitor] the visitor
|
122
|
-
def accept(aVisitor)
|
123
|
-
aVisitor.visit_terminal(self)
|
124
|
-
end
|
125
|
-
|
126
|
-
# This method can be overriden
|
127
|
-
def init_value(aValue)
|
128
|
-
@value = aValue
|
129
|
-
end
|
130
|
-
end # class
|
131
|
-
|
132
|
-
class SkmBoolean < SkmTerminal
|
133
|
-
def boolean?
|
134
|
-
true
|
135
|
-
end
|
136
|
-
end # class
|
137
|
-
|
138
|
-
class SkmNumber < SkmTerminal
|
139
|
-
def number?
|
140
|
-
true
|
141
|
-
end
|
142
|
-
end # class
|
143
|
-
|
144
|
-
class SkmReal < SkmNumber
|
145
|
-
def real?
|
146
|
-
true
|
147
|
-
end
|
148
|
-
end # class
|
149
|
-
|
150
|
-
class SkmInteger < SkmReal
|
151
|
-
def integer?
|
152
|
-
true
|
153
|
-
end
|
154
|
-
end # class
|
155
|
-
|
156
|
-
class SkmString < SkmTerminal
|
157
|
-
# Override
|
158
|
-
def init_value(aValue)
|
159
|
-
super(aValue.dup)
|
160
|
-
end
|
161
|
-
|
162
|
-
def string?
|
163
|
-
true
|
164
|
-
end
|
165
|
-
end # class
|
166
|
-
|
167
|
-
class SkmIdentifier < SkmTerminal
|
168
|
-
# Override
|
169
|
-
def init_value(aValue)
|
170
|
-
super(aValue.dup)
|
171
|
-
end
|
172
|
-
|
173
|
-
def symbol?
|
174
|
-
true
|
175
|
-
end
|
176
|
-
end # class
|
177
|
-
|
178
|
-
class SkmReserved < SkmIdentifier
|
179
|
-
end # class
|
180
|
-
|
181
|
-
|
182
|
-
class SkmList < SkmElement
|
183
|
-
attr_accessor(:members)
|
184
|
-
extend Forwardable
|
185
|
-
|
186
|
-
def_delegators :@members, :each, :first, :last, :length, :empty?, :size
|
187
|
-
|
188
|
-
def initialize(theMembers)
|
189
|
-
super(nil)
|
190
|
-
@members = theMembers.nil? ? [] : theMembers
|
191
|
-
end
|
192
|
-
|
193
|
-
def head()
|
194
|
-
return members.first
|
195
|
-
end
|
196
|
-
|
197
|
-
def tail()
|
198
|
-
SkmList.new(members.slice(1..-1))
|
199
|
-
end
|
200
|
-
|
201
|
-
def list?
|
202
|
-
true
|
203
|
-
end
|
204
13
|
|
205
|
-
def
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
# Construct an Enumerator that will return iteratively the result
|
216
|
-
# of 'evaluate' method of each members of self.
|
217
|
-
def to_eval_enum(aRuntime)
|
218
|
-
=begin
|
219
|
-
elements = self.members
|
220
|
-
|
221
|
-
new_enum = Enumerator.new do |result|
|
222
|
-
context = aRuntime
|
223
|
-
elements.each { |elem| result << elem.evaluate(context) }
|
14
|
+
def ==(other)
|
15
|
+
return true if other.kind_of?(SkmUndefined)
|
16
|
+
|
17
|
+
result = case other
|
18
|
+
when Symbol
|
19
|
+
self.value == other
|
20
|
+
when String
|
21
|
+
self.value.to_s == other
|
22
|
+
else
|
23
|
+
raise StandardError, other.inspect
|
224
24
|
end
|
225
|
-
|
226
|
-
new_enum
|
227
|
-
=end
|
228
|
-
members.map { |elem| elem.evaluate(aRuntime) }
|
229
|
-
end
|
230
|
-
|
231
|
-
# Part of the 'visitee' role in Visitor design pattern.
|
232
|
-
# @param aVisitor[ParseTreeVisitor] the visitor
|
233
|
-
def accept(aVisitor)
|
234
|
-
aVisitor.visit_nonterminal(self)
|
235
|
-
end
|
236
|
-
|
237
|
-
def done!()
|
238
|
-
# Do nothing
|
239
|
-
end
|
240
|
-
|
241
|
-
def inspect()
|
242
|
-
result = inspect_prefix
|
243
|
-
members.each { |elem| result << elem.inspect + ', ' }
|
244
|
-
result.sub!(/, $/, '')
|
245
|
-
result << inspect_suffix
|
246
|
-
result
|
247
|
-
end
|
248
|
-
|
249
|
-
alias children members
|
250
|
-
alias subnodes members
|
251
|
-
alias to_a members
|
252
|
-
alias rest tail
|
253
|
-
end # class
|
254
|
-
|
255
|
-
class SkmVector < SkmElement
|
256
|
-
attr_accessor(:elements)
|
257
|
-
extend Forwardable
|
258
|
-
|
259
|
-
def_delegators :@elements, :each, :length, :empty?, :size
|
260
|
-
|
261
|
-
def initialize(theElements)
|
262
|
-
super(nil)
|
263
|
-
@elements = theElements.nil? ? [] : theElements
|
264
|
-
end
|
265
|
-
|
266
|
-
def vector?
|
267
|
-
true
|
268
|
-
end
|
269
|
-
|
270
|
-
def evaluate(aRuntime)
|
271
|
-
elements_evaluated = elements.map { |elem| elem.evaluate(aRuntime) }
|
272
|
-
SkmVector.new(elements_evaluated)
|
273
25
|
end
|
274
|
-
|
275
|
-
def inspect()
|
276
|
-
result = inspect_prefix
|
277
|
-
elements.each { |elem| result << elem.inspect + ', ' }
|
278
|
-
result.sub!(/, $/, '')
|
279
|
-
result << inspect_suffix
|
280
|
-
result
|
281
|
-
end
|
282
|
-
|
283
26
|
end # class
|
284
27
|
|
285
|
-
|
286
|
-
|
287
|
-
|
288
|
-
|
289
|
-
|
290
|
-
super(nil)
|
291
|
-
@datum = aDatum
|
292
|
-
end
|
293
|
-
|
294
|
-
def evaluate(aRuntime)
|
295
|
-
datum
|
28
|
+
class SkmMultiExpression < SkmExpression
|
29
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
30
|
+
# @param _visitor [SkmElementVisitor] the visitor
|
31
|
+
def accept(aVisitor)
|
32
|
+
aVisitor.visit_multi_expression(self)
|
296
33
|
end
|
297
34
|
|
298
|
-
|
299
|
-
|
300
|
-
|
301
|
-
result << inspect_suffix
|
302
|
-
result
|
35
|
+
# @return [Array] the names of attributes referencing child SkmElement.
|
36
|
+
def associations
|
37
|
+
raise NotImplementedError
|
303
38
|
end
|
304
|
-
end
|
39
|
+
end
|
305
40
|
|
306
|
-
class SkmDefinition <
|
41
|
+
class SkmDefinition < SkmMultiExpression
|
307
42
|
attr_reader :variable
|
308
43
|
attr_reader :expression
|
309
44
|
|
@@ -339,6 +74,17 @@ module Skeem
|
|
339
74
|
|
340
75
|
result
|
341
76
|
end
|
77
|
+
|
78
|
+
def quasiquote(aRuntime)
|
79
|
+
quasi_var = variable.quasiquote(aRuntime)
|
80
|
+
quasi_expression = variable.quasiquote(aRuntime)
|
81
|
+
|
82
|
+
if quasi_var.equal?(variable) && quasi_expression.equal?(expression)
|
83
|
+
self
|
84
|
+
else
|
85
|
+
self.class.new(position, quasi_var, quasi_expression)
|
86
|
+
end
|
87
|
+
end
|
342
88
|
|
343
89
|
# call method should only invoked when the expression is a SkmLambda
|
344
90
|
def call(aRuntime, aProcedureCall)
|
@@ -357,41 +103,13 @@ module Skeem
|
|
357
103
|
result << inspect_suffix
|
358
104
|
result
|
359
105
|
end
|
360
|
-
|
361
|
-
|
362
|
-
|
363
|
-
attr_reader :variable
|
364
|
-
|
365
|
-
def initialize(aPosition, aVariable)
|
366
|
-
super(aPosition)
|
367
|
-
@variable = aVariable
|
368
|
-
end
|
369
|
-
|
370
|
-
def evaluate(aRuntime)
|
371
|
-
var_key = variable.evaluate(aRuntime)
|
372
|
-
unless aRuntime.include?(var_key.value)
|
373
|
-
err = StandardError
|
374
|
-
key = var_key.kind_of?(SkmIdentifier) ? var_key.value : var_key
|
375
|
-
err_msg = "Unbound variable: '#{key}'"
|
376
|
-
raise err, err_msg
|
377
|
-
end
|
378
|
-
definition = aRuntime.environment.fetch(var_key.value)
|
379
|
-
result = definition.expression.evaluate(aRuntime)
|
380
|
-
end
|
381
|
-
|
382
|
-
# Confusing!
|
383
|
-
# Value, here, means the value of the identifier (the variable's name).
|
384
|
-
def value()
|
385
|
-
variable.value
|
386
|
-
end
|
387
|
-
|
388
|
-
def inspect
|
389
|
-
result = inspect_prefix + variable.inspect + inspect_suffix
|
390
|
-
result
|
106
|
+
|
107
|
+
def associations
|
108
|
+
[:variable, :expression]
|
391
109
|
end
|
392
110
|
end # class
|
393
111
|
|
394
|
-
class ProcedureCall <
|
112
|
+
class ProcedureCall < SkmMultiExpression
|
395
113
|
attr_reader :operator
|
396
114
|
attr_reader :operands
|
397
115
|
|
@@ -425,17 +143,28 @@ module Skeem
|
|
425
143
|
# $stderr.puts "## RETURN #{result.inspect}"
|
426
144
|
result
|
427
145
|
end
|
146
|
+
|
147
|
+
def quasiquote(aRuntime)
|
148
|
+
quasi_operator = operator.quasiquote(aRuntime)
|
149
|
+
quasi_operands = operands.map { |oper | oper.quasiquote(aRuntime) }
|
150
|
+
|
151
|
+
self.class.new(position, quasi_operator, quasi_operands)
|
152
|
+
end
|
428
153
|
|
429
154
|
def inspect
|
430
155
|
result = inspect_prefix + operator.inspect + ', '
|
431
156
|
result << '@operands ' + operands.inspect + inspect_suffix
|
432
157
|
result
|
433
158
|
end
|
159
|
+
|
160
|
+
def associations
|
161
|
+
[:operator, :operands]
|
162
|
+
end
|
434
163
|
|
435
164
|
alias children operands
|
436
165
|
end # class
|
437
166
|
|
438
|
-
class SkmCondition <
|
167
|
+
class SkmCondition < SkmMultiExpression
|
439
168
|
attr_reader :test
|
440
169
|
attr_reader :consequent
|
441
170
|
attr_reader :alternate
|
@@ -457,6 +186,14 @@ module Skeem
|
|
457
186
|
condition_result = consequent.evaluate(aRuntime)
|
458
187
|
end
|
459
188
|
end
|
189
|
+
|
190
|
+
def quasiquote(aRuntime)
|
191
|
+
quasi_test = test.quasiquote(aRuntime)
|
192
|
+
quasi_consequent = consequent.quasiquote(aRuntime)
|
193
|
+
quasi_alternate = alternate.quasiquote(aRuntime)
|
194
|
+
|
195
|
+
self.class.new(position, quasi_test, quasi_consequent, quasi_alternate)
|
196
|
+
end
|
460
197
|
|
461
198
|
def inspect
|
462
199
|
result = inspect_prefix + '@test ' + test.inspect + ', '
|
@@ -464,6 +201,10 @@ module Skeem
|
|
464
201
|
result << '@alternate ' + alternate.inspect + inspect_suffix
|
465
202
|
result
|
466
203
|
end
|
204
|
+
|
205
|
+
def associations
|
206
|
+
[:test, :consequent, :alternate]
|
207
|
+
end
|
467
208
|
end # class
|
468
209
|
|
469
210
|
SkmArity = Struct.new(:low, :high) do
|
@@ -535,7 +276,7 @@ module Skeem
|
|
535
276
|
end
|
536
277
|
end # class
|
537
278
|
|
538
|
-
class SkmLambda <
|
279
|
+
class SkmLambda < SkmMultiExpression
|
539
280
|
# @!attribute [r] formals
|
540
281
|
# @return [Array<SkmIdentifier>] the argument names
|
541
282
|
attr_reader :formals
|
@@ -552,7 +293,16 @@ module Skeem
|
|
552
293
|
def evaluate(aRuntime)
|
553
294
|
formals.evaluate(aRuntime)
|
554
295
|
end
|
555
|
-
|
296
|
+
=begin
|
297
|
+
TODO
|
298
|
+
def quasiquote(aRuntime)
|
299
|
+
quasi_test = test.quasiquote(aRuntime)
|
300
|
+
quasi_consequent = consequent.quasiquote(aRuntime)
|
301
|
+
quasi_alternate = alternate.quasiquote(aRuntime)
|
302
|
+
|
303
|
+
self.class.new(position, quasi_test, quasi_consequent, quasi_alternate)
|
304
|
+
end
|
305
|
+
=end
|
556
306
|
def call(aRuntime, aProcedureCall)
|
557
307
|
aRuntime.nest
|
558
308
|
bind_locals(aRuntime, aProcedureCall)
|
@@ -579,13 +329,17 @@ module Skeem
|
|
579
329
|
result << '@sequence ' + sequence.inspect + inspect_suffix
|
580
330
|
result
|
581
331
|
end
|
332
|
+
|
333
|
+
def associations
|
334
|
+
[:formals, :definitions, :sequence]
|
335
|
+
end
|
582
336
|
|
583
337
|
private
|
584
338
|
|
585
339
|
def bind_locals(aRuntime, aProcedureCall)
|
586
340
|
actuals = aProcedureCall.operands.members
|
587
341
|
count_actuals = actuals.size
|
588
|
-
|
342
|
+
|
589
343
|
if (count_actuals < required_arity) ||
|
590
344
|
((count_actuals > required_arity) && !formals.variadic?)
|
591
345
|
raise StandardError, msg_arity_mismatch(aProcedureCall)
|
@@ -596,7 +350,7 @@ module Skeem
|
|
596
350
|
variadic_part_raw = actuals.drop(required_arity)
|
597
351
|
variadic_part = variadic_part_raw.map do |actual|
|
598
352
|
if actual.kind_of?(ProcedureCall)
|
599
|
-
actual.evaluate(aRuntime)
|
353
|
+
actual.evaluate(aRuntime)
|
600
354
|
else
|
601
355
|
actual
|
602
356
|
end
|
@@ -604,7 +358,7 @@ module Skeem
|
|
604
358
|
variadic_arg_name = formals.formals.last
|
605
359
|
args_coll = SkmList.new(variadic_part)
|
606
360
|
a_def = SkmDefinition.new(position, variadic_arg_name, args_coll)
|
607
|
-
a_def.evaluate(aRuntime)
|
361
|
+
a_def.evaluate(aRuntime)
|
608
362
|
end
|
609
363
|
end
|
610
364
|
|
@@ -643,7 +397,7 @@ module Skeem
|
|
643
397
|
break if index >= max_index
|
644
398
|
end
|
645
399
|
end
|
646
|
-
|
400
|
+
|
647
401
|
def msg_arity_mismatch(aProcedureCall)
|
648
402
|
# *** ERROR: wrong number of arguments for #<closure morph> (required 2, got 1)
|
649
403
|
msg1 = "Wrong number of arguments for procedure #{operator} "
|
@@ -0,0 +1,118 @@
|
|
1
|
+
require 'forwardable'
|
2
|
+
require_relative 'skm_element'
|
3
|
+
|
4
|
+
module Skeem
|
5
|
+
# Abstract class.
|
6
|
+
class SkmCompoundDatum < SkmElement
|
7
|
+
extend Forwardable
|
8
|
+
|
9
|
+
attr_accessor(:members)
|
10
|
+
alias children members
|
11
|
+
|
12
|
+
def_delegators :@members, :each, :first, :last, :length, :empty?, :size
|
13
|
+
alias to_a members
|
14
|
+
|
15
|
+
def initialize(theMembers)
|
16
|
+
super(nil)
|
17
|
+
@members = theMembers.nil? ? [] : theMembers
|
18
|
+
end
|
19
|
+
|
20
|
+
def ==(other)
|
21
|
+
return true if self.equal?(other)
|
22
|
+
result = case other
|
23
|
+
when SkmCompoundDatum
|
24
|
+
self.class == other.class && self.members == other.members
|
25
|
+
when Array
|
26
|
+
members == other
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
def evaluate(aRuntime)
|
31
|
+
members_eval = members.map { |elem| elem.evaluate(aRuntime) }
|
32
|
+
self.class.new(members_eval)
|
33
|
+
end
|
34
|
+
|
35
|
+
# Return this object un-evaluated.
|
36
|
+
# Reminder: As terminals are atomic, there is no need to launch a visitor.
|
37
|
+
# @param aRuntime [Skeem::Runtime]
|
38
|
+
def quasiquote(aRuntime)
|
39
|
+
quasi_members = members.map { |elem| elem.quasiquote(aRuntime) }
|
40
|
+
self.class.new(quasi_members)
|
41
|
+
end
|
42
|
+
|
43
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
44
|
+
# @param aVisitor [SkmElementVisitor] the visitor
|
45
|
+
def accept(aVisitor)
|
46
|
+
aVisitor.visit_compound_datum(self)
|
47
|
+
end
|
48
|
+
|
49
|
+
protected
|
50
|
+
|
51
|
+
def inspect_specific
|
52
|
+
result = ''
|
53
|
+
members.each { |elem| result << elem.inspect + ', ' }
|
54
|
+
result.sub!(/, $/, '')
|
55
|
+
result
|
56
|
+
end
|
57
|
+
end # class
|
58
|
+
|
59
|
+
class SkmList < SkmCompoundDatum
|
60
|
+
def tail()
|
61
|
+
SkmList.new(members.slice(1..-1))
|
62
|
+
end
|
63
|
+
|
64
|
+
def list?
|
65
|
+
true
|
66
|
+
end
|
67
|
+
|
68
|
+
def null?
|
69
|
+
empty?
|
70
|
+
end
|
71
|
+
|
72
|
+
def evaluate(aRuntime)
|
73
|
+
if empty?
|
74
|
+
self.class.new(nil)
|
75
|
+
else
|
76
|
+
first_evaluated = members.first.evaluate(aRuntime)
|
77
|
+
|
78
|
+
if first_evaluated.kind_of?(SkmIdentifier)
|
79
|
+
aRuntime.evaluate_form(self)
|
80
|
+
else
|
81
|
+
members_eval = members.map { |elem| elem.evaluate(aRuntime) }
|
82
|
+
self.class.new(members_eval)
|
83
|
+
end
|
84
|
+
end
|
85
|
+
end
|
86
|
+
|
87
|
+
|
88
|
+
# Factory method.
|
89
|
+
# Construct an Enumerator that will return iteratively the result
|
90
|
+
# of 'evaluate' method of each members of self.
|
91
|
+
def to_eval_enum(aRuntime)
|
92
|
+
=begin
|
93
|
+
elements = self.members
|
94
|
+
|
95
|
+
new_enum = Enumerator.new do |result|
|
96
|
+
context = aRuntime
|
97
|
+
elements.each { |elem| result << elem.evaluate(context) }
|
98
|
+
end
|
99
|
+
|
100
|
+
new_enum
|
101
|
+
=end
|
102
|
+
members.map { |elem| elem.evaluate(aRuntime) }
|
103
|
+
end
|
104
|
+
|
105
|
+
def done!()
|
106
|
+
# Do nothing
|
107
|
+
end
|
108
|
+
|
109
|
+
alias head first
|
110
|
+
alias rest tail
|
111
|
+
end # class
|
112
|
+
|
113
|
+
class SkmVector < SkmCompoundDatum
|
114
|
+
def vector?
|
115
|
+
true
|
116
|
+
end
|
117
|
+
end # class
|
118
|
+
end # module
|
@@ -0,0 +1,85 @@
|
|
1
|
+
module Skeem
|
2
|
+
# Abstract class. Generalization of any S-expr element.
|
3
|
+
SkmElement = Struct.new(:position) do
|
4
|
+
def initialize(aPosition)
|
5
|
+
self.position = aPosition
|
6
|
+
end
|
7
|
+
|
8
|
+
def number?
|
9
|
+
false
|
10
|
+
end
|
11
|
+
|
12
|
+
def real?
|
13
|
+
false
|
14
|
+
end
|
15
|
+
|
16
|
+
def integer?
|
17
|
+
false
|
18
|
+
end
|
19
|
+
|
20
|
+
def boolean?
|
21
|
+
false
|
22
|
+
end
|
23
|
+
|
24
|
+
def string?
|
25
|
+
false
|
26
|
+
end
|
27
|
+
|
28
|
+
def symbol?
|
29
|
+
false
|
30
|
+
end
|
31
|
+
|
32
|
+
def list?
|
33
|
+
false
|
34
|
+
end
|
35
|
+
|
36
|
+
def null?
|
37
|
+
false
|
38
|
+
end
|
39
|
+
|
40
|
+
def vector?
|
41
|
+
false
|
42
|
+
end
|
43
|
+
|
44
|
+
def evaluate(_runtime)
|
45
|
+
raise NotImplementedError, "Missing implementation of #{self.class.name}"
|
46
|
+
end
|
47
|
+
|
48
|
+
def quasiquote(_runtime)
|
49
|
+
raise NotImplementedError, "Missing implementation of #{self.class.name}"
|
50
|
+
end
|
51
|
+
|
52
|
+
# Abstract method.
|
53
|
+
# Part of the 'visitee' role in Visitor design pattern.
|
54
|
+
# @param _visitor [SkmElementVisitor] the visitor
|
55
|
+
def accept(_visitor)
|
56
|
+
raise NotImplementedError
|
57
|
+
end
|
58
|
+
|
59
|
+
def done!()
|
60
|
+
# Do nothing
|
61
|
+
end
|
62
|
+
|
63
|
+
def inspect
|
64
|
+
result = inspect_prefix
|
65
|
+
result << inspect_specific
|
66
|
+
result << inspect_suffix
|
67
|
+
|
68
|
+
result
|
69
|
+
end
|
70
|
+
|
71
|
+
protected
|
72
|
+
|
73
|
+
def inspect_prefix
|
74
|
+
"<#{self.class.name}: "
|
75
|
+
end
|
76
|
+
|
77
|
+
def inspect_suffix
|
78
|
+
'>'
|
79
|
+
end
|
80
|
+
|
81
|
+
def inspect_specific
|
82
|
+
raise NotImplementedError
|
83
|
+
end
|
84
|
+
end # struct
|
85
|
+
end # module
|