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
@@ -0,0 +1,183 @@
|
|
1
|
+
module RedShift
|
2
|
+
|
3
|
+
class Component
|
4
|
+
|
5
|
+
class_superhash2 :flows
|
6
|
+
class_superhash :exported_events # :event => index
|
7
|
+
class_superhash :states
|
8
|
+
class_superhash :continuous_variables, :constant_variables
|
9
|
+
class_superhash :link_variables # :link_name => [type, strictness]
|
10
|
+
class_superhash :input_variables # :var_name => :piecewise | :strict
|
11
|
+
class_superhash :queues
|
12
|
+
|
13
|
+
@subclasses = []
|
14
|
+
|
15
|
+
class << self
|
16
|
+
# Component is abstract, and not included in subclasses. This returns nil
|
17
|
+
# when called on subs.
|
18
|
+
attr_reader :subclasses
|
19
|
+
|
20
|
+
def inherited(sub)
|
21
|
+
Component.subclasses << sub
|
22
|
+
end
|
23
|
+
|
24
|
+
# Declare +events+ to be exported (optional). Returns array of corresponding
|
25
|
+
# event indexes which can be used in code generation.
|
26
|
+
def export(*events)
|
27
|
+
events.map do |event|
|
28
|
+
exported_events[event.to_sym] ||= exported_events.size
|
29
|
+
end
|
30
|
+
end
|
31
|
+
|
32
|
+
def queue(*var_names)
|
33
|
+
var_names.each do |var_name|
|
34
|
+
next if queues[var_name]
|
35
|
+
queues[var_name] = true
|
36
|
+
class_eval %{
|
37
|
+
def #{var_name}
|
38
|
+
@#{var_name} ||= Queue.new(self)
|
39
|
+
end
|
40
|
+
}
|
41
|
+
end
|
42
|
+
end
|
43
|
+
|
44
|
+
def attach_link vars, strictness
|
45
|
+
unless not strictness or strictness == :strict
|
46
|
+
raise ArgumentError, "Strictness must be false or :strict"
|
47
|
+
end
|
48
|
+
unless vars.is_a? Hash
|
49
|
+
raise SyntaxError, "Arguments to link must be of form :var => class, " +
|
50
|
+
"where class can be either a Class or a string denoting class name"
|
51
|
+
end
|
52
|
+
vars.each do |var_name, var_type|
|
53
|
+
link_variables[var_name.to_sym] = [var_type, strictness]
|
54
|
+
end
|
55
|
+
end
|
56
|
+
|
57
|
+
def attach_state name
|
58
|
+
state = State.new(name, self)
|
59
|
+
const_set(name, state)
|
60
|
+
states[name] = state
|
61
|
+
end
|
62
|
+
|
63
|
+
def attach states, features
|
64
|
+
if features.class != Array
|
65
|
+
features = [features]
|
66
|
+
end
|
67
|
+
|
68
|
+
case states
|
69
|
+
when Array; attach_flows states, features
|
70
|
+
when Hash; attach_transitions states, features
|
71
|
+
else raise SyntaxError, "Bad state list: #{states.inspect}"
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
def attach_flows states, new_flows
|
76
|
+
states.each do |state|
|
77
|
+
fl = flows(state)
|
78
|
+
for f in new_flows
|
79
|
+
fl[f.var] = f
|
80
|
+
end
|
81
|
+
end
|
82
|
+
end
|
83
|
+
|
84
|
+
def attach_transitions state_pairs, new_transitions
|
85
|
+
new_transitions.delete_if {|t| t.guard && t.guard.any?{|g| g==false}}
|
86
|
+
state_pairs.each do |src, dst|
|
87
|
+
a = own_transitions(src)
|
88
|
+
new_transitions.each do |t|
|
89
|
+
name = t.name
|
90
|
+
a.delete_if {|u,d| u.name == name}
|
91
|
+
a << [t, dst]
|
92
|
+
end
|
93
|
+
end
|
94
|
+
end
|
95
|
+
|
96
|
+
# returns list of transitions from state s in evaluation order
|
97
|
+
# (just the ones defined in this class)
|
98
|
+
def own_transitions(s)
|
99
|
+
@own_transitions ||= {}
|
100
|
+
@own_transitions[s] ||= []
|
101
|
+
end
|
102
|
+
|
103
|
+
def all_transitions(s)
|
104
|
+
if self < Component
|
105
|
+
own_transitions(s) + superclass.all_transitions(s)
|
106
|
+
else
|
107
|
+
own_transitions(s)
|
108
|
+
end
|
109
|
+
end
|
110
|
+
|
111
|
+
def outgoing_transition_data s
|
112
|
+
ary = []
|
113
|
+
all_strict = true
|
114
|
+
seen = {}
|
115
|
+
all_transitions(s).each do |t, d|
|
116
|
+
next if seen[t.name] # overridden in subclass
|
117
|
+
seen[t.name] = true
|
118
|
+
|
119
|
+
t_strict = !t.sync || t.sync.empty?
|
120
|
+
guard_list = t.guard
|
121
|
+
guard_list and guard_list.each do |g|
|
122
|
+
t_strict &&= g.respond_to?(:strict) && g.strict
|
123
|
+
end
|
124
|
+
all_strict &&= t_strict
|
125
|
+
|
126
|
+
ary << [t, d, t.guard, t_strict]
|
127
|
+
end
|
128
|
+
|
129
|
+
result = []
|
130
|
+
ary.reverse_each do |list| # since step_discrete reads them in reverse
|
131
|
+
result.concat list
|
132
|
+
end
|
133
|
+
result << (all_strict ? 1 : 0) # other bits are used elsewhere
|
134
|
+
result
|
135
|
+
end
|
136
|
+
|
137
|
+
def attach_variables(dest, kind, var_names, var_type = nil)
|
138
|
+
if var_names.last.kind_of? Hash
|
139
|
+
h = var_names.pop
|
140
|
+
var_names.concat h.keys.sort_by {|n|n.to_s}
|
141
|
+
defaults h
|
142
|
+
end
|
143
|
+
var_names.each do |var_name|
|
144
|
+
dest[var_name.to_sym] = var_type ? [var_type, kind] : kind
|
145
|
+
end
|
146
|
+
end
|
147
|
+
|
148
|
+
# kind is :strict, :piecewise, or :permissive
|
149
|
+
def attach_continuous_variables(kind, var_names)
|
150
|
+
attach_variables(continuous_variables, kind, var_names)
|
151
|
+
end
|
152
|
+
|
153
|
+
# kind is :strict, :piecewise, or :permissive
|
154
|
+
def attach_constant_variables(kind, var_names)
|
155
|
+
attach_variables(constant_variables, kind, var_names)
|
156
|
+
end
|
157
|
+
|
158
|
+
def attach_input(kind, var_names)
|
159
|
+
var_names.each do |var_name|
|
160
|
+
input_variables[var_name.to_sym] = kind
|
161
|
+
end
|
162
|
+
end
|
163
|
+
|
164
|
+
def find_var_superhash var_name
|
165
|
+
[continuous_variables, constant_variables,
|
166
|
+
link_variables, input_variables].find {|sh| sh[var_name]}
|
167
|
+
end
|
168
|
+
end
|
169
|
+
|
170
|
+
def states
|
171
|
+
self.class.states.values
|
172
|
+
end
|
173
|
+
|
174
|
+
def flows s = state
|
175
|
+
self.class.flows s
|
176
|
+
end
|
177
|
+
|
178
|
+
def transitions s = state
|
179
|
+
self.class.all_transitions s
|
180
|
+
end
|
181
|
+
end # class Component
|
182
|
+
|
183
|
+
end # module RedShift
|
@@ -0,0 +1,69 @@
|
|
1
|
+
class RedShift::World
|
2
|
+
|
3
|
+
# Include this module in a World class. See example in examples/zeno.rb. Has a
|
4
|
+
# very small performance cost, so don't use it in production runs. Note that,
|
5
|
+
# even without ZenoDebugger, RedShift will still detect zeno problems by
|
6
|
+
# raising a ZenoError when world.zeno_counter > world.zeno_limit, if
|
7
|
+
# zeno_limit >= 0.
|
8
|
+
#
|
9
|
+
# ZenoDebugger is compatible with other kinds of debuggers.
|
10
|
+
|
11
|
+
module ZenoDebugger
|
12
|
+
|
13
|
+
# Can be used to turn on and off this module, set to $REDSHIFT_DEBUG_ZENO by
|
14
|
+
# default.
|
15
|
+
attr_accessor :debug_zeno
|
16
|
+
|
17
|
+
# Zeno output goes to this object, $stderr by default, using #<<.
|
18
|
+
attr_accessor :zeno_output
|
19
|
+
|
20
|
+
# Can be used to see which components are causing trouble. Ny default,
|
21
|
+
# the output covers all compontents taking transitions. However, you
|
22
|
+
# can use this attr to focus more narrowly.
|
23
|
+
attr_accessor :zeno_watch_list
|
24
|
+
|
25
|
+
# How many zeno steps before the debugger gives up. Set to ZENO_UNLIMITED to
|
26
|
+
# debug indefinitely, e.g., for interactive mode. By default, equal to 3
|
27
|
+
# times world.zeno_limit, so that batch runs will terminate.
|
28
|
+
attr_accessor :debug_zeno_limit
|
29
|
+
|
30
|
+
def initialize
|
31
|
+
@debug_zeno ||= $REDSHIFT_DEBUG_ZENO
|
32
|
+
@zeno_output ||= $stderr
|
33
|
+
super
|
34
|
+
end
|
35
|
+
|
36
|
+
# This method is called for each discrete step after the zeno_limit has been
|
37
|
+
# exceeded. This implementation is just one possibility, useful for
|
38
|
+
# debugging. One other useful behavior might be to shuffle guards in the
|
39
|
+
# active components.
|
40
|
+
#
|
41
|
+
# In this implementation, when the zeno_counter exceeds zeno_limit, we start
|
42
|
+
# to add active objects to the zeno_watch_list. When the counter exceeds
|
43
|
+
# two times the zeno_limit, we call report_zeno. When the counter exceeds
|
44
|
+
# three times the zeno_limit, we fall back to the super definition of
|
45
|
+
# step_zeno, which is typically to raise a ZenoError.
|
46
|
+
|
47
|
+
def step_zeno
|
48
|
+
self.debug_zeno_limit ||= zeno_limit*3
|
49
|
+
if debug_zeno and
|
50
|
+
(debug_zeno_limit == RedShift::ZENO_UNLIMITED or
|
51
|
+
zeno_counter < debug_zeno_limit)
|
52
|
+
report_zeno if zeno_counter >= 2*zeno_limit
|
53
|
+
else
|
54
|
+
super
|
55
|
+
end
|
56
|
+
end
|
57
|
+
|
58
|
+
HEADER = '-'*10 + " Zeno step: %d; Components: %d; Active: %d " + '-'*10 + "\n"
|
59
|
+
|
60
|
+
# Reports to zeno_output the list of active components.
|
61
|
+
def report_zeno
|
62
|
+
f = zeno_output
|
63
|
+
active = zeno_watch_list || curr_T
|
64
|
+
|
65
|
+
f << HEADER % [zeno_counter, components.size, curr_T.size]
|
66
|
+
f << ' ' + active.map{|c|c.inspect}.join("\n ") + "\n"
|
67
|
+
end
|
68
|
+
end
|
69
|
+
end
|
@@ -0,0 +1,57 @@
|
|
1
|
+
module RedShift; class Component
|
2
|
+
class Port
|
3
|
+
attr_reader :component, :variable, :connectable
|
4
|
+
|
5
|
+
def initialize component, variable, connectable
|
6
|
+
@component, @variable, @connectable = component, variable, connectable
|
7
|
+
end
|
8
|
+
|
9
|
+
# Convenience method to get source port rather than component/var pair.
|
10
|
+
def source
|
11
|
+
source_component && source_component.port(source_variable)
|
12
|
+
end
|
13
|
+
|
14
|
+
def check_connectable
|
15
|
+
unless connectable
|
16
|
+
raise TypeError, "Not an input: #{variable} in #{component.class}"
|
17
|
+
end
|
18
|
+
end
|
19
|
+
|
20
|
+
def connect port
|
21
|
+
check_connectable
|
22
|
+
component.connect(variable, port && port.component, port && port.variable)
|
23
|
+
end
|
24
|
+
|
25
|
+
def _connect port
|
26
|
+
component.connect(variable, port && port.component, port && port.variable, false)
|
27
|
+
end
|
28
|
+
|
29
|
+
def <<(other)
|
30
|
+
connect(other)
|
31
|
+
return other
|
32
|
+
end
|
33
|
+
|
34
|
+
def >>(other)
|
35
|
+
other.connect(self)
|
36
|
+
return other
|
37
|
+
end
|
38
|
+
|
39
|
+
def disconnect
|
40
|
+
connect nil
|
41
|
+
end
|
42
|
+
|
43
|
+
def source_component
|
44
|
+
check_connectable
|
45
|
+
component.source_component_for(variable)
|
46
|
+
end
|
47
|
+
|
48
|
+
def source_variable
|
49
|
+
check_connectable
|
50
|
+
component.source_variable_for(variable)
|
51
|
+
end
|
52
|
+
|
53
|
+
def value
|
54
|
+
component.send variable
|
55
|
+
end
|
56
|
+
end
|
57
|
+
end; end
|
@@ -0,0 +1,104 @@
|
|
1
|
+
module RedShift
|
2
|
+
# a queue entry that contains multiple simultaneously enqueued objects
|
3
|
+
# (same in both continuous and discrete time)
|
4
|
+
class SimultaneousQueueEntries < Array; end
|
5
|
+
|
6
|
+
class Queue
|
7
|
+
# Owner of the queue.
|
8
|
+
attr_reader :component
|
9
|
+
|
10
|
+
def initialize component
|
11
|
+
@q = []
|
12
|
+
@step_count = nil
|
13
|
+
@discrete_step = nil
|
14
|
+
@component = component
|
15
|
+
end
|
16
|
+
|
17
|
+
def push obj
|
18
|
+
world = @component.world
|
19
|
+
step_count = world.step_count
|
20
|
+
discrete_step = world.discrete_step
|
21
|
+
|
22
|
+
if step_count == @step_count and discrete_step == @discrete_step
|
23
|
+
last = @q[-1]
|
24
|
+
case last
|
25
|
+
when SimultaneousQueueEntries
|
26
|
+
last << obj
|
27
|
+
when nil; raise "Internal error: expected simultaneous queue entry."
|
28
|
+
else
|
29
|
+
@q[-1] = SimultaneousQueueEntries[last, obj]
|
30
|
+
end
|
31
|
+
|
32
|
+
else
|
33
|
+
was_empty = @q.empty?
|
34
|
+
@step_count = step_count
|
35
|
+
@discrete_step = discrete_step
|
36
|
+
@q << obj
|
37
|
+
@component.inc_queue_ready_count if was_empty
|
38
|
+
end
|
39
|
+
|
40
|
+
self
|
41
|
+
end
|
42
|
+
|
43
|
+
alias << push
|
44
|
+
|
45
|
+
class QueueEmptyError < StandardError; end
|
46
|
+
|
47
|
+
# When popping from a queue, the result may be an instance
|
48
|
+
# of SimultaneousQueueEntries, which should probably be handled specially.
|
49
|
+
def pop
|
50
|
+
if @q.empty?
|
51
|
+
raise QueueEmptyError, "tried to pop empty queue in #{@component.inspect}"
|
52
|
+
end
|
53
|
+
obj = @q.shift
|
54
|
+
@component.dec_queue_ready_count if @q.empty?
|
55
|
+
obj
|
56
|
+
end
|
57
|
+
|
58
|
+
# Correctly handles case when obj is SimultaneousQueueEntries.
|
59
|
+
def unpop obj
|
60
|
+
was_empty = @q.empty?
|
61
|
+
case obj
|
62
|
+
when SimultaneousQueueEntries
|
63
|
+
case obj.size
|
64
|
+
when 0
|
65
|
+
was_empty = false # just to prevent the inc
|
66
|
+
when 1
|
67
|
+
@q.unshift obj.first
|
68
|
+
else
|
69
|
+
@q.unshift obj
|
70
|
+
end
|
71
|
+
else
|
72
|
+
@q.unshift obj
|
73
|
+
end
|
74
|
+
@component.inc_queue_ready_count if was_empty
|
75
|
+
end
|
76
|
+
|
77
|
+
# Called from guard evaluation in step_discrete. Returns true if at least
|
78
|
+
# one entry in the head of the queue matches _all_ of the conditions, which
|
79
|
+
# may be Procs (called to return boolean) or any objects with #===.
|
80
|
+
def head_matches(*conds)
|
81
|
+
return false if @q.empty?
|
82
|
+
head = @q[0]
|
83
|
+
case head
|
84
|
+
when SimultaneousQueueEntries
|
85
|
+
head.any? do |head_item|
|
86
|
+
item_matches conds, head_item
|
87
|
+
end
|
88
|
+
else
|
89
|
+
item_matches conds, head
|
90
|
+
end
|
91
|
+
end
|
92
|
+
|
93
|
+
def item_matches conds, item
|
94
|
+
conds.all? do |cond|
|
95
|
+
case cond
|
96
|
+
when Proc
|
97
|
+
cond.call(item)
|
98
|
+
else
|
99
|
+
cond === item
|
100
|
+
end
|
101
|
+
end
|
102
|
+
end
|
103
|
+
end
|
104
|
+
end
|
@@ -0,0 +1,111 @@
|
|
1
|
+
# Copyright (C) 2001-2006, Joel VanderWerf
|
2
|
+
# Distributed under the Ruby license. See www.ruby-lang.org.
|
3
|
+
|
4
|
+
# Read all environment variables related to RedShift and store in globals
|
5
|
+
## see importenv.rb for a way to keep these in sync
|
6
|
+
ENV.keys.grep(/RedShift/i) do |key|
|
7
|
+
val = ENV[key] # make eval safe
|
8
|
+
eval "$#{key} = val unless defined? $#{key}"
|
9
|
+
end
|
10
|
+
|
11
|
+
if $REDSHIFT_DEBUG
|
12
|
+
f = $stderr
|
13
|
+
f.puts " ----------------------------------------------------------------- "
|
14
|
+
f.puts " |RedShift debugging information enabled by env var REDSHIFT_DEBUG.|"
|
15
|
+
f.puts " | Please ignore error messages that do not halt the progam. |"
|
16
|
+
f.puts " ----------------------------------------------------------------- "
|
17
|
+
f.puts "\n debug level = #{$REDSHIFT_DEBUG}\n\n" if $REDSHIFT_DEBUG != true
|
18
|
+
|
19
|
+
$REDSHIFT_DEBUG = ($REDSHIFT_DEBUG.to_i rescue 1)
|
20
|
+
end
|
21
|
+
|
22
|
+
class AssertionFailure < StandardError; end
|
23
|
+
class Object ## get rid of this?
|
24
|
+
def assert(test, *msg)
|
25
|
+
raise AssertionFailure, *msg unless test
|
26
|
+
end
|
27
|
+
end
|
28
|
+
|
29
|
+
module Math
|
30
|
+
Infinity = 1.0/0.0 unless defined? Infinity
|
31
|
+
end
|
32
|
+
|
33
|
+
module RedShift
|
34
|
+
include Math
|
35
|
+
|
36
|
+
VERSION = '1.3.15'
|
37
|
+
|
38
|
+
Infinity = Math::Infinity
|
39
|
+
|
40
|
+
def debug setting = true, &block
|
41
|
+
if block
|
42
|
+
begin
|
43
|
+
save_setting = $REDSHIFT_DEBUG
|
44
|
+
$REDSHIFT_DEBUG = setting
|
45
|
+
block.call
|
46
|
+
ensure
|
47
|
+
$REDSHIFT_DEBUG = save_setting
|
48
|
+
end
|
49
|
+
else
|
50
|
+
$REDSHIFT_DEBUG = setting
|
51
|
+
end
|
52
|
+
end
|
53
|
+
|
54
|
+
# Returns a list of all worlds (instances of RedShift::World and subclasses),
|
55
|
+
# or just those descending from +world_class+.
|
56
|
+
# Not very efficient, since it uses <tt>ObjectSpace.each_object</tt>, but
|
57
|
+
# useful in irb.
|
58
|
+
def self.worlds(world_class = World)
|
59
|
+
worlds = []
|
60
|
+
ObjectSpace.each_object(world_class) {|w| worlds << w}
|
61
|
+
worlds
|
62
|
+
end
|
63
|
+
|
64
|
+
# class Warning < Exception; end
|
65
|
+
#
|
66
|
+
# # Warn with string str and skipping n stack frames.
|
67
|
+
# def warn str, n = 0
|
68
|
+
# warning = sprintf "\nWarning: #{str}\n\t#{caller(n).join("\n\t")}\n"
|
69
|
+
# #if $REDSHIFT_DEBUG -- in debug mode, exception is always printed ???
|
70
|
+
# raise Warning, warning
|
71
|
+
# #else
|
72
|
+
# # $stderr.print warning
|
73
|
+
# #end
|
74
|
+
# end
|
75
|
+
# module_function :warn
|
76
|
+
|
77
|
+
@library_calls = []
|
78
|
+
|
79
|
+
# Defer a block until just after the library ruby code is loaded, but before
|
80
|
+
# commit. Necessary for defining inline C functions or shadow_attrs. Note that
|
81
|
+
# a whole require statement could be placed inside the with_library block.
|
82
|
+
def RedShift.with_library(&block) # :yields: library
|
83
|
+
@library_calls << block
|
84
|
+
end
|
85
|
+
|
86
|
+
def RedShift.do_library_calls
|
87
|
+
@library_calls.each do |block|
|
88
|
+
block[library]
|
89
|
+
end
|
90
|
+
end
|
91
|
+
|
92
|
+
def RedShift.require_target
|
93
|
+
require $REDSHIFT_TARGET
|
94
|
+
end
|
95
|
+
|
96
|
+
end # module RedShift
|
97
|
+
|
98
|
+
case $REDSHIFT_TARGET
|
99
|
+
when nil, /^c$/i
|
100
|
+
$REDSHIFT_TARGET = 'redshift/target/c'
|
101
|
+
when /^spec$/i
|
102
|
+
$REDSHIFT_TARGET = 'redshift/target/spec'
|
103
|
+
when /^dot$/i
|
104
|
+
$REDSHIFT_TARGET = 'redshift/target/dot'
|
105
|
+
end
|
106
|
+
|
107
|
+
# There could be other things here... Java, YAML, HSIF, Teja, pure ruby
|
108
|
+
# reference impl. etc. (but procs are a problem for all but ruby)
|
109
|
+
|
110
|
+
require 'redshift/syntax'
|
111
|
+
|