pione 0.1.1 → 0.1.2
Sign up to get free protection for your applications and to get access to all the features.
- data/History.txt +9 -2
- data/Rakefile +1 -1
- data/example/Fib/Fib.pione +5 -5
- data/example/SequentialProcess/SequentialProcess.pione +69 -0
- data/lib/pione.rb +7 -11
- data/lib/pione/agent/input-generator.rb +3 -2
- data/lib/pione/agent/task-worker.rb +6 -3
- data/lib/pione/agent/trivial-routine-worker.rb +6 -5
- data/lib/pione/command/basic-command.rb +7 -1
- data/lib/pione/command/child-process.rb +5 -1
- data/lib/pione/command/front-owner-command.rb +15 -4
- data/lib/pione/command/pione-client.rb +16 -9
- data/lib/pione/command/pione-syntax-checker.rb +45 -30
- data/lib/pione/command/pione-task-worker.rb +22 -13
- data/lib/pione/command/pione-tuple-space-provider.rb +4 -2
- data/lib/pione/command/pione-tuple-space-receiver.rb +10 -5
- data/lib/pione/front/task-worker-owner.rb +1 -0
- data/lib/pione/model/basic-model.rb +3 -0
- data/lib/pione/model/block.rb +2 -1
- data/lib/pione/model/call-rule.rb +10 -0
- data/lib/pione/model/feature-expr.rb +143 -54
- data/lib/pione/model/float.rb +0 -1
- data/lib/pione/model/rule-expr.rb +132 -7
- data/lib/pione/model/rule.rb +53 -17
- data/lib/pione/model/ticket-expr.rb +124 -0
- data/lib/pione/parser/expr-parser.rb +75 -38
- data/lib/pione/parser/literal-parser.rb +14 -0
- data/lib/pione/parser/parslet-extension.rb +143 -0
- data/lib/pione/rule-handler/flow-handler.rb +33 -3
- data/lib/pione/system/global.rb +10 -3
- data/lib/pione/transformer.rb +24 -0
- data/lib/pione/transformer/block-transformer.rb +6 -5
- data/lib/pione/transformer/document-transformer.rb +5 -10
- data/lib/pione/transformer/expr-transformer.rb +56 -30
- data/lib/pione/transformer/feature-expr-transformer.rb +9 -5
- data/lib/pione/transformer/flow-element-transformer.rb +21 -23
- data/lib/pione/transformer/literal-transformer.rb +39 -35
- data/lib/pione/transformer/rule-definition-transformer.rb +8 -6
- data/lib/pione/transformer/transformer-module.rb +7 -5
- data/lib/pione/tuple/ticket-tuple.rb +8 -0
- data/lib/pione/util/{message.rb → console-message.rb} +54 -26
- data/lib/pione/version.rb +1 -1
- data/pione.gemspec +2 -1
- data/test/model/spec_feature-expr.rb +18 -3
- data/test/model/spec_feature-expr.yml +28 -16
- data/test/model/spec_ticket-expr.rb +67 -0
- data/test/parser/spec_expr-parser.yml +74 -25
- data/test/parser/spec_literal-parser.yml +11 -0
- data/test/test-util.rb +1 -1
- data/test/transformer/spec_expr-transformer.rb +27 -54
- data/test/transformer/spec_literal-transformer.rb +6 -0
- metadata +29 -7
- data/lib/pione/parser/syntax-error.rb +0 -61
@@ -102,24 +102,33 @@ TXT
|
|
102
102
|
end
|
103
103
|
end
|
104
104
|
|
105
|
+
# Terminate the task worker. Kill the agent and disconnect from parent
|
106
|
+
# front.
|
107
|
+
#
|
108
|
+
# @return [void]
|
105
109
|
def terminate
|
106
|
-
|
107
|
-
|
110
|
+
Global.monitor.synchronize do
|
111
|
+
begin
|
112
|
+
return if @terminated
|
113
|
+
@agent.terminate
|
108
114
|
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
115
|
+
while true
|
116
|
+
break if @agent.terminated? and @agent.running_thread.stop?
|
117
|
+
sleep 1
|
118
|
+
end
|
113
119
|
|
114
|
-
|
115
|
-
|
120
|
+
# disconnect parent front
|
121
|
+
@parent_front.remove_task_worker_front(self, @connection_id)
|
116
122
|
|
117
|
-
|
118
|
-
|
123
|
+
# flag
|
124
|
+
@terminated = true
|
119
125
|
|
120
|
-
|
121
|
-
|
122
|
-
|
126
|
+
super
|
127
|
+
rescue DRb::DRbConnError, DRb::ReplyReaderThreadError
|
128
|
+
# ignore
|
129
|
+
end
|
130
|
+
super
|
131
|
+
end
|
123
132
|
end
|
124
133
|
end
|
125
134
|
end
|
@@ -42,13 +42,18 @@ TXT
|
|
42
42
|
# ignore reply reader error
|
43
43
|
end
|
44
44
|
|
45
|
+
# Terminate the tuple space recevier.
|
46
|
+
#
|
47
|
+
# @return [void]
|
45
48
|
def terminate
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
49
|
+
Global.monitor.synchronize do
|
50
|
+
begin
|
51
|
+
@tuple_space_receiver.terminate
|
52
|
+
rescue DRb::DRbConnError
|
53
|
+
# ignore
|
54
|
+
end
|
55
|
+
super
|
50
56
|
end
|
51
|
-
super
|
52
57
|
end
|
53
58
|
end
|
54
59
|
end
|
@@ -251,6 +251,9 @@ module Pione
|
|
251
251
|
# rule io element type for PIONE system
|
252
252
|
TypeRuleIOElement = Type.new("rule-io-element")
|
253
253
|
|
254
|
+
# ticket expression type
|
255
|
+
TypeTicketExpr = Type.new("ticket-expr")
|
256
|
+
|
254
257
|
# any type for PIONE system
|
255
258
|
TypeAny = Type.new("any")
|
256
259
|
|
data/lib/pione/model/block.rb
CHANGED
@@ -49,6 +49,16 @@ module Pione::Model
|
|
49
49
|
self.class.new(@expr.eval(vtable))
|
50
50
|
end
|
51
51
|
|
52
|
+
# Return a set of call-rules that the rule expression are expanded.
|
53
|
+
#
|
54
|
+
# @return [Set<CallRule>]
|
55
|
+
# a set of call-rules
|
56
|
+
def to_set
|
57
|
+
@expr.to_set.map do |expr|
|
58
|
+
self.class.new(expr)
|
59
|
+
end
|
60
|
+
end
|
61
|
+
|
52
62
|
# @api private
|
53
63
|
def textize
|
54
64
|
"call_rule(%s)" % [@expr.textize]
|
@@ -4,32 +4,46 @@ module Pione::Model
|
|
4
4
|
# Feature is selection system between task and task worker.
|
5
5
|
module Feature
|
6
6
|
class << self
|
7
|
-
#
|
8
|
-
#
|
7
|
+
# Return feature conjunction.
|
8
|
+
#
|
9
|
+
# @param exprs [Array<Expr>]
|
9
10
|
# feature expression list
|
10
11
|
# @return [Expr]
|
11
12
|
# conjuncted expression
|
13
|
+
#
|
14
|
+
# @example
|
15
|
+
# x = RequisiteExpr.new("X")
|
16
|
+
# y = RequisiteExpr.new("Y")
|
17
|
+
# Feature.and(x, y) #=> +X & +Y
|
12
18
|
def and(*exprs)
|
13
19
|
AndExpr.new(*exprs)
|
14
20
|
end
|
15
21
|
|
16
|
-
#
|
17
|
-
#
|
22
|
+
# Return feature disjunction.
|
23
|
+
#
|
24
|
+
# @param exprs [Array<Expr>]
|
18
25
|
# feature expression list
|
19
26
|
# @return [Expr]
|
20
27
|
# disjuncted expression
|
28
|
+
#
|
29
|
+
# @example
|
30
|
+
# x = RequisiteExpr.new("X")
|
31
|
+
# y = RequisiteExpr.new("Y")
|
32
|
+
# Feature.or(x, y) #=> +X | +Y
|
21
33
|
def or(*exprs)
|
22
34
|
OrExpr.new(*exprs)
|
23
35
|
end
|
24
36
|
|
25
|
-
#
|
37
|
+
# Return empty feature.
|
38
|
+
#
|
26
39
|
# @return [Expr]
|
27
40
|
# empty feature
|
28
41
|
def empty
|
29
42
|
empty ||= EmptyFeature.new
|
30
43
|
end
|
31
44
|
|
32
|
-
#
|
45
|
+
# Return boundless feature.
|
46
|
+
#
|
33
47
|
# @return [Expr]
|
34
48
|
# boundless feature
|
35
49
|
def boundless
|
@@ -41,28 +55,30 @@ module Pione::Model
|
|
41
55
|
class Expr < BasicModel
|
42
56
|
set_pione_model_type TypeFeature
|
43
57
|
|
44
|
-
#
|
58
|
+
# Return simplified expression.
|
59
|
+
#
|
45
60
|
# @return [Expr]
|
46
|
-
#
|
61
|
+
# simplified expression
|
47
62
|
def simplify
|
48
63
|
return self
|
49
64
|
end
|
50
65
|
|
51
|
-
#
|
66
|
+
# Return true if the feature is empty.
|
67
|
+
#
|
52
68
|
# @return [Boolean]
|
53
|
-
#
|
69
|
+
# true if the feature is empty
|
54
70
|
def empty?
|
55
71
|
return false
|
56
72
|
end
|
57
73
|
|
58
|
-
#
|
74
|
+
# Return true if the other matches the feature.
|
75
|
+
#
|
59
76
|
# @return [Boolean]
|
60
77
|
# true if the other matches the feature
|
61
78
|
def match(other)
|
62
79
|
raise ArgumentError.new(other) unless other.kind_of?(Expr)
|
63
80
|
Sentence.new(self, other).decide
|
64
81
|
end
|
65
|
-
|
66
82
|
alias :=== :match
|
67
83
|
end
|
68
84
|
|
@@ -75,14 +91,13 @@ module Pione::Model
|
|
75
91
|
|
76
92
|
# @api private
|
77
93
|
def textize
|
78
|
-
|
94
|
+
symbol
|
79
95
|
end
|
80
96
|
|
81
97
|
# @api private
|
82
98
|
def ==(other)
|
83
99
|
other.kind_of?(self.class)
|
84
|
-
|
85
|
-
|
100
|
+
end
|
86
101
|
alias :eql? :==
|
87
102
|
|
88
103
|
# @api private
|
@@ -96,14 +111,16 @@ module Pione::Model
|
|
96
111
|
# ability in provider expression and the task has no specific request in
|
97
112
|
# request expression.
|
98
113
|
class EmptyFeature < SpecialFeature
|
99
|
-
#
|
100
|
-
#
|
114
|
+
# Return the symbol of empty feature.
|
115
|
+
#
|
116
|
+
# return [String]
|
101
117
|
# "*"
|
102
118
|
def symbol
|
103
119
|
"*"
|
104
120
|
end
|
105
121
|
|
106
|
-
#
|
122
|
+
# Return true because empty feature is empty.
|
123
|
+
#
|
107
124
|
# @return [Boolean]
|
108
125
|
# true
|
109
126
|
def empty?
|
@@ -122,9 +139,18 @@ module Pione::Model
|
|
122
139
|
# ability in provider expression and the task has boundless ability request
|
123
140
|
# in request expression.
|
124
141
|
class BoundlessFeature < SpecialFeature
|
142
|
+
# Return the symbol of bundless feature.
|
143
|
+
#
|
144
|
+
# return [String]
|
145
|
+
# "@"
|
125
146
|
def symbol
|
126
147
|
"@"
|
127
148
|
end
|
149
|
+
|
150
|
+
# @api private
|
151
|
+
def ==(other)
|
152
|
+
other.kind_of?(BoundlessFeature)
|
153
|
+
end
|
128
154
|
end
|
129
155
|
|
130
156
|
# Operator is superclass of all operator classes.
|
@@ -134,7 +160,8 @@ module Pione::Model
|
|
134
160
|
class UnaryOperator < Operator
|
135
161
|
attr_reader :symbol
|
136
162
|
|
137
|
-
#
|
163
|
+
# Return the operator symbol.
|
164
|
+
#
|
138
165
|
# @return [String]
|
139
166
|
# operator symbol
|
140
167
|
# @example
|
@@ -156,7 +183,8 @@ module Pione::Model
|
|
156
183
|
@operator
|
157
184
|
end
|
158
185
|
|
159
|
-
#
|
186
|
+
# Create a new operator.
|
187
|
+
#
|
160
188
|
# @param [Symbol] symbol
|
161
189
|
# feature symbol
|
162
190
|
def initialize(symbol)
|
@@ -183,7 +211,6 @@ module Pione::Model
|
|
183
211
|
def ==(other)
|
184
212
|
other.kind_of?(self.class) and @symbol == other.symbol
|
185
213
|
end
|
186
|
-
|
187
214
|
alias :eql? :==
|
188
215
|
|
189
216
|
# @api private
|
@@ -203,6 +230,7 @@ module Pione::Model
|
|
203
230
|
end
|
204
231
|
|
205
232
|
# RestrictiveExpr is a class for restrictive feature expression.
|
233
|
+
#
|
206
234
|
# @example
|
207
235
|
# !X
|
208
236
|
class RestrictiveExpr < ProviderExpr
|
@@ -215,6 +243,7 @@ module Pione::Model
|
|
215
243
|
# Requisite Operator is a class for requisite feature expressions. Requisite
|
216
244
|
# Feature are written like as "+X", these represent feature's requiste
|
217
245
|
# ability.
|
246
|
+
#
|
218
247
|
# @example
|
219
248
|
# +X
|
220
249
|
class RequisiteExpr < RequestExpr
|
@@ -224,8 +253,9 @@ module Pione::Model
|
|
224
253
|
# BlockingExpr is a class for blocking feature expressions. Blocking Feature
|
225
254
|
# are written like as "-X", these represent the ability that block to
|
226
255
|
# execute the task.
|
256
|
+
#
|
227
257
|
# @example
|
228
|
-
# -X
|
258
|
+
# BlockingExpr.new("X") #=> -X
|
229
259
|
class BlockingExpr < RequestExpr
|
230
260
|
@operator = "-"
|
231
261
|
end
|
@@ -233,38 +263,55 @@ module Pione::Model
|
|
233
263
|
# PreferredExpr is a class for preferred feature expressions. Preferred
|
234
264
|
# Feature are written like as "?X", these represent that task workers what
|
235
265
|
# the feature have take the task.
|
266
|
+
#
|
267
|
+
# @example
|
268
|
+
# PreferredExpr.new("X") #=> ?X
|
236
269
|
class PreferredExpr < RequestExpr
|
237
270
|
@operator = "?"
|
238
271
|
end
|
239
272
|
|
240
273
|
# Connective is a superclass of AndExpr and OrExpr. This represents
|
241
|
-
# connection of
|
274
|
+
# connection of feature expressions.
|
242
275
|
class Connective < Expr
|
276
|
+
# @return [Set]
|
277
|
+
# feature expressions included in the connective
|
243
278
|
attr_reader :elements
|
244
279
|
|
245
|
-
#
|
246
|
-
#
|
247
|
-
#
|
280
|
+
# Create a new connective.
|
281
|
+
#
|
282
|
+
# @param elements [Array<Expr>]
|
283
|
+
# feature expressions
|
248
284
|
def initialize(*elements)
|
249
285
|
@elements = Set.new
|
250
286
|
elements.each {|elt| add(elt) }
|
251
287
|
super()
|
252
288
|
end
|
253
289
|
|
254
|
-
#
|
255
|
-
#
|
290
|
+
# Add the feature expression as elements of the connective and unify it.
|
291
|
+
#
|
292
|
+
# @param expr [Expr]
|
256
293
|
# feature element
|
257
294
|
# @return [void]
|
258
|
-
|
259
|
-
|
260
|
-
|
295
|
+
#
|
296
|
+
# @example AND expression
|
297
|
+
# x = RequisiteExpr.new("X")
|
298
|
+
# y = RequisiteExpr.new("Y")
|
299
|
+
# AndExpr.new(x).add(y) #=> +X & +Y
|
300
|
+
# @example OR expression
|
301
|
+
# x = RequisiteExpr.new("X")
|
302
|
+
# y = RequisiteExpr.new("Y")
|
303
|
+
# OrExpr.new(x, y).add(x) #=> +X | +Y
|
304
|
+
def add(expr)
|
305
|
+
if expr.kind_of?(self.class)
|
306
|
+
expr.elements.each {|e| unify(e) }
|
261
307
|
else
|
262
|
-
unify(
|
308
|
+
unify(expr)
|
263
309
|
end
|
264
310
|
end
|
265
311
|
|
266
|
-
#
|
267
|
-
#
|
312
|
+
# Delete the element from the connective set.
|
313
|
+
#
|
314
|
+
# @param elt [Expr]
|
268
315
|
# feature element
|
269
316
|
# @return [void]
|
270
317
|
def delete(elt)
|
@@ -274,7 +321,8 @@ module Pione::Model
|
|
274
321
|
end
|
275
322
|
end
|
276
323
|
|
277
|
-
#
|
324
|
+
# Unify connective set by the element.
|
325
|
+
#
|
278
326
|
# @param [Expr] elt
|
279
327
|
# feature element
|
280
328
|
# @return [void]
|
@@ -284,9 +332,13 @@ module Pione::Model
|
|
284
332
|
end
|
285
333
|
end
|
286
334
|
|
287
|
-
#
|
335
|
+
# Simplify the connective by unifing and up-rising single element.
|
336
|
+
#
|
288
337
|
# @return [Expr]
|
289
338
|
# simplified feature
|
339
|
+
#
|
340
|
+
# @example
|
341
|
+
# AndExpr.new(RequisiteExpr.new("X")).simplify #=> +X
|
290
342
|
def simplify
|
291
343
|
if @elements.size == 1
|
292
344
|
return @elements.first.simplify
|
@@ -298,7 +350,8 @@ module Pione::Model
|
|
298
350
|
end
|
299
351
|
end
|
300
352
|
|
301
|
-
#
|
353
|
+
# Return true if the connective set is empty.
|
354
|
+
#
|
302
355
|
# @return [Boolean]
|
303
356
|
# true if the connective set is empty
|
304
357
|
def empty?
|
@@ -317,9 +370,7 @@ module Pione::Model
|
|
317
370
|
|
318
371
|
# @api private
|
319
372
|
def textize
|
320
|
-
"#{self.class.name}(%s)" %
|
321
|
-
@elements.map{|elt| elt.textize}.join(",")
|
322
|
-
]
|
373
|
+
"#{self.class.name}(%s)" % @elements.map{|elt| elt.textize}.join(",")
|
323
374
|
end
|
324
375
|
|
325
376
|
# @api private
|
@@ -327,8 +378,7 @@ module Pione::Model
|
|
327
378
|
return true if empty? and other.kind_of?(Expr) and other.empty?
|
328
379
|
other.kind_of?(self.class) and @elements == other.elements
|
329
380
|
end
|
330
|
-
|
331
|
-
alias :eql? :==
|
381
|
+
alias :eql? :"=="
|
332
382
|
|
333
383
|
# @api private
|
334
384
|
def hash
|
@@ -336,6 +386,7 @@ module Pione::Model
|
|
336
386
|
end
|
337
387
|
|
338
388
|
# Clone with cloning the elements set.
|
389
|
+
#
|
339
390
|
# @api private
|
340
391
|
def clone
|
341
392
|
obj = super
|
@@ -345,6 +396,10 @@ module Pione::Model
|
|
345
396
|
end
|
346
397
|
end
|
347
398
|
|
399
|
+
# AndExpr represents conjunction of feature expressions.
|
400
|
+
#
|
401
|
+
# @example
|
402
|
+
# AndExpr.new(RequisiteExpr.new("X"), RequisiteExpr.new("Y")) #=> +X & +Y
|
348
403
|
class AndExpr < Connective
|
349
404
|
UNIFICATIONS =
|
350
405
|
[ :unify_redundant_feature,
|
@@ -354,10 +409,21 @@ module Pione::Model
|
|
354
409
|
]
|
355
410
|
|
356
411
|
module UnificationMethod
|
357
|
-
|
358
|
-
|
359
|
-
|
360
|
-
|
412
|
+
# Unify redundant feature. This unification rule is described as
|
413
|
+
# follows:
|
414
|
+
#
|
415
|
+
# - Γ & Γ -> Γ
|
416
|
+
# - Δ & Δ -> Δ
|
417
|
+
#
|
418
|
+
# @param expr [Expr]
|
419
|
+
# feature expression
|
420
|
+
#
|
421
|
+
# @example
|
422
|
+
# x = RequisiteExpr.new("X")
|
423
|
+
# y = RequisiteExpr.new("Y")
|
424
|
+
# AndExpr.new(x,y).unify_redundant_feature(x) #=> true
|
425
|
+
def unify_redundant_feature(expr)
|
426
|
+
return @elements.include?(expr)
|
361
427
|
end
|
362
428
|
|
363
429
|
def summarize_or(elt)
|
@@ -449,7 +515,7 @@ module Pione::Model
|
|
449
515
|
|
450
516
|
include UnificationMethod
|
451
517
|
|
452
|
-
#
|
518
|
+
# Make an expander for response test.
|
453
519
|
def expander
|
454
520
|
# convert or-clause into expander
|
455
521
|
elements = @elements.map do |elt|
|
@@ -463,7 +529,7 @@ module Pione::Model
|
|
463
529
|
|
464
530
|
require 'fiber'
|
465
531
|
|
466
|
-
#
|
532
|
+
# Choose a concrete expression that expand or-clause.
|
467
533
|
def choose_concrete_expr(y, orig, list, fiber, i)
|
468
534
|
if orig.size == i
|
469
535
|
# when reach the terminateion of elements, yield a concrete expression
|
@@ -503,7 +569,12 @@ module Pione::Model
|
|
503
569
|
end
|
504
570
|
end
|
505
571
|
|
572
|
+
# OrExpr represents disjunction of feature expressions.
|
573
|
+
#
|
574
|
+
# @example
|
575
|
+
# OrExpr.new(RequisiteExpr.new("X"), RequisiteExpr.new("Y")) #=> +X | +Y
|
506
576
|
class OrExpr < Connective
|
577
|
+
# unification list
|
507
578
|
UNIFICATIONS =
|
508
579
|
[ :unify_redundant_feature,
|
509
580
|
:summarize_and,
|
@@ -512,19 +583,37 @@ module Pione::Model
|
|
512
583
|
:neutralize
|
513
584
|
]
|
514
585
|
|
586
|
+
# OrExpr's unification methods.
|
515
587
|
module UnificationMethod
|
516
|
-
|
517
|
-
|
518
|
-
|
519
|
-
|
588
|
+
# Return true if elements include the feature. This unification rule is
|
589
|
+
# described as follows:
|
590
|
+
#
|
591
|
+
# - Γ | Γ -> Γ
|
592
|
+
# - Δ | Δ -> Δ
|
593
|
+
#
|
594
|
+
# @param expr [Expr]
|
595
|
+
# feature expression
|
596
|
+
#
|
597
|
+
# @example
|
598
|
+
# x = RequisiteExpr.new("X")
|
599
|
+
# y = RequisiteExpr.new("Y")
|
600
|
+
# OrExpr.new(x, y).unify_redundant_feature(x) #=> true
|
601
|
+
def unify_redundant_feature(expr)
|
602
|
+
return @elements.include?(expr)
|
520
603
|
end
|
521
604
|
|
605
|
+
# Return true if the expression is summarized by AND connective. This
|
606
|
+
# rule is described as follows:
|
607
|
+
#
|
608
|
+
# - (Γ1 & Γ2) | (Γ1 & Γ3) -> Γ1 & (Γ2 | Γ3)
|
609
|
+
# - Γ1 | (Γ1 & Γ3) -> Γ1
|
610
|
+
# - (Γ1 & Γ2) | Γ1 -> Γ1
|
522
611
|
def summarize_and(elt)
|
523
612
|
if elt.kind_of?(AndExpr)
|
613
|
+
# (Γ1 & Γ2) | (Γ1 & Γ3) -> Γ1 & (Γ2 | Γ3)
|
524
614
|
if target = @elements.find {|e|
|
525
615
|
e.kind_of?(AndExpr) && not((e.elements & elt.elements).empty?)
|
526
616
|
}
|
527
|
-
# (Γ1 & Γ2) | (Γ1 & Γ3) -> Γ1 & (Γ2 | Γ3)
|
528
617
|
@elements.delete(target)
|
529
618
|
union = target.elements & elt.elements
|
530
619
|
union_expr = if union.length > 1
|
@@ -616,7 +705,7 @@ module Pione::Model
|
|
616
705
|
|
617
706
|
include UnificationMethod
|
618
707
|
|
619
|
-
#
|
708
|
+
# Make an expander for response test.
|
620
709
|
def expander
|
621
710
|
Enumerator.new do |y|
|
622
711
|
@elements.each do |elt|
|