MINT-scxml 1.0.0 → 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
data/Gemfile CHANGED
@@ -1,5 +1,5 @@
1
1
  source :rubygems
2
- gem "MINT-statemachine", "1.2.3"
3
- gem "rspec", "1.3.1"
2
+ gem "MINT-statemachine","1.3.0"
3
+ gem "rspec","2.8.0"
4
4
  gem "rake","0.9.2"
5
5
  gem "hoe", "2.9.6"
data/Gemfile.lock CHANGED
@@ -1,18 +1,26 @@
1
1
  GEM
2
2
  remote: http://rubygems.org/
3
3
  specs:
4
- MINT-statemachine (1.2.3)
4
+ MINT-statemachine (1.3.0)
5
+ diff-lcs (1.1.3)
5
6
  hoe (2.9.6)
6
7
  rake (~> 0.8)
7
8
  rake (0.9.2)
8
- rspec (1.3.1)
9
+ rspec (2.8.0)
10
+ rspec-core (~> 2.8.0)
11
+ rspec-expectations (~> 2.8.0)
12
+ rspec-mocks (~> 2.8.0)
13
+ rspec-core (2.8.0)
14
+ rspec-expectations (2.8.0)
15
+ diff-lcs (~> 1.1.2)
16
+ rspec-mocks (2.8.0)
9
17
 
10
18
  PLATFORMS
11
19
  ruby
12
20
  x86-mingw32
13
21
 
14
22
  DEPENDENCIES
15
- MINT-statemachine (= 1.2.3)
23
+ MINT-statemachine (= 1.3.0)
16
24
  hoe (= 2.9.6)
17
25
  rake (= 0.9.2)
18
- rspec (= 1.3.1)
26
+ rspec (= 2.8.0)
data/History.txt CHANGED
@@ -1,3 +1,17 @@
1
+ === 1.1.0 / 2012-11-20
2
+
3
+ * (Sebastian) fixed bug: root statemachine was wrongly set for states that are nested inside parallel
4
+ * (Sebastian) added test for spontaneous transitions inside parallel states
5
+ * (Sebastian) removed old MINT test state machines
6
+ * (Jessica) transitions now stored as an array
7
+ * (Jessica) fixed parallel superstate bug
8
+ * (Jessica) All tests working. Added on_entry, on_exit and transitions for parallel states
9
+ * (Jessica) added spontaneous transition
10
+ * (Jessica) WIP: script
11
+ * (Jessica) added treatment for ifs
12
+ * (Jessica) fixed history states support and history state tests
13
+ * (Jessica) Removed unnecessary transitions.
14
+
1
15
  === 1.0.0 / 2011-11-01
2
16
 
3
17
  * First version
data/MINT-scxml.gemspec CHANGED
@@ -1,35 +1,41 @@
1
1
  # -*- encoding: utf-8 -*-
2
2
 
3
3
  Gem::Specification.new do |s|
