ceml 0.2.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.
@@ -0,0 +1,138 @@
1
+ require 'set'
2
+
3
+ module CEML
4
+ class Dummy
5
+ def method_missing(meth, *args, &blk)
6
+ # puts "#{meth}: #{args.to_s.inspect}"
7
+ end
8
+ end
9
+
10
+ class Engine
11
+ attr_reader :script, :parts
12
+ def this; @parts[@current_id]; end
13
+ def roles; this[:roles] ||= Set.new; end
14
+ def got; this[:received]; end
15
+ def recognized; this[:recognized]; end
16
+ def pc; this[:pc] ||= 0; end
17
+
18
+ def initialize(script_text, delg = Dummy.new)
19
+ @script = CEML.parse(:script, script_text)
20
+ @delg = delg
21
+ @parts = {}
22
+ @seq = {}
23
+ end
24
+
25
+ def add(id, *roles)
26
+ obj = Hash === roles[-1] ? roles.pop : {}
27
+ parts[id] = obj.merge :roles => Set.new(roles)
28
+ end
29
+
30
+ def run
31
+ :loop while parts.keys.any? do |@current_id|
32
+ # puts "trying: #{@current_id}: #{seq[pc]}"
33
+ next unless seq[pc] and send(*seq[pc])
34
+ @delg.send(*seq[pc] + [@current_id])
35
+ this[:pc]+=1
36
+ end
37
+ end
38
+
39
+ def seq
40
+ @seq[roles] ||= begin
41
+ bytecode = [[:start]]
42
+ instrs = script.instructions_for(roles)
43
+ instrs.each do |inst|
44
+ case inst.cmd
45
+ when :ask
46
+ bytecode << [:ask_q, inst]
47
+ bytecode << [:answered_q, inst]
48
+ when :tell
49
+ if script.title
50
+ bytecode << [:assign, inst]
51
+ bytecode << [:complete_assign, inst]
52
+ else
53
+ bytecode << [:send_msg, inst]
54
+ end
55
+ end
56
+ end
57
+ if instrs.empty? and script.title
58
+ bytecode << [:null_assign]
59
+ bytecode << [:complete_assign]
60
+ end
61
+ bytecode << [:finish]
62
+ end
63
+ end
64
+
65
+ def say x, params = {}
66
+ this[:said] = x
67
+ this.merge! params
68
+ end
69
+
70
+ def qs_answers
71
+ this[:qs_answers] ||= Hash.new
72
+ end
73
+
74
+ def expand(role, var)
75
+ role = nil if role == 'otherguy'
76
+ role = role.to_sym if role
77
+ parts.each do |key, thing|
78
+ next if key == @current_id
79
+ next if role and not thing[:roles].include? role
80
+ value = (thing[:qs_answers]||{})[var] and return value
81
+ end
82
+ nil
83
+ end
84
+
85
+ # ==============
86
+ # = basic flow =
87
+ # ==============
88
+
89
+ def start
90
+ roles.include? :agent or return false
91
+ true
92
+ end
93
+
94
+ def ask_q q
95
+ text = q.interpolate(self) or return false
96
+ say :ask, :q => text
97
+ true
98
+ end
99
+
100
+ def answered_q q
101
+ got or return false
102
+ qs_answers[q.key] = got
103
+ true
104
+ end
105
+
106
+ def send_msg a
107
+ text = a.interpolate(self) or return false
108
+ say :message, :msg => text
109
+ true
110
+ end
111
+
112
+ def assign a
113
+ text = a.interpolate(self) or return false
114
+ say :assignment, :msg => text
115
+ true
116
+ end
117
+
118
+ def complete_assign a = nil
119
+ got or return false
120
+ if recognized == :done
121
+ say :ok
122
+ true
123
+ else
124
+ @delg.send :did_report
125
+ false
126
+ end
127
+ end
128
+
129
+ def null_assign
130
+ say :proceed
131
+ true
132
+ end
133
+
134
+ def finish
135
+ true
136
+ end
137
+ end
138
+ end
@@ -0,0 +1,31 @@
1
+ module CEML
2
+ module Instructions
3
+ def validate!(allowed_roles)
4
+ extra_roles = roles - allowed_roles
5
+ raise "unrecognized rolenames: #{extra_roles.inspect}" unless extra_roles.empty?
6
+
7
+ # max one tell per role
8
+ roles.each{ |r| tell([r]) }
9
+ end
10
+
11
+ def roles
12
+ elements.map{ |s| s.role.to_sym }.uniq
13
+ end
14
+
15
+ def for(roles)
16
+ elements.select{ |s| roles.include?(s.role.to_sym) }
17
+ end
18
+
19
+ def asks(roles)
20
+ elements.select do |s|
21
+ s.text_value =~ /^ask/ && roles.include?(s.role.to_sym)
22
+ end
23
+ end
24
+
25
+ def tell(roles)
26
+ ss = elements.select{ |s| s.text_value =~ /^tell/ && roles.include?(s.role.to_sym) }
27
+ raise "multiple assignments for role: #{role}" if ss.size > 1
28
+ ss.first
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,103 @@
1
+ module CEML
2
+ module Script
3
+
4
+ def to_hash *fields
5
+ fields.inject({}){ |h, s| x = send(s); h[s] = x if x; h }
6
+ end
7
+
8
+ def script
9
+ text_value
10
+ end
11
+
12
+ def title
13
+ super && !super.empty? && super.value
14
+ end
15
+
16
+ def name
17
+ title || label
18
+ end
19
+
20
+ def radius
21
+ casting_statement.empty? ? nil : casting_statement.radius
22
+ end
23
+
24
+ def roles
25
+ return [:agents] if casting_statement.empty?
26
+ return casting_statement.roles
27
+ end
28
+
29
+ def dramatis_personae
30
+ casting_statement.empty? ? nil : casting_statement
31
+ end
32
+
33
+ alias_method :dp, :dramatis_personae
34
+
35
+ def simple?
36
+ (roles - [:agents, :organizer]).empty?
37
+ end
38
+
39
+ def expand_roles(roles)
40
+ roles.map{ |r| r == :agent ? [:agent, :agents] : r }.flatten.concat([:both, :all, :everyone])
41
+ end
42
+
43
+ def instructions_for(roles)
44
+ return [] if !instructions or instructions.empty?
45
+ return instructions.for(expand_roles(roles))
46
+ end
47
+
48
+ def asks(roles)
49
+ return [] if instructions.empty?
50
+ instructions.asks([*roles])
51
+ end
52
+
53
+ def params
54
+ asks(:organizer).map do |ask|
55
+ [ask.var, ask.var.capitalize, ask.text]
56
+ end
57
+ end
58
+
59
+ def tell(roles)
60
+ return nil if instructions.empty?
61
+ instructions.tell([*roles])
62
+ end
63
+
64
+ def type
65
+ return 'mission' if title
66
+ return 'unknown' if instructions.empty?
67
+ return 'question' if not instructions.asks.empty?
68
+ return 'message' if instructions.tell(:agents)
69
+ return 'unknown'
70
+ end
71
+
72
+ def message?
73
+ type == 'message'
74
+ end
75
+
76
+ def label
77
+ return title || begin
78
+ return "unknown" unless simple?
79
+ if q = instructions.asks(:agents).first
80
+ "Question: #{q.text}"
81
+ elsif tell = instructions.tell(:agents)
82
+ "Message: #{tell}" if tell
83
+ else
84
+ "unknown"
85
+ end
86
+ end
87
+ end
88
+
89
+ def validate!
90
+ instructions.validate!(allowed_roles) unless instructions.empty?
91
+ end
92
+
93
+ def allowed_roles
94
+ allowed_roles = [:organizer, :agents]
95
+ allowed_roles += casting_statement.roles unless casting_statement.empty?
96
+ allowed_roles
97
+ end
98
+
99
+ def concludes_immediately?
100
+ !title and instructions.asks([:agents]).empty?
101
+ end
102
+ end
103
+ end