skeem 0.0.23 → 0.0.24

Sign up to get free protection for your applications and to get access to all the features.
@@ -1,309 +1,44 @@
1
1
  # Classes that implement nodes of Abstract Syntax Trees (AST) representing
2
2
  # Skeem parse results.
3
3
 
4
- require 'forwardable'
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 null?
206
- empty?
207
- end
208
-
209
- def evaluate(aRuntime)
210
- list_evaluated = members.map { |elem| elem.evaluate(aRuntime) }
211
- SkmList.new(list_evaluated)
212
- end
213
-
214
- # Factory method.
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
- class SkmQuotation < SkmElement
287
- attr_accessor(:datum)
288
-
289
- def initialize(aDatum)
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
- def inspect
299
- result = inspect_prefix
300
- result << datum.inspect
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 # class
39
+ end
305
40
 
306
- class SkmDefinition < SkmElement
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
- end # class
361
-
362
- class SkmVariableReference < SkmElement
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 < SkmElement
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 < SkmElement
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 < SkmElement
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