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