cpee-transformation 1.0.0
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 +7 -0
- data/AUTHORS +2 -0
- data/LICENSE +165 -0
- data/README.md +1 -0
- data/Rakefile +21 -0
- data/cpee-transformation.gemspec +29 -0
- data/lib/cpee/transformation/beautiful.rb +182 -0
- data/lib/cpee/transformation/bpmn2.rb +144 -0
- data/lib/cpee/transformation/cpee.rb +309 -0
- data/lib/cpee/transformation/dataflow.rb +127 -0
- data/lib/cpee/transformation/graphviz.rb +100 -0
- data/lib/cpee/transformation/implementation.rb +144 -0
- data/lib/cpee/transformation/implementation.xml +47 -0
- data/lib/cpee/transformation/mermaid.rb +242 -0
- data/lib/cpee/transformation/ptml.rb +316 -0
- data/lib/cpee/transformation/structures.rb +570 -0
- data/lib/cpee/transformation/target.rb +58 -0
- data/lib/cpee/transformation/text-bf.rb +201 -0
- data/lib/cpee/transformation/text-df-PO-extended.rb +221 -0
- data/lib/cpee/transformation/text-df-PO-reduced.rb +211 -0
- data/lib/cpee/transformation/transformation_text_cpee.xml +49 -0
- data/lib/cpee/transformation/transformation_xml_cpee.xml +49 -0
- data/lib/cpee/transformation/transformation_xml_text.xml +49 -0
- data/lib/cpee/transformation/transformer.rb +300 -0
- data/server/trans +38 -0
- data/tools/bpmn2_to_cpee.rb +84 -0
- data/tools/bpmn2_to_mermaid.rb +85 -0
- data/tools/bpmn2_to_ptml.rb +87 -0
- data/tools/cpee-trans +74 -0
- data/tools/cpee_to_cpee.rb +83 -0
- data/tools/cpee_to_dataflow.rb +83 -0
- data/tools/cpee_to_mermaid.rb +85 -0
- data/tools/cpee_to_ptml.rb +87 -0
- data/tools/cpee_to_text_bf.rb +85 -0
- data/tools/cpee_to_text_df-poe.rb +85 -0
- data/tools/cpee_to_text_df-por.rb +85 -0
- data/tools/mermaid_to_cpee.rb +85 -0
- data/tools/ptml_to_cpee.rb +87 -0
- metadata +160 -0
|
@@ -0,0 +1,570 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# This file is part of CPEE-TRANSFORMATION.
|
|
4
|
+
#
|
|
5
|
+
# CPEE-TRANSFORMATION is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or (at your
|
|
8
|
+
# option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# CPEE-TRANSFORMATION is distributed in the hope that it will be useful, but
|
|
11
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
13
|
+
# for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
# along with CPEE-TRANSFORMATION (file COPYING in the main directory). If not,
|
|
17
|
+
# see <http://www.gnu.org/licenses/>.
|
|
18
|
+
|
|
19
|
+
module CPEE
|
|
20
|
+
|
|
21
|
+
module Transformation
|
|
22
|
+
|
|
23
|
+
module Container #{{{
|
|
24
|
+
def container?
|
|
25
|
+
@container || false
|
|
26
|
+
end
|
|
27
|
+
end #}}}
|
|
28
|
+
module Struct #{{{
|
|
29
|
+
def each(&a)
|
|
30
|
+
@sub.each{|s| a.call(s)}
|
|
31
|
+
end
|
|
32
|
+
def length
|
|
33
|
+
@sub.length
|
|
34
|
+
end
|
|
35
|
+
end #}}}
|
|
36
|
+
|
|
37
|
+
class Node #{{{
|
|
38
|
+
include Container
|
|
39
|
+
@@niceid = {}
|
|
40
|
+
attr_reader :id
|
|
41
|
+
attr_reader :endpoints, :methods, :arguments, :attributes
|
|
42
|
+
attr_accessor :script, :script_id, :script_var, :script_type, :incoming, :outgoing, :type, :label, :niceid
|
|
43
|
+
def initialize(context,id,type,label,incoming,outgoing)
|
|
44
|
+
@@niceid[context] ||= -1
|
|
45
|
+
@niceid = (@@niceid[context] += 1)
|
|
46
|
+
@id = id
|
|
47
|
+
@type = type
|
|
48
|
+
@label = label
|
|
49
|
+
@endpoints = []
|
|
50
|
+
@methods = []
|
|
51
|
+
@script = nil
|
|
52
|
+
@script_type = nil
|
|
53
|
+
@script_id = nil
|
|
54
|
+
@script_var = 'result'
|
|
55
|
+
@arguments = {}
|
|
56
|
+
@incoming = incoming
|
|
57
|
+
@outgoing = outgoing
|
|
58
|
+
@attributes = {}
|
|
59
|
+
end
|
|
60
|
+
|
|
61
|
+
def inc_incoming!
|
|
62
|
+
@incoming += 1
|
|
63
|
+
end
|
|
64
|
+
def inc_outgoing!
|
|
65
|
+
@outgoing += 1
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
def to_s
|
|
69
|
+
"#{@niceid} (#{@label},#{@type})\n"
|
|
70
|
+
end
|
|
71
|
+
end # }}}
|
|
72
|
+
class Link #{{{
|
|
73
|
+
attr_accessor :from, :to
|
|
74
|
+
attr_reader :condition, :attributes, :otherwise
|
|
75
|
+
def initialize(from,to,cond=nil,otherwise=false,id=nil)
|
|
76
|
+
@from = from
|
|
77
|
+
@to = to
|
|
78
|
+
@id = id
|
|
79
|
+
@otherwise = otherwise
|
|
80
|
+
@condition = cond
|
|
81
|
+
@attributes = {}
|
|
82
|
+
end
|
|
83
|
+
end #}}}
|
|
84
|
+
class Break < Node #{{{
|
|
85
|
+
def initialize(context)
|
|
86
|
+
super context, '-1', :break, 'BREAK', 1, []
|
|
87
|
+
end
|
|
88
|
+
end #}}}
|
|
89
|
+
|
|
90
|
+
class Alternative < Array #{{{
|
|
91
|
+
include Container
|
|
92
|
+
attr_accessor :condition, :condition_type, :otherwise
|
|
93
|
+
attr_reader :id, :attributes
|
|
94
|
+
def condition?; true; end
|
|
95
|
+
def initialize(id)
|
|
96
|
+
@container = true
|
|
97
|
+
@id = id
|
|
98
|
+
@otherwise = false
|
|
99
|
+
@condition = []
|
|
100
|
+
@condition_type = nil
|
|
101
|
+
@attributes = {}
|
|
102
|
+
end
|
|
103
|
+
def inspect
|
|
104
|
+
::Object::inspect()
|
|
105
|
+
end
|
|
106
|
+
end #}}}
|
|
107
|
+
class Branch < Array #{{{
|
|
108
|
+
include Container
|
|
109
|
+
attr_reader :id
|
|
110
|
+
def condition?; false; end
|
|
111
|
+
def initialize(id)
|
|
112
|
+
@container = true
|
|
113
|
+
@id = id
|
|
114
|
+
end
|
|
115
|
+
end #}}}
|
|
116
|
+
|
|
117
|
+
class Loop #{{{
|
|
118
|
+
include Container
|
|
119
|
+
include Struct
|
|
120
|
+
include Enumerable
|
|
121
|
+
attr_reader :id, :sub
|
|
122
|
+
attr_accessor :type, :condition, :condition_type, :mode
|
|
123
|
+
attr_reader :attributes
|
|
124
|
+
def condition?; true; end
|
|
125
|
+
def initialize(id)
|
|
126
|
+
@container = true
|
|
127
|
+
@id = id
|
|
128
|
+
@type = :loop
|
|
129
|
+
@mode = :pre_test
|
|
130
|
+
@condition = []
|
|
131
|
+
@sub = []
|
|
132
|
+
@condition_type = nil
|
|
133
|
+
@attributes = {}
|
|
134
|
+
end
|
|
135
|
+
def new_branch
|
|
136
|
+
(@sub << Alternative.new(@id)).last
|
|
137
|
+
end
|
|
138
|
+
end #}}}
|
|
139
|
+
|
|
140
|
+
class Parallel #{{{
|
|
141
|
+
include Container
|
|
142
|
+
include Struct
|
|
143
|
+
include Enumerable
|
|
144
|
+
attr_reader :id, :sub
|
|
145
|
+
attr_accessor :type, :wait, :cancel
|
|
146
|
+
def initialize(id,type,wait='-1',cancel='last')
|
|
147
|
+
@container = true
|
|
148
|
+
@id = id
|
|
149
|
+
@type = type
|
|
150
|
+
@sub = []
|
|
151
|
+
@wait = wait
|
|
152
|
+
@cancel = cancel
|
|
153
|
+
end
|
|
154
|
+
def new_branch
|
|
155
|
+
(@sub << Branch.new(@id)).last
|
|
156
|
+
end
|
|
157
|
+
end #}}}
|
|
158
|
+
|
|
159
|
+
class Conditional #{{{
|
|
160
|
+
include Container
|
|
161
|
+
include Struct
|
|
162
|
+
include Enumerable
|
|
163
|
+
attr_reader :container
|
|
164
|
+
attr_reader :id, :sub, :mode, :label
|
|
165
|
+
attr_reader :attributes
|
|
166
|
+
attr_accessor :type
|
|
167
|
+
def initialize(id,mode,type,label='')
|
|
168
|
+
@container = true
|
|
169
|
+
@id = id
|
|
170
|
+
@label = label
|
|
171
|
+
@sub = []
|
|
172
|
+
@mode = mode
|
|
173
|
+
@type = type
|
|
174
|
+
@attributes = {}
|
|
175
|
+
end
|
|
176
|
+
def new_branch
|
|
177
|
+
(@sub << Alternative.new(@id)).last
|
|
178
|
+
end
|
|
179
|
+
end #}}}
|
|
180
|
+
|
|
181
|
+
class Graph #{{{
|
|
182
|
+
attr_reader :flow, :nodes
|
|
183
|
+
|
|
184
|
+
def find_node(niceid)
|
|
185
|
+
@nodes.find{|k,v| v.niceid == niceid }
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
def initialize
|
|
189
|
+
@nodes = {}
|
|
190
|
+
@links = []
|
|
191
|
+
end
|
|
192
|
+
|
|
193
|
+
def to_s
|
|
194
|
+
s = ''
|
|
195
|
+
s << "Nodes:\n"
|
|
196
|
+
@nodes.each do |k,v|
|
|
197
|
+
s << " #{v.niceid} -> #{v.id}, #{v.label}\n"
|
|
198
|
+
end
|
|
199
|
+
s << "Links:\n"
|
|
200
|
+
@links.each do |e|
|
|
201
|
+
s << " #{e.from} -> #{e.to} #{e.condition ? "(#{e.condition})" : ''}\n"
|
|
202
|
+
end
|
|
203
|
+
s
|
|
204
|
+
end
|
|
205
|
+
|
|
206
|
+
def clean_up(&bl)
|
|
207
|
+
selnodes = []
|
|
208
|
+
@nodes.each do |k,n|
|
|
209
|
+
ret = bl.call(n)
|
|
210
|
+
selnodes << n if ret
|
|
211
|
+
end
|
|
212
|
+
selnodes.each do |n|
|
|
213
|
+
if n.incoming > 1 || n.outgoing > 1
|
|
214
|
+
raise "#{n.inspect} - not a simple node to remove"
|
|
215
|
+
end
|
|
216
|
+
to,from = nil
|
|
217
|
+
@links.each do |f|
|
|
218
|
+
to = f if f.to == n.id
|
|
219
|
+
from = f if f.from == n.id
|
|
220
|
+
end
|
|
221
|
+
if to && from
|
|
222
|
+
to.to = from.to
|
|
223
|
+
@links.delete(from)
|
|
224
|
+
@nodes.delete(n.id)
|
|
225
|
+
else
|
|
226
|
+
raise "#{n.inspect} - could not remove flow"
|
|
227
|
+
end
|
|
228
|
+
end
|
|
229
|
+
end
|
|
230
|
+
|
|
231
|
+
def find_script_id(s)
|
|
232
|
+
@nodes.find_all{|k,n| n.script_id == s}
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
def add_node(n,ntype=nil)
|
|
236
|
+
if @nodes.include?(n.id)
|
|
237
|
+
case ntype
|
|
238
|
+
when :outgoing
|
|
239
|
+
@nodes[n.id].inc_outgoing!
|
|
240
|
+
when :incoming
|
|
241
|
+
@nodes[n.id].inc_incoming!
|
|
242
|
+
end
|
|
243
|
+
if @nodes[n.id].label.nil? || @nodes[n.id].label.strip == ''
|
|
244
|
+
@nodes[n.id].label = n.label
|
|
245
|
+
end
|
|
246
|
+
@nodes[n.id]
|
|
247
|
+
else
|
|
248
|
+
@nodes[n.id] = n
|
|
249
|
+
end
|
|
250
|
+
end
|
|
251
|
+
|
|
252
|
+
def link(f,t)
|
|
253
|
+
@links.find{ |x| x.from == f && x.to == t }
|
|
254
|
+
end
|
|
255
|
+
|
|
256
|
+
def add_link(l)
|
|
257
|
+
@links << l
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
def next_nodes(from)
|
|
261
|
+
links = @links.find_all { |x| x.from == from.id }
|
|
262
|
+
links.map{|x| @nodes[x.to] }
|
|
263
|
+
end
|
|
264
|
+
|
|
265
|
+
def next_node(from)
|
|
266
|
+
if (nodes = next_nodes(from)).length == 1
|
|
267
|
+
nodes.first
|
|
268
|
+
else
|
|
269
|
+
raise "#{from.inspect} - multiple outgoing connections"
|
|
270
|
+
end
|
|
271
|
+
end
|
|
272
|
+
end #}}}
|
|
273
|
+
|
|
274
|
+
class Tree < Array #{{{
|
|
275
|
+
def condition?; false; end
|
|
276
|
+
|
|
277
|
+
def to_s(verbose=true)
|
|
278
|
+
"TREE:\n" << print_tree(self,' ',verbose)
|
|
279
|
+
end
|
|
280
|
+
|
|
281
|
+
def print_tree(ele,indent=' ',verbose=true)
|
|
282
|
+
ret = ''
|
|
283
|
+
ele.each_with_index do |e,i|
|
|
284
|
+
last = (i == ele.length - 1)
|
|
285
|
+
pchar = last ? '└' : '├'
|
|
286
|
+
if e.container?
|
|
287
|
+
cname = e.class.to_s.gsub(/[^:]*::/,'')
|
|
288
|
+
ret << indent + pchar + ' ' + cname + " #{cname == 'Alternative' ? e.condition : ''}\n"
|
|
289
|
+
ret << print_tree(e,indent + (last ? ' ' : '│ '),verbose)
|
|
290
|
+
elsif e.is_a?(Break)
|
|
291
|
+
ret << indent + pchar + ' ' + e.class.to_s.gsub(/[^:]*::/,'') + "\n"
|
|
292
|
+
else
|
|
293
|
+
ret << indent + pchar + ' ' + e.niceid.to_s + (verbose ? " (#{e.label})" : "") + "\n"
|
|
294
|
+
end
|
|
295
|
+
end
|
|
296
|
+
ret
|
|
297
|
+
end
|
|
298
|
+
private :print_tree
|
|
299
|
+
end #}}}
|
|
300
|
+
|
|
301
|
+
class Traces < Array #{{{
|
|
302
|
+
def initialize_copy(other)
|
|
303
|
+
super
|
|
304
|
+
self.map!{ |t| t.dup }
|
|
305
|
+
end
|
|
306
|
+
|
|
307
|
+
def remove(trcs)
|
|
308
|
+
trcs.each do |t|
|
|
309
|
+
self.delete(t)
|
|
310
|
+
end
|
|
311
|
+
end
|
|
312
|
+
def remove_by_endnode(enode)
|
|
313
|
+
self.delete_if do |t|
|
|
314
|
+
t[0] != enode
|
|
315
|
+
end
|
|
316
|
+
# self.delete_if do |t|
|
|
317
|
+
# t[0] == enode && t.length <= 2
|
|
318
|
+
# end
|
|
319
|
+
end
|
|
320
|
+
|
|
321
|
+
def empty!
|
|
322
|
+
self.delete_if{true}
|
|
323
|
+
end
|
|
324
|
+
|
|
325
|
+
def remove_empty
|
|
326
|
+
self.delete_if{|t| t.empty? }
|
|
327
|
+
end
|
|
328
|
+
|
|
329
|
+
def first_node
|
|
330
|
+
self.first.first
|
|
331
|
+
end
|
|
332
|
+
def second_nodes
|
|
333
|
+
self.map { |t| t.length > 1 ? t[1] : t[0] }
|
|
334
|
+
end
|
|
335
|
+
|
|
336
|
+
def shortest
|
|
337
|
+
self.min_by{|e|e.length}
|
|
338
|
+
end
|
|
339
|
+
|
|
340
|
+
def legend(nid=true)
|
|
341
|
+
ret = "Legend:\n"
|
|
342
|
+
a = self.flatten.uniq
|
|
343
|
+
a.each {|n| ret << " " + (nid ? n.niceid.to_s : n.id.to_s) + ' ' + n.type.to_s + ' ' + n.label.to_s + "\n" }
|
|
344
|
+
ret
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
def to_s(nid = true)
|
|
348
|
+
"TRACES: " + self.collect { |t| t.empty? ? '∅' : t.collect{|n| ("%2d" % (nid ? n.niceid : n.id.to_i)) + "(i#{n.incoming},o#{n.outgoing})" }.join(' → ') }.join("\n ")
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
def shift_all
|
|
352
|
+
self.each{ |tr| tr.shift }
|
|
353
|
+
end
|
|
354
|
+
def pop_all(what=nil)
|
|
355
|
+
if what.nil?
|
|
356
|
+
self.each{ |tr| tr.pop }
|
|
357
|
+
else
|
|
358
|
+
self.each{ |tr| tr.pop if tr.last == what }
|
|
359
|
+
end
|
|
360
|
+
end
|
|
361
|
+
|
|
362
|
+
def finished?
|
|
363
|
+
self.reduce(0){|sum,t| sum += t.length} == 0
|
|
364
|
+
end
|
|
365
|
+
|
|
366
|
+
def same_first
|
|
367
|
+
(n = self.map{|t| t.first }.uniq).length == 1 ? n.first : nil
|
|
368
|
+
end
|
|
369
|
+
|
|
370
|
+
def incoming(node)
|
|
371
|
+
tcount = 1
|
|
372
|
+
self.each do |t|
|
|
373
|
+
break if t.length == 1
|
|
374
|
+
tcount += 1 if t.last == node
|
|
375
|
+
end
|
|
376
|
+
tcount
|
|
377
|
+
end
|
|
378
|
+
|
|
379
|
+
def include_in_all?(e)
|
|
380
|
+
num = 0
|
|
381
|
+
self.each{|n| num += 1 if n.include?(e)}
|
|
382
|
+
num == self.length
|
|
383
|
+
end
|
|
384
|
+
|
|
385
|
+
# first and last the same in all traces
|
|
386
|
+
def all_loops?
|
|
387
|
+
num = 0
|
|
388
|
+
self.each{|n| num += 1 if n.first == n.last }
|
|
389
|
+
num == self.length
|
|
390
|
+
end
|
|
391
|
+
# find all loops. Loops need to have the same second to last
|
|
392
|
+
def all_front?
|
|
393
|
+
lo = Traces.new self.find_all{ |t| t.first == t.last }
|
|
394
|
+
lo.uniq!
|
|
395
|
+
num = 0
|
|
396
|
+
search = lo.first[-2]
|
|
397
|
+
self.each{|n| num += 1 if n.include?(search) }
|
|
398
|
+
num == self.length
|
|
399
|
+
end
|
|
400
|
+
|
|
401
|
+
# second to last the same as in all traces
|
|
402
|
+
# second to last because last must be the same as current
|
|
403
|
+
def all_tail?
|
|
404
|
+
num = 0
|
|
405
|
+
search = self.first[-2]
|
|
406
|
+
self.each{|n| num += 1 if n[-2] == search }
|
|
407
|
+
num == self.length
|
|
408
|
+
end
|
|
409
|
+
|
|
410
|
+
def add_breaks(context,front=true)
|
|
411
|
+
trueloops = self.find_all{ |t| t.last == t.first }.length
|
|
412
|
+
tb = Break.new(context)
|
|
413
|
+
if trueloops == self.length
|
|
414
|
+
self << (front ? [nil,tb] : [tb,nil])
|
|
415
|
+
else
|
|
416
|
+
self.each do |t|
|
|
417
|
+
t << tb unless t.last == t.first ### an explicit break
|
|
418
|
+
end
|
|
419
|
+
end
|
|
420
|
+
end
|
|
421
|
+
|
|
422
|
+
def loops_only
|
|
423
|
+
lo = Traces.new self.find_all{ |t| t.first == t.last }
|
|
424
|
+
lo.uniq!
|
|
425
|
+
lo
|
|
426
|
+
end
|
|
427
|
+
def loops_and_partial_loops
|
|
428
|
+
lo = Traces.new self.find_all{ |t| t.first == t.last }
|
|
429
|
+
self.each do |t|
|
|
430
|
+
lo << t if lo.second_nodes.include?(t[1])
|
|
431
|
+
end
|
|
432
|
+
lo.uniq!
|
|
433
|
+
lo
|
|
434
|
+
end
|
|
435
|
+
|
|
436
|
+
def eliminate_front(loops)
|
|
437
|
+
### find nested loops
|
|
438
|
+
self.each_with_index do |t,i|
|
|
439
|
+
maxcut = 0
|
|
440
|
+
### find out which common parts the traces share with theloops
|
|
441
|
+
loops.each do |l|
|
|
442
|
+
maxcut.upto(l.length) do |i|
|
|
443
|
+
maxcut = i if t[0...i] == l[0...i]
|
|
444
|
+
end
|
|
445
|
+
end
|
|
446
|
+
### in case of nested loop (common part occurs at end of loop), include the whole
|
|
447
|
+
0.upto (maxcut-1) do |j|
|
|
448
|
+
if self[i][j] == self[i].last
|
|
449
|
+
loops << self[i].shift(self[i].length)
|
|
450
|
+
end
|
|
451
|
+
end
|
|
452
|
+
end
|
|
453
|
+
loops.uniq!
|
|
454
|
+
loops.remove_empty
|
|
455
|
+
self.remove_empty
|
|
456
|
+
|
|
457
|
+
### cut from non-nested loops
|
|
458
|
+
self.each_with_index do |t,i|
|
|
459
|
+
maxcut = 0
|
|
460
|
+
### find out which common parts the traces share with theloops
|
|
461
|
+
loops.each do |l|
|
|
462
|
+
maxcut.upto(l.length) do |i|
|
|
463
|
+
maxcut = i if t[0...i] == l[0...i]
|
|
464
|
+
end
|
|
465
|
+
end
|
|
466
|
+
self[i].shift(maxcut)
|
|
467
|
+
end
|
|
468
|
+
end
|
|
469
|
+
def eliminate(loops)
|
|
470
|
+
### find nested loops
|
|
471
|
+
self.each_with_index do |t,i|
|
|
472
|
+
maxcut = 0
|
|
473
|
+
### find out which common parts the traces share with theloops
|
|
474
|
+
loops.each do |l|
|
|
475
|
+
maxcut.upto(l.length) do |i|
|
|
476
|
+
maxcut = i if t[0...i] == l[0...i]
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
### in case of nested loop (common part occurs at end of loop), include the whole
|
|
480
|
+
0.upto (maxcut-1) do |j|
|
|
481
|
+
if self[i][j] == self[i].last
|
|
482
|
+
loops << self[i].shift(self[i].length)
|
|
483
|
+
end
|
|
484
|
+
end
|
|
485
|
+
end
|
|
486
|
+
loops.uniq!
|
|
487
|
+
loops.remove_empty
|
|
488
|
+
self.remove_empty
|
|
489
|
+
|
|
490
|
+
### cut from non-nested loops
|
|
491
|
+
self.each_with_index do |t,i|
|
|
492
|
+
maxcut = 0
|
|
493
|
+
### find out which common parts the traces share with theloops
|
|
494
|
+
loops.each do |l|
|
|
495
|
+
maxcut.upto(l.length) do |i|
|
|
496
|
+
maxcut = i if t[0...i] == l[0...i]
|
|
497
|
+
end
|
|
498
|
+
end
|
|
499
|
+
cutted = self[i].shift(maxcut)
|
|
500
|
+
loops << cutted if cutted.length > 1 ### if only the loop node is left, no need to attach
|
|
501
|
+
end
|
|
502
|
+
end
|
|
503
|
+
|
|
504
|
+
def extend
|
|
505
|
+
# find largest common
|
|
506
|
+
max = []
|
|
507
|
+
sh = self.shortest
|
|
508
|
+
sh = sh[0..-2] if sh.first == sh.last
|
|
509
|
+
sh.each_with_index do |e,i|
|
|
510
|
+
max << e if self.include_in_all?(e)
|
|
511
|
+
end
|
|
512
|
+
max = max.last
|
|
513
|
+
|
|
514
|
+
# if last is the largest common do nothing
|
|
515
|
+
# else append from last to largest common
|
|
516
|
+
self.each do |t|
|
|
517
|
+
unless t.last == max
|
|
518
|
+
last = t.last
|
|
519
|
+
if t.index(last) && t.index(max)
|
|
520
|
+
(t.index(last) + 1).upto(t.index(max)) do |i|
|
|
521
|
+
t << t[i]
|
|
522
|
+
end
|
|
523
|
+
end
|
|
524
|
+
end
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
max
|
|
528
|
+
end
|
|
529
|
+
|
|
530
|
+
def find_endnode
|
|
531
|
+
# supress loops
|
|
532
|
+
trcs = self.dup
|
|
533
|
+
# dangerous TODO
|
|
534
|
+
trcs.delete_if { |t| t.uniq.length < t.length }
|
|
535
|
+
|
|
536
|
+
# find common node (except loops)
|
|
537
|
+
enode = nil
|
|
538
|
+
unless trcs.empty?
|
|
539
|
+
trcs.first.each do |n|
|
|
540
|
+
if trcs.include_in_all?(n)
|
|
541
|
+
enode = n
|
|
542
|
+
break
|
|
543
|
+
end
|
|
544
|
+
end
|
|
545
|
+
end
|
|
546
|
+
enode
|
|
547
|
+
end
|
|
548
|
+
|
|
549
|
+
def segment_by(endnode)
|
|
550
|
+
# cut shit until common node, return the shit you cut away
|
|
551
|
+
tracesgroup = self.group_by{|t| t.first}.map do |k,trace|
|
|
552
|
+
coltrace = trace.map do |t|
|
|
553
|
+
# slice upto common node, collect the sliced away part
|
|
554
|
+
len = t.index(endnode)
|
|
555
|
+
if len
|
|
556
|
+
cut = t.slice!(0...len)
|
|
557
|
+
cut << t.first
|
|
558
|
+
else # if endnode is nil, then return the whole
|
|
559
|
+
t
|
|
560
|
+
end
|
|
561
|
+
end.uniq
|
|
562
|
+
Traces.new(coltrace)
|
|
563
|
+
end
|
|
564
|
+
[tracesgroup,endnode]
|
|
565
|
+
end
|
|
566
|
+
end #}}}
|
|
567
|
+
|
|
568
|
+
end
|
|
569
|
+
|
|
570
|
+
end
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
# encoding: UTF-8
|
|
2
|
+
#
|
|
3
|
+
# This file is part of CPEE-TRANSFORMATION.
|
|
4
|
+
#
|
|
5
|
+
# CPEE-TRANSFORMATION is free software: you can redistribute it and/or modify
|
|
6
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
|
7
|
+
# the Free Software Foundation, either version 3 of the License, or (at your
|
|
8
|
+
# option) any later version.
|
|
9
|
+
#
|
|
10
|
+
# CPEE-TRANSFORMATION is distributed in the hope that it will be useful, but
|
|
11
|
+
# WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
|
|
12
|
+
# FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License
|
|
13
|
+
# for more details.
|
|
14
|
+
#
|
|
15
|
+
# You should have received a copy of the GNU Lesser General Public License
|
|
16
|
+
# along with CPEE-TRANSFORMATION (file COPYING in the main directory). If not,
|
|
17
|
+
# see <http://www.gnu.org/licenses/>.
|
|
18
|
+
|
|
19
|
+
module CPEE
|
|
20
|
+
|
|
21
|
+
module Transformation
|
|
22
|
+
|
|
23
|
+
module Target
|
|
24
|
+
|
|
25
|
+
class Default
|
|
26
|
+
def initialize(tree)
|
|
27
|
+
@tree = tree
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def generate_in_list(list,res)
|
|
31
|
+
list.each do |e|
|
|
32
|
+
nam = e.class.name.gsub(/\w+:+/,'')
|
|
33
|
+
res = send("print_#{nam}".to_sym,e,res) # always save last node
|
|
34
|
+
end
|
|
35
|
+
res
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
def generate_after_list(list,res)
|
|
39
|
+
post = []
|
|
40
|
+
list.each do |e|
|
|
41
|
+
nam = e.class.name.gsub(/\w+:+/,'')
|
|
42
|
+
post += send("print_#{nam}".to_sym,e,res)
|
|
43
|
+
end
|
|
44
|
+
post.compact!
|
|
45
|
+
post.each do |pair|
|
|
46
|
+
ltext, node = pair
|
|
47
|
+
res << ltext
|
|
48
|
+
generate_after_list(node,res)
|
|
49
|
+
end
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|