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.
- data/CHANGELOG.md +5 -0
- data/Gemfile +18 -0
- data/Gemfile.lock +46 -0
- data/LICENCE.md +22 -0
- data/Manifest.txt +15 -0
- data/README.md +10 -0
- data/Rakefile +11 -0
- data/bin/gvm +9 -0
- data/gisele-vm.gemspec +191 -0
- data/gisele-vm.noespec +31 -0
- data/lib/gisele-vm.rb +4 -0
- data/lib/gisele-vm/loader.rb +5 -0
- data/lib/gisele-vm/version.rb +16 -0
- data/lib/gisele/compiling.rb +3 -0
- data/lib/gisele/compiling/gisele2gts.rb +143 -0
- data/lib/gisele/compiling/gts.rb +74 -0
- data/lib/gisele/compiling/gts2bytecode.rb +127 -0
- data/lib/gisele/vm.rb +87 -0
- data/lib/gisele/vm/bytecode.rb +84 -0
- data/lib/gisele/vm/bytecode/builder.rb +77 -0
- data/lib/gisele/vm/bytecode/grammar.citrus +116 -0
- data/lib/gisele/vm/bytecode/grammar.rb +19 -0
- data/lib/gisele/vm/bytecode/grammar.sexp.yml +113 -0
- data/lib/gisele/vm/bytecode/printer.rb +35 -0
- data/lib/gisele/vm/command.rb +140 -0
- data/lib/gisele/vm/component.rb +91 -0
- data/lib/gisele/vm/console.rb +58 -0
- data/lib/gisele/vm/enacter.rb +29 -0
- data/lib/gisele/vm/errors.rb +26 -0
- data/lib/gisele/vm/event.rb +11 -0
- data/lib/gisele/vm/event_manager.rb +65 -0
- data/lib/gisele/vm/kernel.rb +58 -0
- data/lib/gisele/vm/kernel/macros.gvm +214 -0
- data/lib/gisele/vm/kernel/opcodes.rb +212 -0
- data/lib/gisele/vm/kernel/runner.rb +63 -0
- data/lib/gisele/vm/lifecycle.rb +72 -0
- data/lib/gisele/vm/logging.rb +18 -0
- data/lib/gisele/vm/null_object.rb +19 -0
- data/lib/gisele/vm/prog.rb +63 -0
- data/lib/gisele/vm/prog_list.rb +55 -0
- data/lib/gisele/vm/prog_list/memory.rb +74 -0
- data/lib/gisele/vm/prog_list/sqldb.rb +123 -0
- data/lib/gisele/vm/prog_list/storage.rb +31 -0
- data/lib/gisele/vm/proxy.rb +14 -0
- data/lib/gisele/vm/proxy/client.rb +64 -0
- data/lib/gisele/vm/proxy/server.rb +29 -0
- data/lib/gisele/vm/registry.rb +57 -0
- data/lib/gisele/vm/robustness.rb +31 -0
- data/lib/gisele/vm/simulator/resumer.rb +32 -0
- data/spec/command/gvm_compile.cmd +1 -0
- data/spec/command/gvm_compile.stdout +111 -0
- data/spec/command/gvm_gts.cmd +1 -0
- data/spec/command/gvm_gts.stdout +101 -0
- data/spec/command/gvm_help.cmd +1 -0
- data/spec/command/gvm_help.stdout +30 -0
- data/spec/command/gvm_version.cmd +1 -0
- data/spec/command/gvm_version.stdout +2 -0
- data/spec/command/test_command.rb +29 -0
- data/spec/fixtures/complete.gis +13 -0
- data/spec/fixtures/fake_component.rb +24 -0
- data/spec/fixtures/kernel.rb +39 -0
- data/spec/fixtures/ts.adl +11 -0
- data/spec/fixtures/ts.gts +20 -0
- data/spec/fixtures/ts.gvm +19 -0
- data/spec/spec_helper.rb +86 -0
- data/spec/test_examples.rb +29 -0
- data/spec/test_gisele-vm.rb +8 -0
- data/spec/unit/bytecode/builder/test_at.rb +56 -0
- data/spec/unit/bytecode/builder/test_helpers.rb +36 -0
- data/spec/unit/bytecode/builder/test_instruction.rb +35 -0
- data/spec/unit/bytecode/builder/test_to_a.rb +53 -0
- data/spec/unit/bytecode/bytecode.gvm +1 -0
- data/spec/unit/bytecode/grammar/fixtures/comments.gvm +16 -0
- data/spec/unit/bytecode/grammar/fixtures/every.gvm +46 -0
- data/spec/unit/bytecode/grammar/fixtures/singleblock.gvm +2 -0
- data/spec/unit/bytecode/grammar/fixtures/twoblocks.gvm +4 -0
- data/spec/unit/bytecode/grammar/fixtures/with_end.gvm +5 -0
- data/spec/unit/bytecode/grammar/test_array.rb +24 -0
- data/spec/unit/bytecode/grammar/test_block.rb +35 -0
- data/spec/unit/bytecode/grammar/test_boolean.rb +20 -0
- data/spec/unit/bytecode/grammar/test_constant.rb +20 -0
- data/spec/unit/bytecode/grammar/test_eol.rb +20 -0
- data/spec/unit/bytecode/grammar/test_eol_comment.rb +36 -0
- data/spec/unit/bytecode/grammar/test_file.rb +38 -0
- data/spec/unit/bytecode/grammar/test_hash.rb +33 -0
- data/spec/unit/bytecode/grammar/test_instruction.rb +32 -0
- data/spec/unit/bytecode/grammar/test_int.rb +24 -0
- data/spec/unit/bytecode/grammar/test_label.rb +24 -0
- data/spec/unit/bytecode/grammar/test_opcode.rb +23 -0
- data/spec/unit/bytecode/grammar/test_string.rb +25 -0
- data/spec/unit/bytecode/grammar/test_symbol.rb +30 -0
- data/spec/unit/bytecode/test_build.rb +36 -0
- data/spec/unit/bytecode/test_coerce.rb +41 -0
- data/spec/unit/bytecode/test_fetch.rb +20 -0
- data/spec/unit/bytecode/test_grammar.rb +30 -0
- data/spec/unit/bytecode/test_parse.rb +22 -0
- data/spec/unit/bytecode/test_plus.rb +27 -0
- data/spec/unit/bytecode/test_to_a.rb +19 -0
- data/spec/unit/bytecode/test_to_s.rb +32 -0
- data/spec/unit/command/code.gis +3 -0
- data/spec/unit/command/test_vm.rb +51 -0
- data/spec/unit/compiling/gisele2gts/test_on_par_st.rb +51 -0
- data/spec/unit/compiling/gisele2gts/test_on_seq_st.rb +46 -0
- data/spec/unit/compiling/gisele2gts/test_on_task_call_st.rb +37 -0
- data/spec/unit/compiling/gisele2gts/test_on_task_def.rb +49 -0
- data/spec/unit/compiling/gisele2gts/test_on_unit_def.rb +35 -0
- data/spec/unit/compiling/gts2bytecode/test_on_end.rb +31 -0
- data/spec/unit/compiling/gts2bytecode/test_on_event.rb +37 -0
- data/spec/unit/compiling/gts2bytecode/test_on_fork.rb +41 -0
- data/spec/unit/compiling/gts2bytecode/test_on_join.rb +42 -0
- data/spec/unit/compiling/gts2bytecode/test_on_listen.rb +36 -0
- data/spec/unit/compiling/gts2bytecode/test_on_nop.rb +30 -0
- data/spec/unit/component/test_component_name.rb +16 -0
- data/spec/unit/component/test_logging.rb +36 -0
- data/spec/unit/enacter/test_component.rb +11 -0
- data/spec/unit/event/test_to_s.rb +12 -0
- data/spec/unit/event_manager/test_component.rb +9 -0
- data/spec/unit/event_manager/test_subscribe.rb +40 -0
- data/spec/unit/event_manager/test_unsubscribe.rb +39 -0
- data/spec/unit/kernel/macros/test_fork.rb +37 -0
- data/spec/unit/kernel/macros/test_join.rb +43 -0
- data/spec/unit/kernel/macros/test_listen.rb +37 -0
- data/spec/unit/kernel/macros/test_notify.rb +57 -0
- data/spec/unit/kernel/macros/test_react.rb +47 -0
- data/spec/unit/kernel/macros/test_schedule_at.rb +30 -0
- data/spec/unit/kernel/opcodes/test_op_del.rb +42 -0
- data/spec/unit/kernel/opcodes/test_op_event.rb +25 -0
- data/spec/unit/kernel/opcodes/test_op_fetch.rb +27 -0
- data/spec/unit/kernel/opcodes/test_op_flip.rb +17 -0
- data/spec/unit/kernel/opcodes/test_op_fold.rb +29 -0
- data/spec/unit/kernel/opcodes/test_op_fork.rb +63 -0
- data/spec/unit/kernel/opcodes/test_op_forka.rb +51 -0
- data/spec/unit/kernel/opcodes/test_op_get.rb +62 -0
- data/spec/unit/kernel/opcodes/test_op_getr.rb +48 -0
- data/spec/unit/kernel/opcodes/test_op_ifenil.rb +41 -0
- data/spec/unit/kernel/opcodes/test_op_ifezero.rb +32 -0
- data/spec/unit/kernel/opcodes/test_op_invoke.rb +34 -0
- data/spec/unit/kernel/opcodes/test_op_nop.rb +18 -0
- data/spec/unit/kernel/opcodes/test_op_parent.rb +39 -0
- data/spec/unit/kernel/opcodes/test_op_pop.rb +22 -0
- data/spec/unit/kernel/opcodes/test_op_push.rb +17 -0
- data/spec/unit/kernel/opcodes/test_op_save.rb +32 -0
- data/spec/unit/kernel/opcodes/test_op_savea.rb +34 -0
- data/spec/unit/kernel/opcodes/test_op_self.rb +20 -0
- data/spec/unit/kernel/opcodes/test_op_send.rb +20 -0
- data/spec/unit/kernel/opcodes/test_op_set.rb +61 -0
- data/spec/unit/kernel/opcodes/test_op_then.rb +50 -0
- data/spec/unit/kernel/opcodes/test_op_unfold.rb +22 -0
- data/spec/unit/kernel/opcodes/test_op_uuid.rb +16 -0
- data/spec/unit/kernel/runner/test_pop.rb +26 -0
- data/spec/unit/kernel/runner/test_stack.rb +28 -0
- data/spec/unit/kernel/test_progress.rb +47 -0
- data/spec/unit/kernel/test_resume.rb +53 -0
- data/spec/unit/kernel/test_start.rb +36 -0
- data/spec/unit/prog/test_to_hash.rb +29 -0
- data/spec/unit/prog/test_waitlist_eq.rb +20 -0
- data/spec/unit/prog_list/memory/test_component.rb +9 -0
- data/spec/unit/prog_list/memory/test_fetch.rb +40 -0
- data/spec/unit/prog_list/memory/test_pick.rb +39 -0
- data/spec/unit/prog_list/memory/test_save.rb +91 -0
- data/spec/unit/prog_list/memory/test_to_relation.rb +17 -0
- data/spec/unit/prog_list/sqldb/test_component.rb +11 -0
- data/spec/unit/prog_list/sqldb/test_connect.rb +46 -0
- data/spec/unit/prog_list/test_memory.rb +9 -0
- data/spec/unit/prog_list/test_sqldb.rb +13 -0
- data/spec/unit/prog_list/test_storage.rb +51 -0
- data/spec/unit/registry/test_component.rb +9 -0
- data/spec/unit/registry/test_connect.rb +53 -0
- data/spec/unit/registry/test_disconnect.rb +51 -0
- data/spec/unit/registry/test_registration.rb +44 -0
- data/spec/unit/shared/a_component.rb +49 -0
- data/spec/unit/shared/a_storage.rb +114 -0
- data/spec/unit/test_logging.rb +46 -0
- data/spec/unit/test_prog.rb +57 -0
- data/spec/unit/test_prog_list.rb +22 -0
- data/spec/unit/vm/test_event_facace.rb +11 -0
- data/spec/unit/vm/test_initialize.rb +59 -0
- data/spec/unit/vm/test_proglist_facade.rb +21 -0
- data/tasks/debug_mail.rake +75 -0
- data/tasks/debug_mail.txt +13 -0
- data/tasks/gem.rake +73 -0
- data/tasks/spec_test.rake +71 -0
- data/tasks/unit_test.rake +76 -0
- data/tasks/yard.rake +51 -0
- 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
|
data/lib/gisele/vm.rb
ADDED
|
@@ -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
|