gisele-vm 0.6.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.
Files changed (185) hide show
  1. data/CHANGELOG.md +5 -0
  2. data/Gemfile +18 -0
  3. data/Gemfile.lock +46 -0
  4. data/LICENCE.md +22 -0
  5. data/Manifest.txt +15 -0
  6. data/README.md +10 -0
  7. data/Rakefile +11 -0
  8. data/bin/gvm +9 -0
  9. data/gisele-vm.gemspec +191 -0
  10. data/gisele-vm.noespec +31 -0
  11. data/lib/gisele-vm.rb +4 -0
  12. data/lib/gisele-vm/loader.rb +5 -0
  13. data/lib/gisele-vm/version.rb +16 -0
  14. data/lib/gisele/compiling.rb +3 -0
  15. data/lib/gisele/compiling/gisele2gts.rb +143 -0
  16. data/lib/gisele/compiling/gts.rb +74 -0
  17. data/lib/gisele/compiling/gts2bytecode.rb +127 -0
  18. data/lib/gisele/vm.rb +87 -0
  19. data/lib/gisele/vm/bytecode.rb +84 -0
  20. data/lib/gisele/vm/bytecode/builder.rb +77 -0
  21. data/lib/gisele/vm/bytecode/grammar.citrus +116 -0
  22. data/lib/gisele/vm/bytecode/grammar.rb +19 -0
  23. data/lib/gisele/vm/bytecode/grammar.sexp.yml +113 -0
  24. data/lib/gisele/vm/bytecode/printer.rb +35 -0
  25. data/lib/gisele/vm/command.rb +140 -0
  26. data/lib/gisele/vm/component.rb +91 -0
  27. data/lib/gisele/vm/console.rb +58 -0
  28. data/lib/gisele/vm/enacter.rb +29 -0
  29. data/lib/gisele/vm/errors.rb +26 -0
  30. data/lib/gisele/vm/event.rb +11 -0
  31. data/lib/gisele/vm/event_manager.rb +65 -0
  32. data/lib/gisele/vm/kernel.rb +58 -0
  33. data/lib/gisele/vm/kernel/macros.gvm +214 -0
  34. data/lib/gisele/vm/kernel/opcodes.rb +212 -0
  35. data/lib/gisele/vm/kernel/runner.rb +63 -0
  36. data/lib/gisele/vm/lifecycle.rb +72 -0
  37. data/lib/gisele/vm/logging.rb +18 -0
  38. data/lib/gisele/vm/null_object.rb +19 -0
  39. data/lib/gisele/vm/prog.rb +63 -0
  40. data/lib/gisele/vm/prog_list.rb +55 -0
  41. data/lib/gisele/vm/prog_list/memory.rb +74 -0
  42. data/lib/gisele/vm/prog_list/sqldb.rb +123 -0
  43. data/lib/gisele/vm/prog_list/storage.rb +31 -0
  44. data/lib/gisele/vm/proxy.rb +14 -0
  45. data/lib/gisele/vm/proxy/client.rb +64 -0
  46. data/lib/gisele/vm/proxy/server.rb +29 -0
  47. data/lib/gisele/vm/registry.rb +57 -0
  48. data/lib/gisele/vm/robustness.rb +31 -0
  49. data/lib/gisele/vm/simulator/resumer.rb +32 -0
  50. data/spec/command/gvm_compile.cmd +1 -0
  51. data/spec/command/gvm_compile.stdout +111 -0
  52. data/spec/command/gvm_gts.cmd +1 -0
  53. data/spec/command/gvm_gts.stdout +101 -0
  54. data/spec/command/gvm_help.cmd +1 -0
  55. data/spec/command/gvm_help.stdout +30 -0
  56. data/spec/command/gvm_version.cmd +1 -0
  57. data/spec/command/gvm_version.stdout +2 -0
  58. data/spec/command/test_command.rb +29 -0
  59. data/spec/fixtures/complete.gis +13 -0
  60. data/spec/fixtures/fake_component.rb +24 -0
  61. data/spec/fixtures/kernel.rb +39 -0
  62. data/spec/fixtures/ts.adl +11 -0
  63. data/spec/fixtures/ts.gts +20 -0
  64. data/spec/fixtures/ts.gvm +19 -0
  65. data/spec/spec_helper.rb +86 -0
  66. data/spec/test_examples.rb +29 -0
  67. data/spec/test_gisele-vm.rb +8 -0
  68. data/spec/unit/bytecode/builder/test_at.rb +56 -0
  69. data/spec/unit/bytecode/builder/test_helpers.rb +36 -0
  70. data/spec/unit/bytecode/builder/test_instruction.rb +35 -0
  71. data/spec/unit/bytecode/builder/test_to_a.rb +53 -0
  72. data/spec/unit/bytecode/bytecode.gvm +1 -0
  73. data/spec/unit/bytecode/grammar/fixtures/comments.gvm +16 -0
  74. data/spec/unit/bytecode/grammar/fixtures/every.gvm +46 -0
  75. data/spec/unit/bytecode/grammar/fixtures/singleblock.gvm +2 -0
  76. data/spec/unit/bytecode/grammar/fixtures/twoblocks.gvm +4 -0
  77. data/spec/unit/bytecode/grammar/fixtures/with_end.gvm +5 -0
  78. data/spec/unit/bytecode/grammar/test_array.rb +24 -0
  79. data/spec/unit/bytecode/grammar/test_block.rb +35 -0
  80. data/spec/unit/bytecode/grammar/test_boolean.rb +20 -0
  81. data/spec/unit/bytecode/grammar/test_constant.rb +20 -0
  82. data/spec/unit/bytecode/grammar/test_eol.rb +20 -0
  83. data/spec/unit/bytecode/grammar/test_eol_comment.rb +36 -0
  84. data/spec/unit/bytecode/grammar/test_file.rb +38 -0
  85. data/spec/unit/bytecode/grammar/test_hash.rb +33 -0
  86. data/spec/unit/bytecode/grammar/test_instruction.rb +32 -0
  87. data/spec/unit/bytecode/grammar/test_int.rb +24 -0
  88. data/spec/unit/bytecode/grammar/test_label.rb +24 -0
  89. data/spec/unit/bytecode/grammar/test_opcode.rb +23 -0
  90. data/spec/unit/bytecode/grammar/test_string.rb +25 -0
  91. data/spec/unit/bytecode/grammar/test_symbol.rb +30 -0
  92. data/spec/unit/bytecode/test_build.rb +36 -0
  93. data/spec/unit/bytecode/test_coerce.rb +41 -0
  94. data/spec/unit/bytecode/test_fetch.rb +20 -0
  95. data/spec/unit/bytecode/test_grammar.rb +30 -0
  96. data/spec/unit/bytecode/test_parse.rb +22 -0
  97. data/spec/unit/bytecode/test_plus.rb +27 -0
  98. data/spec/unit/bytecode/test_to_a.rb +19 -0
  99. data/spec/unit/bytecode/test_to_s.rb +32 -0
  100. data/spec/unit/command/code.gis +3 -0
  101. data/spec/unit/command/test_vm.rb +51 -0
  102. data/spec/unit/compiling/gisele2gts/test_on_par_st.rb +51 -0
  103. data/spec/unit/compiling/gisele2gts/test_on_seq_st.rb +46 -0
  104. data/spec/unit/compiling/gisele2gts/test_on_task_call_st.rb +37 -0
  105. data/spec/unit/compiling/gisele2gts/test_on_task_def.rb +49 -0
  106. data/spec/unit/compiling/gisele2gts/test_on_unit_def.rb +35 -0
  107. data/spec/unit/compiling/gts2bytecode/test_on_end.rb +31 -0
  108. data/spec/unit/compiling/gts2bytecode/test_on_event.rb +37 -0
  109. data/spec/unit/compiling/gts2bytecode/test_on_fork.rb +41 -0
  110. data/spec/unit/compiling/gts2bytecode/test_on_join.rb +42 -0
  111. data/spec/unit/compiling/gts2bytecode/test_on_listen.rb +36 -0
  112. data/spec/unit/compiling/gts2bytecode/test_on_nop.rb +30 -0
  113. data/spec/unit/component/test_component_name.rb +16 -0
  114. data/spec/unit/component/test_logging.rb +36 -0
  115. data/spec/unit/enacter/test_component.rb +11 -0
  116. data/spec/unit/event/test_to_s.rb +12 -0
  117. data/spec/unit/event_manager/test_component.rb +9 -0
  118. data/spec/unit/event_manager/test_subscribe.rb +40 -0
  119. data/spec/unit/event_manager/test_unsubscribe.rb +39 -0
  120. data/spec/unit/kernel/macros/test_fork.rb +37 -0
  121. data/spec/unit/kernel/macros/test_join.rb +43 -0
  122. data/spec/unit/kernel/macros/test_listen.rb +37 -0
  123. data/spec/unit/kernel/macros/test_notify.rb +57 -0
  124. data/spec/unit/kernel/macros/test_react.rb +47 -0
  125. data/spec/unit/kernel/macros/test_schedule_at.rb +30 -0
  126. data/spec/unit/kernel/opcodes/test_op_del.rb +42 -0
  127. data/spec/unit/kernel/opcodes/test_op_event.rb +25 -0
  128. data/spec/unit/kernel/opcodes/test_op_fetch.rb +27 -0
  129. data/spec/unit/kernel/opcodes/test_op_flip.rb +17 -0
  130. data/spec/unit/kernel/opcodes/test_op_fold.rb +29 -0
  131. data/spec/unit/kernel/opcodes/test_op_fork.rb +63 -0
  132. data/spec/unit/kernel/opcodes/test_op_forka.rb +51 -0
  133. data/spec/unit/kernel/opcodes/test_op_get.rb +62 -0
  134. data/spec/unit/kernel/opcodes/test_op_getr.rb +48 -0
  135. data/spec/unit/kernel/opcodes/test_op_ifenil.rb +41 -0
  136. data/spec/unit/kernel/opcodes/test_op_ifezero.rb +32 -0
  137. data/spec/unit/kernel/opcodes/test_op_invoke.rb +34 -0
  138. data/spec/unit/kernel/opcodes/test_op_nop.rb +18 -0
  139. data/spec/unit/kernel/opcodes/test_op_parent.rb +39 -0
  140. data/spec/unit/kernel/opcodes/test_op_pop.rb +22 -0
  141. data/spec/unit/kernel/opcodes/test_op_push.rb +17 -0
  142. data/spec/unit/kernel/opcodes/test_op_save.rb +32 -0
  143. data/spec/unit/kernel/opcodes/test_op_savea.rb +34 -0
  144. data/spec/unit/kernel/opcodes/test_op_self.rb +20 -0
  145. data/spec/unit/kernel/opcodes/test_op_send.rb +20 -0
  146. data/spec/unit/kernel/opcodes/test_op_set.rb +61 -0
  147. data/spec/unit/kernel/opcodes/test_op_then.rb +50 -0
  148. data/spec/unit/kernel/opcodes/test_op_unfold.rb +22 -0
  149. data/spec/unit/kernel/opcodes/test_op_uuid.rb +16 -0
  150. data/spec/unit/kernel/runner/test_pop.rb +26 -0
  151. data/spec/unit/kernel/runner/test_stack.rb +28 -0
  152. data/spec/unit/kernel/test_progress.rb +47 -0
  153. data/spec/unit/kernel/test_resume.rb +53 -0
  154. data/spec/unit/kernel/test_start.rb +36 -0
  155. data/spec/unit/prog/test_to_hash.rb +29 -0
  156. data/spec/unit/prog/test_waitlist_eq.rb +20 -0
  157. data/spec/unit/prog_list/memory/test_component.rb +9 -0
  158. data/spec/unit/prog_list/memory/test_fetch.rb +40 -0
  159. data/spec/unit/prog_list/memory/test_pick.rb +39 -0
  160. data/spec/unit/prog_list/memory/test_save.rb +91 -0
  161. data/spec/unit/prog_list/memory/test_to_relation.rb +17 -0
  162. data/spec/unit/prog_list/sqldb/test_component.rb +11 -0
  163. data/spec/unit/prog_list/sqldb/test_connect.rb +46 -0
  164. data/spec/unit/prog_list/test_memory.rb +9 -0
  165. data/spec/unit/prog_list/test_sqldb.rb +13 -0
  166. data/spec/unit/prog_list/test_storage.rb +51 -0
  167. data/spec/unit/registry/test_component.rb +9 -0
  168. data/spec/unit/registry/test_connect.rb +53 -0
  169. data/spec/unit/registry/test_disconnect.rb +51 -0
  170. data/spec/unit/registry/test_registration.rb +44 -0
  171. data/spec/unit/shared/a_component.rb +49 -0
  172. data/spec/unit/shared/a_storage.rb +114 -0
  173. data/spec/unit/test_logging.rb +46 -0
  174. data/spec/unit/test_prog.rb +57 -0
  175. data/spec/unit/test_prog_list.rb +22 -0
  176. data/spec/unit/vm/test_event_facace.rb +11 -0
  177. data/spec/unit/vm/test_initialize.rb +59 -0
  178. data/spec/unit/vm/test_proglist_facade.rb +21 -0
  179. data/tasks/debug_mail.rake +75 -0
  180. data/tasks/debug_mail.txt +13 -0
  181. data/tasks/gem.rake +73 -0
  182. data/tasks/spec_test.rake +71 -0
  183. data/tasks/unit_test.rake +76 -0
  184. data/tasks/yard.rake +51 -0
  185. metadata +493 -0
