redshift 1.3.15
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.
- data/.gitignore +8 -0
- data/README +5 -0
- data/RELEASE-NOTES +455 -0
- data/TODO +431 -0
- data/bench/alg-state.rb +61 -0
- data/bench/bench +26 -0
- data/bench/bench.rb +10 -0
- data/bench/continuous.rb +76 -0
- data/bench/diff-bench +86 -0
- data/bench/discrete.rb +101 -0
- data/bench/euler.rb +50 -0
- data/bench/formula.rb +78 -0
- data/bench/half-strict.rb +103 -0
- data/bench/inertness.rb +116 -0
- data/bench/queue.rb +92 -0
- data/bench/run +66 -0
- data/bench/simple.rb +74 -0
- data/bench/strictness.rb +86 -0
- data/examples/ball-tkar.rb +72 -0
- data/examples/ball.rb +123 -0
- data/examples/collide.rb +70 -0
- data/examples/connect-parallel.rb +48 -0
- data/examples/connect.rb +109 -0
- data/examples/constants.rb +27 -0
- data/examples/delay.rb +80 -0
- data/examples/derivative.rb +77 -0
- data/examples/euler.rb +46 -0
- data/examples/external-lib.rb +33 -0
- data/examples/guard-debugger.rb +77 -0
- data/examples/lotka-volterra.rb +33 -0
- data/examples/persist-ball.rb +68 -0
- data/examples/pid.rb +87 -0
- data/examples/ports.rb +60 -0
- data/examples/queue.rb +56 -0
- data/examples/queue2.rb +98 -0
- data/examples/reset-with-event-val.rb +28 -0
- data/examples/scheduler.rb +104 -0
- data/examples/set-dest.rb +23 -0
- data/examples/simulink/README +1 -0
- data/examples/simulink/delay.mdl +827 -0
- data/examples/simulink/derivative.mdl +655 -0
- data/examples/step-discrete-profiler.rb +103 -0
- data/examples/subsystem.rb +109 -0
- data/examples/sync-deadlock.rb +32 -0
- data/examples/sync-queue.rb +91 -0
- data/examples/sync-retry.rb +20 -0
- data/examples/sync.rb +51 -0
- data/examples/thermostat.rb +53 -0
- data/examples/zeno.rb +53 -0
- data/lib/accessible-index.rb +47 -0
- data/lib/redshift.rb +1 -0
- data/lib/redshift/component.rb +412 -0
- data/lib/redshift/meta.rb +183 -0
- data/lib/redshift/mixins/zeno-debugger.rb +69 -0
- data/lib/redshift/port.rb +57 -0
- data/lib/redshift/queue.rb +104 -0
- data/lib/redshift/redshift.rb +111 -0
- data/lib/redshift/state.rb +31 -0
- data/lib/redshift/syntax.rb +558 -0
- data/lib/redshift/target/c.rb +37 -0
- data/lib/redshift/target/c/component-gen.rb +1303 -0
- data/lib/redshift/target/c/flow-gen.rb +325 -0
- data/lib/redshift/target/c/flow/algebraic.rb +85 -0
- data/lib/redshift/target/c/flow/buffer.rb +74 -0
- data/lib/redshift/target/c/flow/delay.rb +203 -0
- data/lib/redshift/target/c/flow/derivative.rb +101 -0
- data/lib/redshift/target/c/flow/euler.rb +67 -0
- data/lib/redshift/target/c/flow/expr.rb +113 -0
- data/lib/redshift/target/c/flow/rk4.rb +80 -0
- data/lib/redshift/target/c/library.rb +85 -0
- data/lib/redshift/target/c/world-gen.rb +1370 -0
- data/lib/redshift/target/spec.rb +34 -0
- data/lib/redshift/world.rb +300 -0
- data/rakefile +37 -0
- data/test/test.rb +52 -0
- data/test/test_buffer.rb +58 -0
- data/test/test_connect.rb +242 -0
- data/test/test_connect_parallel.rb +47 -0
- data/test/test_connect_strict.rb +135 -0
- data/test/test_constant.rb +74 -0
- data/test/test_delay.rb +145 -0
- data/test/test_derivative.rb +48 -0
- data/test/test_discrete.rb +592 -0
- data/test/test_discrete_isolated.rb +92 -0
- data/test/test_exit.rb +59 -0
- data/test/test_flow.rb +200 -0
- data/test/test_flow_link.rb +288 -0
- data/test/test_flow_sub.rb +100 -0
- data/test/test_flow_trans.rb +292 -0
- data/test/test_inherit.rb +127 -0
- data/test/test_inherit_event.rb +74 -0
- data/test/test_inherit_flow.rb +139 -0
- data/test/test_inherit_link.rb +65 -0
- data/test/test_inherit_setup.rb +56 -0
- data/test/test_inherit_state.rb +66 -0
- data/test/test_inherit_transition.rb +168 -0
- data/test/test_numerics.rb +34 -0
- data/test/test_queue.rb +90 -0
- data/test/test_queue_alone.rb +115 -0
- data/test/test_reset.rb +209 -0
- data/test/test_setup.rb +119 -0
- data/test/test_strict_continuity.rb +410 -0
- data/test/test_strict_reset_error.rb +30 -0
- data/test/test_strictness_error.rb +32 -0
- data/test/test_sync.rb +185 -0
- data/test/test_world.rb +328 -0
- metadata +204 -0
data/examples/zeno.rb
ADDED
@@ -0,0 +1,53 @@
|
|
1
|
+
require "redshift"
|
2
|
+
|
3
|
+
include RedShift
|
4
|
+
|
5
|
+
class Z < Component
|
6
|
+
state :A, :B
|
7
|
+
start A
|
8
|
+
transition A => B, B => A do
|
9
|
+
guard {puts "in guard clause: #{self.inspect}"; true}
|
10
|
+
action {puts "in action clause: #{self.inspect}"}
|
11
|
+
end
|
12
|
+
end
|
13
|
+
|
14
|
+
class ZWorld < World
|
15
|
+
# RedShift::ZenoDebugger already has a useful implementation of report_zeno,
|
16
|
+
# but we can augment its non-interactive output by adding an interactive
|
17
|
+
# debugging shell.
|
18
|
+
include ZenoDebugger
|
19
|
+
|
20
|
+
def report_zeno
|
21
|
+
super # the normal zeno output
|
22
|
+
|
23
|
+
unless @zeno_shell_started
|
24
|
+
require 'irb-shell'
|
25
|
+
puts
|
26
|
+
puts "Zeno debugger shell"
|
27
|
+
puts "^D to continue to next zeno step (^Z and Return on Windows)"
|
28
|
+
puts "'exit' to exit"
|
29
|
+
puts "Variable 'z' has the suspect object."
|
30
|
+
puts
|
31
|
+
@zeno_shell_started = true
|
32
|
+
end
|
33
|
+
|
34
|
+
z = curr_T[0] ###zeno_watch_list[0]
|
35
|
+
IRB.start_session(binding, self)
|
36
|
+
|
37
|
+
end
|
38
|
+
end
|
39
|
+
|
40
|
+
world = ZWorld.new
|
41
|
+
|
42
|
+
world.zeno_limit = 10
|
43
|
+
#world.zeno_limit = ZENO_UNLIMITED # don't check for zeno
|
44
|
+
|
45
|
+
world.debug_zeno = true
|
46
|
+
# After zeno_limit steps, RedShift starts calling world.step_zeno
|
47
|
+
|
48
|
+
world.debug_zeno_limit = ZENO_UNLIMITED
|
49
|
+
# The user is in control for as long as the user wants to be.
|
50
|
+
|
51
|
+
world.create(Z)
|
52
|
+
|
53
|
+
world.step 1
|
@@ -0,0 +1,47 @@
|
|
1
|
+
module AccessibleIndex
|
2
|
+
def index_accessor(h)
|
3
|
+
h.each do |sym, idx|
|
4
|
+
define_method sym do
|
5
|
+
self[idx]
|
6
|
+
end
|
7
|
+
define_method "#{sym}=" do |val|
|
8
|
+
self[idx] = val
|
9
|
+
end
|
10
|
+
end
|
11
|
+
end
|
12
|
+
|
13
|
+
def index_reader(h)
|
14
|
+
h.each do |sym, idx|
|
15
|
+
define_method sym do
|
16
|
+
self[idx]
|
17
|
+
end
|
18
|
+
end
|
19
|
+
end
|
20
|
+
|
21
|
+
def index_writer(h)
|
22
|
+
h.each do |sym, idx|
|
23
|
+
define_method "#{sym}=" do |val|
|
24
|
+
self[idx] = val
|
25
|
+
end
|
26
|
+
end
|
27
|
+
end
|
28
|
+
end
|
29
|
+
|
30
|
+
if __FILE__ == $0
|
31
|
+
|
32
|
+
class TestArray < Array
|
33
|
+
extend AccessibleIndex
|
34
|
+
|
35
|
+
index_accessor :a => 3, :b => 7
|
36
|
+
end
|
37
|
+
|
38
|
+
ta = TestArray[0,1,2,3,4,5,6,7,8,9,10]#.new((0..10).to_a)
|
39
|
+
|
40
|
+
p ta
|
41
|
+
|
42
|
+
ta.a = "three"
|
43
|
+
ta.b = "seven"
|
44
|
+
|
45
|
+
p ta
|
46
|
+
|
47
|
+
end
|
data/lib/redshift.rb
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
require 'redshift/redshift'
|
@@ -0,0 +1,412 @@
|
|
1
|
+
require 'singleton'
|
2
|
+
require 'superhash'
|
3
|
+
require 'accessible-index'
|
4
|
+
require 'redshift/state'
|
5
|
+
require 'redshift/meta'
|
6
|
+
require 'redshift/port'
|
7
|
+
require 'redshift/queue'
|
8
|
+
|
9
|
+
module RedShift
|
10
|
+
|
11
|
+
# Can be raised with a [msg, object] pair instead of just a msg string.
|
12
|
+
# In the former case, the +object+ is accessible.
|
13
|
+
module AugmentedException
|
14
|
+
attr_reader :object
|
15
|
+
|
16
|
+
def initialize(*msg)
|
17
|
+
if msg.empty?
|
18
|
+
super; return
|
19
|
+
end
|
20
|
+
|
21
|
+
msg = msg.first if msg.size == 1
|
22
|
+
if defined?(msg.first)
|
23
|
+
msg, @object = *msg
|
24
|
+
s = ((@object.inspect rescue
|
25
|
+
@object.to_s) rescue
|
26
|
+
"id ##{@object.object_id} of class #{@object.class}")
|
27
|
+
msg += " Object is: $!.object == #{s}"
|
28
|
+
end
|
29
|
+
super msg
|
30
|
+
end
|
31
|
+
end
|
32
|
+
|
33
|
+
# For convenience only; not all redshift error classes derive from this.
|
34
|
+
class RedShiftError < StandardError
|
35
|
+
include AugmentedException
|
36
|
+
end
|
37
|
+
|
38
|
+
class AlgebraicAssignmentError < RedShiftError; end
|
39
|
+
class NilLinkError < RedShiftError; end
|
40
|
+
class LinkTypeError < TypeError; include AugmentedException; end
|
41
|
+
class VarTypeError < TypeError; include AugmentedException; end
|
42
|
+
class CircularDefinitionError < RedShiftError; end
|
43
|
+
class StrictnessError < RedShiftError; end
|
44
|
+
class ConstnessError < RedShiftError; end
|
45
|
+
class TransitionError < RedShiftError; end
|
46
|
+
class SyntaxError < ::SyntaxError; end
|
47
|
+
class UnconnectedInputError < RedShiftError; end
|
48
|
+
class NoValueError < RedShiftError; end
|
49
|
+
|
50
|
+
# Raised when a component tries to perform an action that makes sense only
|
51
|
+
# during initialization.
|
52
|
+
class AlreadyStarted < RedShiftError; end
|
53
|
+
|
54
|
+
# These classes are derived from Array for efficient access to contents
|
55
|
+
# from C code.
|
56
|
+
class XArray < Array
|
57
|
+
def inspect; "<#{self.class.name.split("::")[-1]}: #{super[1..-2]}>"; end
|
58
|
+
end
|
59
|
+
|
60
|
+
class Transition < XArray ## put this in meta?
|
61
|
+
attr_reader :name
|
62
|
+
|
63
|
+
extend AccessibleIndex
|
64
|
+
G_IDX, S_IDX, A_IDX, R_IDX, E_IDX, P_IDX, C_IDX = *0..10
|
65
|
+
index_accessor \
|
66
|
+
:guard => G_IDX, :sync => S_IDX, :action => A_IDX,
|
67
|
+
:reset => R_IDX, :event => E_IDX, :post => P_IDX,
|
68
|
+
:connect => C_IDX
|
69
|
+
|
70
|
+
def initialize spec
|
71
|
+
if spec.kind_of? Hash
|
72
|
+
spec = spec.dup
|
73
|
+
def spec.method_missing(m, *); self[m]; end
|
74
|
+
end
|
75
|
+
|
76
|
+
@name = spec.name || "transition_#{object_id}".intern
|
77
|
+
self.guard = spec.guards; self.sync = spec.syncs
|
78
|
+
self.action = spec.actions; self.reset = spec.resets
|
79
|
+
self.event = spec.events; self.post = spec.posts
|
80
|
+
self.connect = spec.connects
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
class Flow ## rename to equation? formula? put in meta?
|
85
|
+
attr_reader :var, :formula
|
86
|
+
|
87
|
+
# Strict flows change value only over continuous time, and not within the
|
88
|
+
# steps of the discrete update. This can be false only for an AlgebraicFlow
|
89
|
+
# which depends on non-strict variables. In the algebraic case, a flow is
|
90
|
+
# strict iff the RHS of the eqn. has only strictly continuous variables.
|
91
|
+
attr_reader :strict
|
92
|
+
|
93
|
+
def initialize v, f
|
94
|
+
@var, @formula = v, f
|
95
|
+
@strict = true
|
96
|
+
self.class.needed = true
|
97
|
+
end
|
98
|
+
|
99
|
+
class << self; attr_accessor :needed; end
|
100
|
+
end
|
101
|
+
|
102
|
+
class AlgebraicFlow < Flow; end
|
103
|
+
class EulerDifferentialFlow < Flow; end
|
104
|
+
class RK4DifferentialFlow < Flow; end
|
105
|
+
|
106
|
+
class DerivativeFlow < Flow
|
107
|
+
attr_reader :feedback
|
108
|
+
def initialize v, f, feedback
|
109
|
+
super(v, f)
|
110
|
+
@feedback = feedback
|
111
|
+
end
|
112
|
+
end
|
113
|
+
|
114
|
+
class DelayFlow < Flow
|
115
|
+
attr_reader :delay_by
|
116
|
+
def initialize v, f, delay_by
|
117
|
+
super(v, f)
|
118
|
+
@delay_by = delay_by
|
119
|
+
end
|
120
|
+
end
|
121
|
+
|
122
|
+
class CexprGuard < Flow; end ## Kinda funny...
|
123
|
+
class Expr < Flow; end ## Kinda funny...
|
124
|
+
|
125
|
+
Always = Transition.new :name => :Always, :guard => nil
|
126
|
+
|
127
|
+
class Component
|
128
|
+
|
129
|
+
attr_reader :start_state
|
130
|
+
attr_accessor :name
|
131
|
+
|
132
|
+
attach_state(:Enter)
|
133
|
+
attach_state(:Exit)
|
134
|
+
|
135
|
+
class GuardPhase < XArray; end
|
136
|
+
class SyncPhase < XArray; end
|
137
|
+
class ActionPhase < XArray; end
|
138
|
+
class PostPhase < XArray; end
|
139
|
+
class EventPhase < XArray; end
|
140
|
+
class ResetPhase < XArray
|
141
|
+
attr_accessor :value_map
|
142
|
+
def inspect
|
143
|
+
"<ResetPhase: #{value_map.inspect}>"
|
144
|
+
end
|
145
|
+
end
|
146
|
+
class QMatch < XArray; end
|
147
|
+
class ConnectPhase < XArray; end
|
148
|
+
|
149
|
+
class PhaseItem < XArray; extend AccessibleIndex; end
|
150
|
+
|
151
|
+
class SyncPhaseItem < PhaseItem
|
152
|
+
LINK_NAME_IDX, LINK_OFFSET_IDX, EVENT_IDX = *0..2
|
153
|
+
index_accessor :link_name => LINK_NAME_IDX,
|
154
|
+
:link_offset => LINK_OFFSET_IDX, :event => EVENT_IDX
|
155
|
+
def inspect; "<Sync #{link_name}:#{event}>"; end
|
156
|
+
end
|
157
|
+
|
158
|
+
class EventPhaseItem < PhaseItem
|
159
|
+
E_IDX = 0; V_IDX = 1; I_IDX = 2
|
160
|
+
index_accessor :event => E_IDX, :value => V_IDX, :index => I_IDX
|
161
|
+
|
162
|
+
def value=(val)
|
163
|
+
self[V_IDX] = case val
|
164
|
+
when Proc
|
165
|
+
DynamicEventValue.new(&val)
|
166
|
+
when String
|
167
|
+
ExprEventValue.new val
|
168
|
+
when Literal # e.g., literal "x", or literal {...}
|
169
|
+
val.literal_value
|
170
|
+
else
|
171
|
+
val
|
172
|
+
end
|
173
|
+
end
|
174
|
+
|
175
|
+
def inspect; "<Event #{event}: #{value.inspect}>"; end
|
176
|
+
end
|
177
|
+
|
178
|
+
class DynamicEventValue < Proc; end
|
179
|
+
class ExprEventValue < String; end
|
180
|
+
|
181
|
+
class Literal
|
182
|
+
attr_accessor :literal_value
|
183
|
+
def initialize val; self.literal_value = val; end
|
184
|
+
end
|
185
|
+
def Component.literal val
|
186
|
+
Literal.new val
|
187
|
+
end
|
188
|
+
|
189
|
+
# Unique across all Worlds and Components in the process. Components are
|
190
|
+
# numbered in the order which this method was called on them and not
|
191
|
+
# necessarily in order of creation.
|
192
|
+
def comp_id
|
193
|
+
@comp_id ||= Component.next_comp_id
|
194
|
+
end
|
195
|
+
|
196
|
+
@next_comp_id = -1
|
197
|
+
def Component.next_comp_id
|
198
|
+
@next_comp_id += 1
|
199
|
+
end
|
200
|
+
|
201
|
+
def to_s
|
202
|
+
"<#{self.class} #{name || comp_id}>"
|
203
|
+
end
|
204
|
+
|
205
|
+
VAR_TYPES = [:constant_variables, :continuous_variables, :link_variables,
|
206
|
+
:input_variables]
|
207
|
+
|
208
|
+
def inspect opts = nil
|
209
|
+
old_inspecting = Thread.current[:inspecting]
|
210
|
+
Thread.current[:inspecting] = self
|
211
|
+
if opts
|
212
|
+
float_fmt = opts["float_fmt"]
|
213
|
+
data = opts["data"]
|
214
|
+
end
|
215
|
+
|
216
|
+
items = []
|
217
|
+
|
218
|
+
unless old_inspecting == self
|
219
|
+
# avoids inf. recursion when send(name) raises exception that
|
220
|
+
# calls inspect again.
|
221
|
+
|
222
|
+
if state
|
223
|
+
items << (trans ? "#{state} => #{dest}" : state)
|
224
|
+
end
|
225
|
+
|
226
|
+
VAR_TYPES.each do |var_type|
|
227
|
+
var_list = self.class.send(var_type)
|
228
|
+
unless var_list.empty?
|
229
|
+
strs = var_list.map {|vname,info| vname.to_s}.sort.map do |vname|
|
230
|
+
begin
|
231
|
+
val = send(vname)
|
232
|
+
val = case val
|
233
|
+
when Float
|
234
|
+
float_fmt ? float_fmt % val : val
|
235
|
+
when Component
|
236
|
+
val.to_s
|
237
|
+
else
|
238
|
+
val.inspect
|
239
|
+
end
|
240
|
+
|
241
|
+
"#{vname} = #{val}"
|
242
|
+
|
243
|
+
rescue CircularDefinitionError
|
244
|
+
"#{vname}: CIRCULAR"
|
245
|
+
rescue UnconnectedInputError
|
246
|
+
"#{vname}: UNCONNECTED"
|
247
|
+
rescue NilLinkError
|
248
|
+
"#{vname}: NIL LINK"
|
249
|
+
rescue => ex
|
250
|
+
"#{vname}: #{ex.inspect}"
|
251
|
+
end
|
252
|
+
end
|
253
|
+
items << strs.join(", ")
|
254
|
+
end
|
255
|
+
end
|
256
|
+
|
257
|
+
if trans and (ep=trans.grep(EventPhase).first)
|
258
|
+
strs = ep.map do |item|
|
259
|
+
e = item.event
|
260
|
+
"#{e}: #{send(e).inspect}"
|
261
|
+
end
|
262
|
+
items << strs.join(", ")
|
263
|
+
end
|
264
|
+
|
265
|
+
items << data if data
|
266
|
+
end
|
267
|
+
|
268
|
+
return "<#{[self, items.join("; ")].join(": ")}>"
|
269
|
+
|
270
|
+
ensure
|
271
|
+
Thread.current[:inspecting] = old_inspecting
|
272
|
+
end
|
273
|
+
|
274
|
+
def initialize(world)
|
275
|
+
if $REDSHIFT_DEBUG
|
276
|
+
unless caller[1] =~ /redshift\/world.*`create'\z/ or
|
277
|
+
caller[0] =~ /`initialize'\z/
|
278
|
+
raise ArgumentError, "Components can be created only using " +
|
279
|
+
"the create method of a world.", caller
|
280
|
+
end
|
281
|
+
end
|
282
|
+
|
283
|
+
__set__world world
|
284
|
+
self.var_count = self.class.var_count
|
285
|
+
|
286
|
+
restore {
|
287
|
+
@start_state = Enter
|
288
|
+
self.cont_state = self.class.cont_state_class.new
|
289
|
+
|
290
|
+
do_defaults
|
291
|
+
yield self if block_given?
|
292
|
+
do_setup
|
293
|
+
|
294
|
+
if state
|
295
|
+
raise RuntimeError, "Can't assign to state.\n" +
|
296
|
+
"Occurred in initialization of component of class #{self.class}."
|
297
|
+
end ## is this a useful restriction?
|
298
|
+
|
299
|
+
self.state = @start_state
|
300
|
+
}
|
301
|
+
end
|
302
|
+
|
303
|
+
def restore
|
304
|
+
if respond_to?(:event_values)
|
305
|
+
event_count = self.class.exported_events.size
|
306
|
+
## should cache this size, since it can't change
|
307
|
+
self.event_values = Array.new(event_count)
|
308
|
+
self.next_event_values = Array.new(event_count)
|
309
|
+
|
310
|
+
event_values.freeze
|
311
|
+
next_event_values.freeze ## should do this deeply?
|
312
|
+
end
|
313
|
+
|
314
|
+
yield if block_given?
|
315
|
+
|
316
|
+
if state == Exit
|
317
|
+
__set__world nil
|
318
|
+
else
|
319
|
+
init_flags
|
320
|
+
update_cache
|
321
|
+
clear_ck_strict # update_cache leaves these set assuming finishing a trans
|
322
|
+
end
|
323
|
+
end
|
324
|
+
|
325
|
+
def do_defaults
|
326
|
+
self.class.do_defaults self
|
327
|
+
end
|
328
|
+
private :do_defaults
|
329
|
+
|
330
|
+
def do_setup
|
331
|
+
self.class.do_setup self
|
332
|
+
end
|
333
|
+
private :do_setup
|
334
|
+
|
335
|
+
def self.do_assignment_map instance, h
|
336
|
+
## could be done in c code
|
337
|
+
h.each do |writer, val|
|
338
|
+
instance.send writer, val
|
339
|
+
end
|
340
|
+
end
|
341
|
+
|
342
|
+
def self.do_defaults instance
|
343
|
+
superclass.do_defaults instance if superclass.respond_to? :do_defaults
|
344
|
+
do_assignment_map instance, @defaults_map if @defaults_map
|
345
|
+
if @defaults_procs
|
346
|
+
@defaults_procs.each do |pr|
|
347
|
+
instance.instance_eval(&pr)
|
348
|
+
end
|
349
|
+
end
|
350
|
+
end
|
351
|
+
|
352
|
+
def self.do_setup instance
|
353
|
+
## should be possible to turn off superclass's setup so that
|
354
|
+
## it can be overridden. 'nosupersetup'? explicit 'super'?
|
355
|
+
superclass.do_setup instance if superclass.respond_to? :do_setup
|
356
|
+
do_assignment_map instance, @setup_map if @setup_map
|
357
|
+
if @setup_procs
|
358
|
+
@setup_procs.each do |pr|
|
359
|
+
instance.instance_eval(&pr)
|
360
|
+
end
|
361
|
+
end
|
362
|
+
end
|
363
|
+
|
364
|
+
## shouldn't be necessary
|
365
|
+
def insteval_proc pr
|
366
|
+
instance_eval(&pr)
|
367
|
+
end
|
368
|
+
|
369
|
+
def disconnect input_var
|
370
|
+
connect(input_var, nil, nil)
|
371
|
+
end
|
372
|
+
|
373
|
+
# +var_name+ can be a input var, a continuous var, or a constant var.
|
374
|
+
def port var_name
|
375
|
+
return nil unless var_name
|
376
|
+
@ports ||= {}
|
377
|
+
@ports[var_name] ||= begin
|
378
|
+
var_name = var_name.to_sym
|
379
|
+
|
380
|
+
if self.class.input_variables.key? var_name
|
381
|
+
Port.new(self, var_name, true)
|
382
|
+
elsif self.class.continuous_variables.key? var_name or
|
383
|
+
self.class.constant_variables.key? var_name
|
384
|
+
Port.new(self, var_name, false)
|
385
|
+
else
|
386
|
+
raise "No variable #{var_name.inspect} in #{self.class.inspect}"
|
387
|
+
end
|
388
|
+
end
|
389
|
+
end
|
390
|
+
|
391
|
+
def inc_queue_ready_count
|
392
|
+
if @queue_ready_count == 0 || !@queue_ready_count
|
393
|
+
@queue_ready_count = 1
|
394
|
+
if world.queue_sleep.delete(self)
|
395
|
+
world.awake << self
|
396
|
+
end
|
397
|
+
else
|
398
|
+
@queue_ready_count += 1
|
399
|
+
end
|
400
|
+
end
|
401
|
+
|
402
|
+
def dec_queue_ready_count
|
403
|
+
@queue_ready_count -= 1
|
404
|
+
end
|
405
|
+
end
|
406
|
+
|
407
|
+
# The asymmetry between these two states is that components in Enter are active
|
408
|
+
# in the continuous and discrete updates. Components in Exit do not evolve.
|
409
|
+
Enter = Component::Enter
|
410
|
+
Exit = Component::Exit
|
411
|
+
|
412
|
+
end
|