ceml 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -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