@@ -0,0 +1,74 @@
1
+ module Gisele
2
+ module Compiling
3
+ class Gts < Stamina::Automaton
4
+
5
+ class Equivalence < Stamina::Automaton::Equivalence
6
+
7
+ def equivalent_states?(s, t)
8
+ super && (s.data == t.data)
9
+ end
10
+
11
+ def equivalent_edges?(e, f)
12
+ super && (e.data == f.data)
13
+ end
14
+ end
15
+
16
+ def to_dot
17
+ dotter = lambda{|elm,kind|
18
+ case kind
19
+ when :automaton
20
+ { :rankdir => "LR" }
21
+ when :state
22
+ { :label => state_label(elm),
23
+ :shape => state_shape(elm),
24
+ :fixedsize => "true",
25
+ :width => "0.6",
26
+ :style => "filled",
27
+ :fillcolor => state_color(elm) }
28
+ when :edge
29
+ { :label => edge_label(elm) }
30
+ end
31
+ }
32
+ super(false, &dotter)
33
+ end
34
+
35
+ def bytecode_equivalent!(other)
36
+ raise "Not DFA equivalent" unless Equivalence.new.call(self, other)
37
+ true
38
+ end
39
+
40
+ private
41
+
42
+ def state_label(state)
43
+ case state[:kind]
44
+ when :event then "EVT"
45
+ when :launch then "LA"
46
+ else
47
+ state[:kind].to_s[0, 1].capitalize
48
+ end
49
+ end
50
+
51
+ def state_color(state)
52
+ case state[:kind]
53
+ when :end then "grey"
54
+ else
55
+ state.initial? ? "green" : "white"
56
+ end
57
+ end
58
+
59
+ def state_shape(state)
60
+ s = [:fork, :join].include?(state[:kind]) ? "octagon" : "circle"
61
+ state.accepting? ? "double#{s}" : s
62
+ end
63
+
64
+ def edge_label(edge)
65
+ if args=edge[:event_args]
66
+ "#{edge.symbol}(#{args.join ', '})"
67
+ else
68
+ edge.symbol || ""
69
+ end
70
+ end
71
+
72
+ end # class Gts
73
+ end # module Compiling
74
+ end # module Gisele
@@ -0,0 +1,127 @@
1
+ module Gisele
2
+ module Compiling
3
+ class Gts2Bytecode
4
+
5
+ attr_reader :builder
6
+
7
+ def initialize(builder = VM::Bytecode::Builder.new)
8
+ @builder = builder
9
+ end
10
+
11
+ def self.call(ts, namespace = nil)
12
+ builder = VM::Bytecode::Builder.new(namespace)
13
+ Gts2Bytecode.new(builder).call(ts)
14
+ end
15
+
16
+ def call(ts)
17
+ builder.at do |b|
18
+ b.then label(ts.initial_state)
19
+ end
20
+ ts.each_state do |s|
21
+ send :"on_#{s[:kind]}", s
22
+ end
23
+ VM::Bytecode.coerce(builder.to_a)
24
+ end
25
+
26
+ def on_nop(state)
27
+ unless state.out_edges.size == 1
28
+ raise ArgumentError, "Invalid :nop state"
29
+ end
30
+ edge = state.out_edges.first
31
+ at(state) do |b|
32
+ b.then label(edge.target)
33
+ end
34
+ end
35
+
36
+ def on_launch(state)
37
+ h = {}
38
+ state.out_edges.each do |edge|
39
+ h[edge.symbol] = label(edge.target)
40
+ end
41
+ at(state) do |b|
42
+ b.push h
43
+ b.flip
44
+ b.get
45
+ b.then
46
+ end
47
+ end
48
+
49
+ def on_event(state)
50
+ unless state.out_edges.size == 1
51
+ raise ArgumentError, "Invalid :event state #{state.inspect}"
52
+ end
53
+ edge = state.out_edges.first
54
+ at(state) do |b|
55
+ b.then label(edge.target)
56
+ b.then label(edge)
57
+ end
58
+ at(edge) do |b|
59
+ b.push edge[:event_args] || []
60
+ b.event edge.symbol
61
+ end
62
+ end
63
+
64
+ def on_listen(state)
65
+ h = {}
66
+ state.out_edges.each do |edge|
67
+ h[edge.symbol] = label(edge.target)
68
+ end
69
+ at(state) do |b|
70
+ b.push h
71
+ b.then :listen
72
+ end
73
+ end
74
+
75
+ def on_fork(state)
76
+ join_edges = state.out_edges.select{|e| e.symbol == :"(wait)"}
77
+ unless join_edges.size == 1
78
+ raise ArgumentError, "Invalid :fork state"
79
+ end
80
+ join_state = join_edges.first.target
81
+ targets = state.out_adjacent_states - [ join_state ]
82
+ at(state) do |b|
83
+ b.push label(join_state)
84
+ b.push targets.map{|t| label(t)}
85
+ b.then :fork
86
+ end
87
+ end
88
+
89
+ def on_join(state)
90
+ unless state.out_edges.size == 1
91
+ raise ArgumentError, "Invalid :join state"
92
+ end
93
+ target = state.out_edges.first.target
94
+ at(state) do |b|
95
+ b.push :wake => label(target)
96
+ b.then :join
97
+ end
98
+ end
99
+
100
+ def on_end(state)
101
+ unless state.out_edges.size <= 1
102
+ raise ArgumentError, "Invalid :end state: #{state}"
103
+ end
104
+ at(state) do |b|
105
+ b.then :notify
106
+ end
107
+ end
108
+
109
+ private
110
+
111
+ def label(arg)
112
+ case arg
113
+ when Symbol then arg
114
+ when Stamina::Automaton::State then :"s#{arg.index}"
115
+ when Stamina::Automaton::Edge then :"e#{arg.index}"
116
+ else
117
+ raise ArgumentError, "Unexpected argument: #{arg.inspect}"
118
+ end
119
+ end
120
+
121
+ def at(state, &bl)
122
+ builder.at(label(state), &bl)
123
+ end
124
+
125
+ end # class Gts2Bytecode
126
+ end # module Compiling
127
+ end # module Gisele
@@ -0,0 +1,87 @@
1
+ require 'logger'
2
+ require 'forwardable'
3
+ require_relative 'vm/errors'
4
+ require_relative 'vm/robustness'
5
+ require_relative 'vm/null_object'
6
+ require_relative 'vm/logging'
7
+ require_relative 'vm/component'
8
+ require_relative 'vm/prog'
9
+ require_relative 'vm/prog_list'
10
+ require_relative 'vm/event'
11
+ require_relative 'vm/event_manager'
12
+ require_relative 'vm/registry'
13
+ require_relative 'vm/bytecode'
14
+ require_relative 'vm/kernel'
15
+ require_relative 'vm/lifecycle'
16
+ require_relative 'vm/enacter'
17
+ require_relative 'vm/console'
18
+ require_relative 'vm/proxy'
19
+ module Gisele
20
+ class VM
21
+ extend Forwardable
22
+
23
+ attr_reader :bytecode
24
+ attr_reader :registry
25
+ attr_reader :kernel
26
+ attr_accessor :proglist
27
+ attr_accessor :event_manager
28
+
29
+ def initialize(bytecode = [:gvm])
30
+ @bytecode = (Kernel.bytecode + Bytecode.coerce(bytecode)).verify!
31
+ @registry = Registry.new(self)
32
+ @kernel = Kernel.new
33
+ @proglist = ProgList.memory
34
+ @event_manager = EventManager.new
35
+
36
+ init_lifecycle
37
+
38
+ # other registration
39
+ yield(self) if block_given?
40
+
41
+ # post installation of prior components
42
+ @registry.register @event_manager, true
43
+ @registry.register @proglist, true
44
+ @registry.register @kernel, true
45
+ end
46
+
47
+ def self.gts(gis)
48
+ Compiling::Gisele2Gts.compile(gis)
49
+ end
50
+
51
+ def self.compile(gis)
52
+ Compiling::Gts2Bytecode.call(gts(gis))
53
+ end
54
+
55
+ def vm
56
+ self
57
+ end
58
+
59
+ include Robustness
60
+ include Logging
61
+ include Lifecycle
62
+
63
+ def_delegators :registry, :components,
64
+ :register,
65
+ :unregister,
66
+ :connect,
67
+ :disconnect,
68
+ :connected?
69
+
70
+ def_delegators :kernel, :start,
71
+ :resume,
72
+ :progress
73
+
74
+ def_delegators :proglist, :pick,
75
+ :fetch,
76
+ :save
77
+
78
+ def_delegators :event_manager, :event,
79
+ :subscribe,
80
+ :unsubscribe
81
+
82
+ def progs(restriction = nil)
83
+ proglist.to_relation(restriction)
84
+ end
85
+
86
+ end
87
+ end
@@ -0,0 +1,84 @@
1
+ require_relative 'bytecode/grammar'
2
+ require_relative 'bytecode/builder'
3
+ require_relative 'bytecode/printer'
4
+ module Gisele
5
+ class VM
6
+ class Bytecode
7
+
8
+ def initialize(sexpr)
9
+ @sexpr = sexpr
10
+ end
11
+
12
+ def self.coerce(arg)
13
+ case arg
14
+ when Bytecode then arg
15
+ when String, Path then parse(arg)
16
+ when Grammar then Bytecode.new(arg)
17
+ else
18
+ raise ArgumentError, "Invalid bytecode source: #{arg}"
19
+ end
20
+ end
21
+
22
+ def self.parse(source)
23
+ Bytecode.new(Grammar.sexpr(source))
24
+ end
25
+
26
+ def self.builder(namespace = nil)
27
+ Builder.new(namespace)
28
+ end
29
+
30
+ def self.build(namespace = nil)
31
+ builder = builder(namespace)
32
+ yield(builder)
33
+ Bytecode.new(builder.to_a)
34
+ end
35
+
36
+ def +(other)
37
+ other = Bytecode.coerce(other)
38
+ Bytecode.new [:gvm] + to_a[1..-1] + other.to_a[1..-1]
39
+ end
40
+
41
+ def [](label)
42
+ block = index[label]
43
+ block ? block[2..-1] : nil
44
+ end
45
+ alias :fetch :[]
46
+
47
+ def to_a
48
+ @sexpr
49
+ end
50
+
51
+ def to_s
52
+ Printer.call(to_a)
53
+ end
54
+
55
+ def verify!
56
+ unless (Bytecode::Grammar === @sexpr)
57
+ sexpr.sexpr_body.each do |block|
58
+ next if Bytecode::Grammar[:block] === block
59
+ invalid = block.sexpr_body[1..-1].find{|i|
60
+ !(Bytecode::Grammar[:instruction]===i)
61
+ }
62
+ raise InvalidBytecodeError, "Bad instruction: #{invalid}"
63
+ end
64
+ end
65
+ self
66
+ end
67
+
68
+ private
69
+
70
+ def index
71
+ @index ||= begin
72
+ index = Hash.new
73
+ to_a.each_with_index do |bl,i|
74
+ next if i==0
75
+ index[bl[1]] = bl
76
+ end
77
+ index
78
+ end
79
+ end
80
+
81
+ end # class Bytecode
82
+ end # class VM
83
+ end # module Gisele
84
+
@@ -0,0 +1,77 @@
1
+ module Gisele
2
+ class VM
3
+ class Bytecode
4
+ class Builder
5
+
6
+ attr_reader :namespace
7
+
8
+ def initialize(namespace = nil)
9
+ @namespace = namespace
10
+ @bytecode = [:gvm]
11
+ @current_block = nil
12
+ end
13
+
14
+ def current_block
15
+ unless @current_block
16
+ raise BadUsageError, "Bytecode builder misused: no current block"
17
+ end
18
+ @current_block
19
+ end
20
+
21
+ def at(label = nil, auto=true)
22
+ raise BadUsageError, "Previous block not dumped." if @current_block
23
+ if label
24
+ label = label(label) if auto
25
+ else
26
+ label = (namespace || "main").to_s.to_sym
27
+ end
28
+ @current_block = [:block, label]
29
+ if block_given?
30
+ yield(self)
31
+ end_block
32
+ end
33
+ end
34
+
35
+ def end_block
36
+ bl, @current_block = @current_block, nil
37
+ @bytecode << bl
38
+ bl
39
+ end
40
+
41
+ def instruction(which, args)
42
+ instr = [which] + args
43
+ if Grammar[which] === instr
44
+ current_block << instr
45
+ instr
46
+ else
47
+ raise InvalidBytecodeError, "Invalid instruction: #{instr.inspect}"
48
+ end
49
+ end
50
+
51
+ def to_a
52
+ @bytecode
53
+ end
54
+
55
+ Grammar.instructions.each do |iname|
56
+ define_method(iname) do |*args|
57
+ instruction(iname, args)
58
+ end
59
+ end
60
+
61
+ [ :then, :fork ].each do |iname|
62
+ define_method(iname) do |label=nil, auto=true|
63
+ label = label(label) if label and auto
64
+ instruction(iname, label ? [ label ] : [ ])
65
+ end
66
+ end
67
+
68
+ private
69
+
70
+ def label(at)
71
+ (namespace ? "#{namespace}_#{at}" : "#{at}").to_sym
72
+ end
73
+
74
+ end # class Builder
75
+ end # class Bytecode
76
+ end # class VM
77
+ end # module Gisele