1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18 """
19 A bouncer-algorithm combinator, using the pyparsing module and a simple logic
20 expression language.
21 """
22
23 try:
24 import pyparsing
25 except ImportError:
26 pyparsing = None
27
28 from twisted.internet import defer
29
30 from flumotion.common import keycards, log
31
32
34 """
35 Error parsing combination specification.
36
37 @cvar line: Line that triggered the error.
38 @type line: string
39 """
40
41
45
46
48
49 logCategory = "notnode"
50
52 self.child = tokens[0][1]
53 self.debug("creating combinator node using %r", self.child)
54
58
61
62
64
65 logCategory = "andnode"
66
68 self.children = tokens[0][0::2]
69 self.debug("creating combinator node using %r", self.children)
70
72 results = [(True, False)]
73
74 d = defer.Deferred()
75
76 for child in self.children:
77 d.addCallback(self.set_result, keycard,
78 child, results, context)
79
80 def decide_result(_):
81
82 if results[-1] == (False, False):
83 return False, False
84
85 assert len(results) - 1 == len(self.children)
86
87 result, volatile = True, False
88 for res, vol in results:
89 if not res:
90 assert vol
91 result = False
92 if vol:
93 volatile = True
94 return result, volatile
95
96 d.addCallback(decide_result)
97 d.callback(None)
98 return d
99
100 - def set_result(self, _, keycard, child, results, context):
101 self.log("processing results %r", results)
102
103
104 if results[-1] == (False, False):
105 return
106
107 d = child.evaluate(keycard, context)
108 return d.addCallback(lambda (res, volatile):
109 results.append((res, volatile)))
110
116
117
119
120 logCategory = "ornode"
121
123 self.children = tokens[0][0::2]
124 self.debug("creating combinator node using %r", self.children)
125
127 results = [(False, False)]
128
129 d = defer.Deferred()
130
131 for child in self.children:
132 d.addCallback(self.set_result, keycard,
133 child, results, context)
134
135 def decide_result(_):
136
137 if results[-1] == (True, False):
138 return True, False
139
140 assert len(results) - 1 == len(self.children)
141
142 result, volatile = False, False
143 for res, vol in results:
144 if res:
145 assert vol
146 result = True
147 if vol:
148 volatile = True
149 return result, volatile
150
151 d.addCallback(decide_result)
152 d.callback(None)
153 return d
154
155 - def set_result(self, _, keycard, child, results, context):
156 self.log("processing results %r", results)
157
158
159 if results[-1] == (True, False):
160 return
161
162 d = child.evaluate(keycard, context)
163 return d.addCallback(lambda (res, volatile):
164 results.append((res, volatile)))
165
171
172
174
175 logCategory = "algorithmnode"
176
177 - def __init__(self, name, call_function, volatile):
182
191
193 self.log("node %r evaluating %r in context %r",
194 self.name, keycard, context)
195 if self.name in context:
196 self.log("node %r found value in context: %r",
197 self.name, context[self.name])
198 result = context[self.name]
199 return defer.succeed((result, self.result_volatile(result)))
200 self.debug("node %r calling algorithm with keycard %r",
201 self.name, keycard)
202 d = defer.maybeDeferred(self.call_function, keycard)
203 return d.addCallback(self.get_state_and_reset, context)
204
206
207 if not result:
208 return False
209
210 return self.volatile
211
213 self.debug("node %r evaluating synchronously in context %r",
214 self.name, context)
215 return context[self.name]
216
217
219
220 logCategory = 'combinator'
221
224
227
238
244
248
251
261
262 algorithm = pyparsing.oneOf(self.algorithms.keys())
263 algorithm.setParseAction(create_algorithm_node)
264
265 openended_expr = pyparsing.operatorPrecedence(
266 algorithm,
267 [("not", 1, pyparsing.opAssoc.RIGHT, NotNode),
268 ("or", 2, pyparsing.opAssoc.LEFT, OrNode),
269 ("and", 2, pyparsing.opAssoc.LEFT, AndNode)])
270
271 return openended_expr + pyparsing.StringEnd()
272