4
- s.name = %q{MINT-scxml}
5
- s.version = "1.0.0"
4
+ s.name = "MINT-scxml"
5
+ s.version = "1.1.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
8
- s.authors = [%q{Jessica H. Colnago, Sebastian Feuerstack}]
9
- s.date = %q{2011-11-01}
10
- s.description = %q{}
11
- s.email = %q{Sebastian@Feuerstack.org}
12
- s.extra_rdoc_files = [%q{History.txt}, %q{Manifest.txt}, %q{README.txt}]
13
- s.files = [%q{.autotest}, %q{.idea/workspace.xml}, %q{Gemfile}, %q{Gemfile.lock}, %q{History.txt}, %q{MINT-scxml.gemspec}, %q{Manifest.txt}, %q{README.rdoc}, %q{README.txt}, %q{Rakefile}, %q{lib/MINT-scxml.rb}, %q{lib/MINT-scxml/scxml-parser.rb}, %q{spec/atm_spec.rb}, %q{spec/parser_spec.rb}, %q{spec/spec.opts}, %q{spec/spec_helper.rb}, %q{spec/test_handgestures_spec.rb}, %q{spec/testmachines/atm_enhanced.rb}, %q{spec/testmachines/handgestures-scxmlgui.png}, %q{spec/testmachines/handgestures-scxmlgui.scxml}, %q{spec/testmachines/multiplestates.rb}, %q{spec/testmachines/traffic_light_enhanced.rb}, %q{spec/testmachines/vending_machine1.rb}, %q{spec/testmachines/vending_machine2.rb}, %q{spec/testmachines/vending_machine3.rb}, %q{spec/testmachines/vending_machine4.rb}, %q{spec_helper.rb}, %q{statemachines/AICommand_scxml_spec.rb}, %q{statemachines/AIO_scxml_spec.rb}, %q{statemachines/aui-scxml/AIC.scxml}, %q{statemachines/aui-scxml/AICommand.scxml}, %q{statemachines/aui-scxml/AICommand2.scxml}, %q{statemachines/aui-scxml/AIO.scxml}, %q{statemachines/aui/AIC.rb}, %q{statemachines/aui/AIChoiceElement.rb}, %q{statemachines/aui/AICommand.rb}, %q{statemachines/aui/AIIN.rb}, %q{statemachines/aui/AIINContinous.rb}, %q{statemachines/aui/AIMultiChoice.rb}, %q{statemachines/aui/AIMultiChoiceElement.rb}, %q{statemachines/aui/AIOUTContinous.rb}, %q{statemachines/aui/AISingleChoice.rb}, %q{statemachines/aui/AISingleChoiceElement.rb}, %q{statemachines/aui/aio.rb}, %q{statemachines/specs/AICommand_spec.rb}, %q{statemachines/specs/AIINContinous_spec.rb}, %q{statemachines/specs/AIMultiChoiceElement_spec.rb}, %q{statemachines/specs/AIMultiChoice_spec.rb}, %q{statemachines/specs/AIOUTContinous_spec.rb}, %q{statemachines/specs/AIO_spec.rb}, %q{statemachines/specs/AISingleChoiceElement_spec.rb}, %q{statemachines/specs/AISingleChoice_spec.rb}, %q{.gemtest}]
14
- s.homepage = %q{http://www.multi-access.de}
15
- s.rdoc_options = [%q{--main}, %q{README.rdoc}]
16
- s.require_paths = [%q{lib}]
17
- s.rubyforge_project = %q{MINT-scxml}
18
- s.rubygems_version = %q{1.8.5}
19
- s.summary = %q{}
8
+ s.authors = ["Jessica H. Colnago, Sebastian Feuerstack"]
9
+ s.date = "2012-11-20"
10
+ s.description = "This gem implements a state chart XML (SCXML) parser that generates a ruby statemachine."
11
+ s.email = "Sebastian@Feuerstack.org"
12
+ s.extra_rdoc_files = ["History.txt", "Manifest.txt", "README.rdoc"]
13
+ s.files = ["Gemfile", "Gemfile.lock", "History.txt", "MINT-scxml.gemspec", "Manifest.txt", "README.rdoc", "Rakefile", "lib/MINT-scxml.rb", "lib/MINT-scxml/scxml-parser.rb", "spec/atm_spec.rb", "spec/if_spec.rb", "spec/parser_spec.rb", "spec/spec.opts", "spec/spec_helper.rb", "spec/test_handgestures_spec.rb", "spec/testmachines/atm_enhanced.rb", "spec/testmachines/button.scxml", "spec/testmachines/handgestures-scxmlgui.png", "spec/testmachines/handgestures-scxmlgui.scxml", "spec/testmachines/multiplestates.rb", "spec/testmachines/traffic_light_enhanced.rb", "spec/testmachines/vending_machine1.rb", "spec/testmachines/vending_machine2.rb", "spec/testmachines/vending_machine3.rb", "spec/testmachines/vending_machine4.rb", "spec_helper.rb", "statemachines/AICommand_scxml_spec.rb", "statemachines/AIO_scxml_spec.rb", "statemachines/specs/AICommand_spec.rb", "statemachines/specs/AIINContinous_spec.rb", "statemachines/specs/AIMultiChoiceElement_spec.rb", "statemachines/specs/AIMultiChoice_spec.rb", "statemachines/specs/AIOUTContinous_spec.rb", "statemachines/specs/AIO_spec.rb", "statemachines/specs/AISingleChoiceElement_spec.rb", "statemachines/specs/AISingleChoice_spec.rb", ".gemtest"]
14
+ s.homepage = "http://www.multi-access.de"
15
+ s.rdoc_options = ["--main", "README.rdoc"]
16
+ s.require_paths = ["lib"]
17
+ s.rubyforge_project = "MINT-scxml"
18
+ s.rubygems_version = "1.8.15"
19
+ s.summary = "This gem implements a state chart XML (SCXML) parser that generates a ruby statemachine."
20
20
 
21
21
  if s.respond_to? :specification_version then
22
22
  s.specification_version = 3
23
23
 
24
24
  if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
25
- s.add_runtime_dependency(%q<MINT-statemachine>, ["~> 1.2.3"])
26
- s.add_development_dependency(%q<hoe>, ["~> 2.9"])
25
+ s.add_runtime_dependency(%q<MINT-statemachine>, ["~> 1.3.0"])
26
+ s.add_development_dependency(%q<rdoc>, ["~> 3.10"])
27
+ s.add_development_dependency(%q<newgem>, [">= 1.5.3"])
28
+ s.add_development_dependency(%q<hoe>, ["~> 3.1"])
27
29
  else
28
- s.add_dependency(%q<MINT-statemachine>, ["~> 1.2.3"])
29
- s.add_dependency(%q<hoe>, ["~> 2.9"])
30
+ s.add_dependency(%q<MINT-statemachine>, ["~> 1.3.0"])
31
+ s.add_dependency(%q<rdoc>, ["~> 3.10"])
32
+ s.add_dependency(%q<newgem>, [">= 1.5.3"])
33
+ s.add_dependency(%q<hoe>, ["~> 3.1"])
30
34
  end
31
35
  else
32
- s.add_dependency(%q<MINT-statemachine>, ["~> 1.2.3"])
33
- s.add_dependency(%q<hoe>, ["~> 2.9"])
36
+ s.add_dependency(%q<MINT-statemachine>, ["~> 1.3.0"])
37
+ s.add_dependency(%q<rdoc>, ["~> 3.10"])
38
+ s.add_dependency(%q<newgem>, [">= 1.5.3"])
39
+ s.add_dependency(%q<hoe>, ["~> 3.1"])
34
40
  end
35
41
  end
data/Manifest.txt CHANGED
@@ -8,11 +8,13 @@ Rakefile
8
8
  lib/MINT-scxml.rb
9
9
  lib/MINT-scxml/scxml-parser.rb
10
10
  spec/atm_spec.rb
11
+ spec/if_spec.rb
11
12
  spec/parser_spec.rb
12
13
  spec/spec.opts
13
14
  spec/spec_helper.rb
14
15
  spec/test_handgestures_spec.rb
15
16
  spec/testmachines/atm_enhanced.rb
17
+ spec/testmachines/button.scxml
16
18
  spec/testmachines/handgestures-scxmlgui.png
17
19
  spec/testmachines/handgestures-scxmlgui.scxml
18
20
  spec/testmachines/multiplestates.rb
@@ -24,21 +26,6 @@ spec/testmachines/vending_machine4.rb
24
26
  spec_helper.rb
25
27
  statemachines/AICommand_scxml_spec.rb
26
28
  statemachines/AIO_scxml_spec.rb
27
- statemachines/aui-scxml/AIC.scxml
28
- statemachines/aui-scxml/AICommand.scxml
29
- statemachines/aui-scxml/AICommand2.scxml
30
- statemachines/aui-scxml/AIO.scxml
31
- statemachines/aui/AIC.rb
32
- statemachines/aui/AIChoiceElement.rb
33
- statemachines/aui/AICommand.rb
34
- statemachines/aui/AIIN.rb
35
- statemachines/aui/AIINContinous.rb
36
- statemachines/aui/AIMultiChoice.rb
37
- statemachines/aui/AIMultiChoiceElement.rb
38
- statemachines/aui/AIOUTContinous.rb
39
- statemachines/aui/AISingleChoice.rb
40
- statemachines/aui/AISingleChoiceElement.rb
41
- statemachines/aui/aio.rb
42
29
  statemachines/specs/AICommand_spec.rb
43
30
  statemachines/specs/AIINContinous_spec.rb
44
31
  statemachines/specs/AIMultiChoiceElement_spec.rb
data/README.rdoc CHANGED
@@ -33,7 +33,7 @@ and generate the RDoc.
33
33
 
34
34
  == LICENSE:
35
35
 
36
- Copyright (C) 2010,2011 Sebastian Feuerstack, Jessica H. Colnago
36
+ Copyright (C) 2010-2012 Sebastian Feuerstack, Jessica H. Colnago
37
37
 
38
38
  This library is free software; you can redistribute it and/or
39
39
  modify it under the terms of the GNU Lesser General Public
data/Rakefile CHANGED
@@ -16,16 +16,10 @@ Hoe.plugin :newgem
16
16
  Hoe.spec 'MINT-scxml' do
17
17
  self.developer 'Jessica H. Colnago, Sebastian Feuerstack', 'Sebastian@Feuerstack.org'
18
18
  self.rubyforge_name = self.name # TODO this is default value
19
- self.extra_deps = [['MINT-statemachine','~> 1.2.3']]
19
+ self.extra_deps = [['MINT-statemachine','~> 1.3.0']]
20
20
  self.email = "Sebastian@Feuerstack.org"
21
21
 
22
- # HEY! If you fill these out in ~/.hoe_template/Rakefile.erb then
23
- # you'll never have to touch them again!
24
- # (delete this comment too, of course)
25
22
 
26
- # developer('FIX', 'FIX@example.com')
27
-
28
- # self.rubyforge_name = 'scxml-gemx' # if different than 'scxml-gem'
29
23
  end
30
24
 
31
25
  # vim: syntax=ruby
data/lib/MINT-scxml.rb CHANGED
@@ -1,5 +1,5 @@
1
1
  class SCXML_MINT
2
- VERSION = '1.0.0'
2
+ VERSION = '1.1.0'
3
3
  end
4
4
 
5
5
  require "MINT-scxml/scxml-parser"
@@ -1,4 +1,3 @@
1
- # -*- coding: raw-text -*-
2
1
  require 'rubygems'
3
2
  require "bundler/setup"
4
3
  require 'statemachine'
@@ -20,98 +19,164 @@ class StatemachineParser < Statemachine::StatemachineBuilder
20
19
 
21
20
  def initialize(context = nil, logger = nil, queue = nil)
22
21
  super()
23
- @actions = Array.new
24
22
  @current_transition = nil
25
23
  @current_state = nil
26
24
  @current_element = nil
27
25
  @parallel = nil
28
- @state = Array.new
26
+ @history_state = nil
29
27
  @statemachine.messenger = logger
30
28
  @statemachine.message_queue = queue
31
29
  @statemachine.context= context
30
+ @actions = Array.new
31
+ @actions_aux = Array.new
32
+ @state = Array.new
32
33
  @substate = Array.new
33
34
  @transitions = Array.new
34
35
  @history_states = Array.new
35
36
  @history_target = Array.new
36
- @history_state = nil
37
+ @parallel_state = Array.new
38
+ @if_actions = Array.new
39
+ @if_actions_aux = Array.new
40
+ @if = Array.new
41
+ @tag = Array.new
42
+ @cond = Array.new
37
43
  @history = false
38
44
  @is_parallel = false
39
45
  @scxml_state = false
40
- @parallel_state = Array.new
41
46
  end
42
47
 
48
+ # This function parses scxml from a file
43
49
  def build_from_scxml(filename)
44
50
  source = File.new filename
45
51
  Document.parse_stream(source, self)
46
- @statemachine.reset
47
- return @statemachine
52
+ #@statemachine.reset
53
+ @statemachine
48
54
  end
49
55
 
50
- # parses scxml directly from string parameter stringbuffer
56
+ # This function parses scxml directly from the string parameter "stringbuffer"
51
57
  def build_from_scxml_string(stringbuffer)
52
58
  Document.parse_stream(stringbuffer, self)
53
- @statemachine.reset
54
- return @statemachine
59
+ #@statemachine.reset
60
+ @statemachine
55
61
  end
56
62
 
63
+
64
+ # This function deals with the different scenarios for the creation of actions with if
65
+ def creating_ifs
66
+ if @if.size == 1
67
+ @if_actions.push(@if_actions_aux.last) if @if_actions_aux.size != 0
68
+ if @actions_aux.size != 0
69
+ @actions_aux.each do |j|
70
+ @if_actions.push(j)
71
+ end
72
+ @actions_aux = []
73
+ end
74
+ @actions.push([@tag.last, @cond.last, @if_actions])
75
+ else
76
+ if @if_actions.size != 0
77
+ @if_actions_aux.push(@if_actions)
78
+ end
79
+ @actions_aux.push([@tag.last, @cond.last, @if_actions_aux.last])
80
+ end
81
+ @if_actions = []
82
+ @cond.pop
83
+ @tag.pop
84
+ @if_actions_aux.pop if @if_actions_aux.size != 0
85
+ end
86
+
87
+ # This function defines the actions to be taken for each different tag when the tag is opened
57
88
  def tag_start(name, attributes)
58
89
  case name
59
90
  when 'scxml'
91
+ # If the initial tag <scxml> has a n ame attribute, define it as the most outer super state
60
92
  if attributes['name']
61
93
  @scxml_state = true
62
- state = nil
63
94
  @current_state = State.new
64
- @current_state.id = attributes['name']
95
+ @current_state.id = attributes['id']
65
96
  @current_state.initial = attributes['initial']
66
97
  state = Statemachine::SuperstateBuilder.new(attributes['name'].to_sym, @subject, @statemachine)
67
- if (@current_state.initial != nil)
98
+ # If the current state has an initial state defined, add it to the state created.
99
+ if @current_state.initial != nil
68
100
  state.startstate(@current_state.initial.to_sym)
69
101
  end
102
+ # Adds it to a list of "open" states
70
103
  @state.push(state)
71
104
  end
72
105
  when 'parallel'
73
- @parallel = Statemachine::ParallelStateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
74
106
  @is_parallel = true
75
107
  # If there is a state that encapsulates the parallel state, change it to a superstate
76
- if (not @state.empty? and @state.last.is_a? Statemachine::StateBuilder)
77
- state = Statemachine::SuperstateBuilder.new(@state.last.subject.id, @state.last.subject.superstate, @state.last.subject.statemachine)
78
- @state.pop # pops the old one
79
- @state.push(state) # pushes the new one
108
+ if not @state.empty? and @state.last.is_a? Statemachine::StateBuilder
109
+ state = Statemachine::SuperstateBuilder.new(@state.last.subject.id, @state.last.subject.superstate, @state.last.subject.statemachine)
110
+ @state.pop # pops the old one
111
+ @state.push(state) # pushes the new one
112
+ end
113
+ if @state.empty?
114
+ @parallel = Statemachine::ParallelStateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
115
+ else
116
+ @parallel = Statemachine::ParallelStateBuilder.new(attributes['id'].to_sym, @state.last.subject, @statemachine)
80
117
  end
118
+
81
119
  when 'state'
82
120
  @current_state = State.new
83
121
  @current_state.id = attributes['id']
84
122
  @current_state.initial = attributes['initial']
85
- if (@state.empty?) # It is not a substate
86
- if (@current_state.initial != nil) # AND it is a superstate
87
- state = Statemachine::SuperstateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
88
- state.startstate(@current_state.initial.to_sym)
89
- else # AND it is a state
90
- state = Statemachine::StateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
91
- end
92
- else # It is a substate
93
- if (@current_state.initial != nil) # AND it is a superstate
94
- state = Statemachine::SuperstateBuilder.new(attributes['id'].to_sym, @state.last.subject, @statemachine)
123
+ if @state.empty?
124
+ # It is not a substate
125
+ if @current_state.initial != nil
126
+ # and it is a superstate
127
+ state = Statemachine::SuperstateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
95
128
  state.startstate(@current_state.initial.to_sym)
96
- else # AND it is a subsubstate
97
- if (@state.last.is_a? Statemachine::StateBuilder) # but it's parent is not a superstate yet
129
+ else
130
+ # and it is a state
131
+ state = Statemachine::StateBuilder.new(attributes['id'].to_sym, @subject, @statemachine)
132
+ end
133
+ else
134
+ #It is a substate
135
+ if @state.last.is_a? Statemachine::StateBuilder
136
+ # Its parent is not a superstate yet
137
+ if @is_parallel and @parallel_state.empty?
138
+ state = Statemachine::SuperstateBuilder.new(@state.last.subject.id, @parallel.subject, @state.last.subject.statemachine)
139
+ else
98
140
  state = Statemachine::SuperstateBuilder.new(@state.last.subject.id, @state.last.subject.superstate, @state.last.subject.statemachine)
99
- @state.pop # pops the old one
100
- @state.push(state) # pushes the new one
101
- if @is_parallel
102
- @parallel_state.pop
103
- @parallel_state.push(state)
104
- end
105
141
  end
106
- state = Statemachine::StateBuilder.new(attributes['id'].to_sym, @state.last.subject, @statemachine)
142
+ @state.pop # pops the old one
143
+ @state.push(state) # pushes the new one
144
+ if @is_parallel
145
+ @parallel_state.pop
146
+ @parallel_state.push(state)
147
+ end
148
+ end
149
+ if @current_state.initial != nil
150
+ # and it is a superstate
151
+ if @is_parallel and @parallel_state.empty?
152
+ state = Statemachine::SuperstateBuilder.new(attributes['id'].to_sym, @parallel.subject, @statemachine)
153
+ else
154
+ state = Statemachine::SuperstateBuilder.new(attributes['id'].to_sym, @state.last.subject, @statemachine)
155
+ end
156
+ state.startstate(@current_state.initial.to_sym)
157
+ else
158
+ # and it is a state
159
+ if @is_parallel and @parallel_state.empty?
160
+ state = Statemachine::StateBuilder.new(attributes['id'].to_sym, @parallel.subject, @statemachine)
161
+ else
162
+ state = Statemachine::StateBuilder.new(attributes['id'].to_sym, @state.last.subject, @statemachine)
163
+ end
107
164
  end
108
165
  end
109
166
  @state.push(state)
110
167
  @parallel_state.push(state) if @is_parallel
111
168
  when 'transition'
112
169
  @current_transition = Transition.new
113
- @current_transition.event = attributes['event']
114
- @current_transition.target = attributes['target']
170
+ if attributes['target'] == @history_state.to_s and @history_state
171
+ @current_transition.target = attributes['target']+"_H"
172
+ else
173
+ @current_transition.target = attributes['target']
174
+ end
175
+ if attributes['event']
176
+ @current_transition.event = attributes['event']
177
+ else
178
+ @current_transition.event = nil
179
+ end
115
180
  if attributes['cond']
116
181
  @current_transition.cond = attributes['cond']
117
182
  else
@@ -121,74 +186,108 @@ class StatemachineParser < Statemachine::StatemachineBuilder
121
186
  when 'onentry'
122
187
  when 'onexit'
123
188
  when 'history'
124
- @history=true
189
+ @history = true
125
190
  @history_states.push(@state.last.subject.id)
126
191
  @history_state = @state.last.subject.id
192
+ when 'if'
193
+ @if.push(true)
194
+ if @if.size >= 1
195
+ @if_actions_aux.push(@if_actions) if @if_actions.size != 0
196
+ @if_actions = []
197
+ end
198
+ @cond.push(attributes['cond'])
199
+ @tag.push("if")
200
+ when 'elseif'
201
+ creating_ifs
202
+ @cond.push(attributes['cond'])
203
+ @tag.push("elseif")
204
+ when 'else'
205
+ creating_ifs
206
+ @cond.push(true)
207
+ @tag.push("else")
127
208
  when 'log'
128
- @actions.push(["log", attributes['expr']])
209
+ if @if.last
210
+ @if_actions.push(["log", attributes['expr']])
211
+ else
212
+ @actions.push(["log", attributes['expr']])
213
+ end
129
214
  when 'send'
130
- @actions.push(["send", attributes['target'], attributes['event']])
215
+ if @if.last
216
+ @if_actions.push(["send", attributes['target'], attributes['event']])
217
+ else
218
+ @actions.push(["send", attributes['target'], attributes['event']])
219
+ end
131
220
  when 'invoke'
132
- @actions.push(["invoke", attributes['src'].to_sym])
221
+ if @if.last
222
+ @if_actions.push(["invoke", attributes['src'].to_sym])
223
+ else
224
+ @actions.push(["invoke", attributes['src'].to_sym])
225
+ end
226
+ when 'script'
227
+ @script = true
228
+ @script_code = ""
133
229
  else
134
230
  @current_element = name
135
- end
231
+ end
136
232
  end
137
233
 
234
+ # This function defines the actions to be taken for each different tag when the tag is closed
138
235
  def tag_end(name)
139
236
  case name
140
237
  when 'parallel'
141
238
  @statemachine.add_state(@parallel.subject)
142
239
  @is_parallel = false
143
240
  when 'state'
144
- if (@state.last.is_a? Statemachine::SuperstateBuilder)
241
+ if @state.last.is_a? Statemachine::SuperstateBuilder
145
242
  s = statemachine.get_state(@state.last.subject.id)
146
243
 
147
- # Changing the state's id
148
244
  if (s.id == @history_state)
149
- s.id = (s.id.to_s + "_H").to_sym
150
- s.default_history=@history_target.last.to_sym
151
- @history_target.pop
245
+ if @history_target.last
246
+ s.default_history = @history_target.last.to_sym
247
+ @history_target.pop
248
+ end
152
249
  end
153
250
 
154
- # Adds the superstate's transitions to all its substates
155
- @substate.each{|j|
156
- if (s)
251
+ # Every state belonging to this superstate should respond to the superstate's transitions
252
+ @substate.each do |j|
253
+ if s
157
254
  s1 = statemachine.get_state(j.subject.id)
158
- s.transitions.each {|v,k|
159
- if (s1)
160
- s1.add(k)
161
- end
162
- }
255
+ s.transitions.each do |k|
256
+ s1.add(k) if s1
257
+ end
163
258
  end
164
- }
259
+ end
165
260
  end
261
+
166
262
  # In case of parallel statemachines the outmost states will become parallel statemachines
167
263
  # only considering parallel on a root level
168
-
169
264
  if @parallel_state.size == 1 and @parallel.is_a? Statemachine::ParallelStateBuilder
170
- statemachine_aux = Statemachine::Statemachine.new(@parallel_state.last.subject)
265
+ statemachine_aux = Statemachine::Statemachine.new(@parallel.subject)
266
+ statemachine_aux.add_state(@parallel_state.last.subject)
267
+ @statemachine.remove_state(@parallel_state.last.subject)
171
268
  @substate.each do |j|
269
+ j.subject.modify_statemachine(statemachine_aux)
172
270
  statemachine_aux.add_state(j.subject)
173
271
  @statemachine.remove_state(j.subject)
174
272
  end
175
- statemachine_aux.reset
273
+ #statemachine_aux.reset
176
274
  @parallel.subject.add_statemachine(statemachine_aux)
177
275
  end
276
+
178
277
  @substate.push(@state.last)
179
278
 
180
279
  if (@state.size == 1 and not @scxml_state) or (@state.size == 2 and @scxml_state) or (@parallel_state.size == 1)
181
280
  @substate = []
182
281
  # TODO make this better. Too inefficient
183
- while (!(@history_states.size == 0))
282
+ while @history_states.size != 0
184
283
  # change every transitions where @history_states.last was the target state to history_states.last+"_H"
185
284
  # for every history state
186
285
  @statemachine.states.each_value do |s|
187
- s.transitions.each_value do |t|
188
- if (t.destination_id == @history_states.last)
189
- t.destination_id = (t.destination_id.to_s + "_H").to_s
190
- end
191
- end
286
+ s.transitions.each do |t|
287
+ if t.destination_id == @history_states.last
288
+ t.destination_id = (t.destination_id.to_s + "_H").to_s
289
+ end
290
+ end
192
291
  end
193
292
  @history_states.pop
194
293
  end
@@ -196,30 +295,69 @@ class StatemachineParser < Statemachine::StatemachineBuilder
196
295
  @state.pop
197
296
  @parallel_state.pop if @is_parallel
198
297
  when 'transition'
199
- if (@transitions.last.event == nil)
298
+ if @transitions.last.event == nil
200
299
  if @history
201
300
  @history_target.push(@transitions.last.target)
202
301
  @history = false
203
302
  else
204
- # TODO spontaneous transitions
303
+ if @is_parallel and @parallel_state.empty?
304
+ @parallel.event(nil, @transitions.last.target.to_sym, @actions, @transitions.last.cond)
305
+ else
306
+ @state.last.event(nil, @transitions.last.target.to_sym, @actions, @transitions.last.cond)
307
+ end
205
308
  end
206
309
  else
207
- if (@transitions.last.target != nil) # if it has a target state
208
- @state.last.event(@transitions.last.event.to_sym, @transitions.last.target.to_sym, @actions, @transitions.last.cond)
209
- else # it is its own target state
210
- @state.last.event(@transitions.last.event.to_sym, @state.last.subject.id.to_sym, @actions, @transitions.last.cond)
310
+ if @transitions.last.target != nil
311
+ if @is_parallel and @parallel_state.empty?
312
+ @parallel.event(@transitions.last.event.to_sym, @transitions.last.target.to_sym, @actions, @transitions.last.cond)
313
+ else
314
+ @state.last.event(@transitions.last.event.to_sym, @transitions.last.target.to_sym, @actions, @transitions.last.cond)
315
+ end
316
+ else
317
+ # if it doesn't have a target state, it is its own target state
318
+ if @is_parallel and @parallel_state.empty?
319
+ @parallel.event(@transitions.last.event.to_sym, @state.last.subject.id.to_sym, @actions, @transitions.last.cond)
320
+ else
321
+ @state.last.event(@transitions.last.event.to_sym, @state.last.subject.id.to_sym, @actions, @transitions.last.cond)
322
+ end
211
323
  end
212
324
  end
213
325
  @actions=[]
214
326
  @transitions.pop
215
327
  when 'onentry'
216
- @state.last.on_entry(@actions)
328
+ if @is_parallel and @parallel_state.empty?
329
+ @parallel.on_entry(@actions)
330
+ else
331
+ @state.last.on_entry(@actions)
332
+ end
217
333
  @actions=[]
218
334
  when 'onexit'
219
- @state.last.on_exit(@actions)
335
+ if @is_parallel and @parallel_state.empty?
336
+ @parallel.on_exit(@actions)
337
+ else
338
+ @state.last.on_exit(@actions)
339
+ end
220
340
  @actions=[]
221
341
  when 'history'
222
342
  @history = false
343
+ when 'if'
344
+ creating_ifs
345
+ @if.pop
346
+ when 'script'
347
+ @script = false
348
+ if @if.last
349
+ @if_actions.push(["script", @script_code])
350
+ else
351
+ @actions.push(["script", @script_code])
352
+ end
353
+ else
354
+
355
+ end
356
+ end
357
+
358
+ def text(text)
359
+ if @script
360
+ @script_code += text
223
361
  end
224
362
  end
225
363