|
1 | 1 | # Copyright 2014-2016, Tresys Technology, LLC |
2 | 2 | # Copyright 2016-2018, Chris PeBenito <pebenito@ieee.org> |
| 3 | +# Copyright 2024, Sealing Technologies, Inc. |
3 | 4 | # |
4 | 5 | # SPDX-License-Identifier: LGPL-2.1-only |
5 | 6 | # |
@@ -192,40 +193,52 @@ cdef class ConstraintExpression(PolicyObject): |
192 | 193 |
|
193 | 194 | # sepol representation is in postfix notation. This code |
194 | 195 | # converts it to infix notation. Parentheses are added |
195 | | - # to ensure correct expressions, though they may end up |
196 | | - # being overused. Set previous operator at start to the |
197 | | - # highest precedence (op) so if there is a single binary |
198 | | - # operator, no parentheses are output |
| 196 | + # to ensure correct expressions. Parentheses are needed |
| 197 | + # whenever an operation involves a subexpression with |
| 198 | + # lower precedence. |
199 | 199 | stack = [] |
200 | | - prev_op_precedence = _max_precedence |
| 200 | + |
| 201 | + @dataclasses.dataclass(repr=False, eq=False, frozen=True) |
| 202 | + class StackObj: |
| 203 | + precedence: int |
| 204 | + expression: List[str] |
| 205 | + |
201 | 206 | for op in self._postfix: |
202 | 207 | if isinstance(op, frozenset) or op in _operands: |
203 | 208 | # operands |
204 | | - stack.append(op) |
| 209 | + stack.append(StackObj(_max_precedence, op)) |
205 | 210 | else: |
206 | 211 | # operators |
| 212 | + op_precedence = _precedence[op] |
207 | 213 | if op == "not": |
208 | 214 | # unary operator |
209 | 215 | operator = op |
210 | | - operand = stack.pop() |
211 | | - op_precedence = _precedence[op] |
212 | | - stack.append([operator, "(", operand, ")"]) |
| 216 | + operand_info = stack.pop() |
| 217 | + if operand_info.precedence < op_precedence: |
| 218 | + e = [operator, "(", operand_info.expression, ")"] |
| 219 | + else: |
| 220 | + e = [operator, operand_info.expression] |
213 | 221 | else: |
214 | 222 | # binary operators |
215 | | - operand2 = stack.pop() |
216 | | - operand1 = stack.pop() |
| 223 | + operand2_info = stack.pop() |
| 224 | + operand1_info = stack.pop() |
217 | 225 | operator = op |
218 | 226 |
|
219 | | - # if previous operator is of higher precedence |
220 | | - # no parentheses are needed. |
221 | | - if _precedence[op] < prev_op_precedence: |
222 | | - stack.append([operand1, operator, operand2]) |
| 227 | + if operand1_info.precedence < op_precedence: |
| 228 | + operand1 = ["(", operand1_info.expression, ")"] |
223 | 229 | else: |
224 | | - stack.append(["(", operand1, operator, operand2, ")"]) |
| 230 | + operand1 = [operand1_info.expression] |
| 231 | + |
| 232 | + if operand2_info.precedence < op_precedence: |
| 233 | + operand2 = ["(", operand2_info.expression, ")"] |
| 234 | + else: |
| 235 | + operand2 = [operand2_info.expression] |
| 236 | + |
| 237 | + e = operand1 + [operator] + operand2 |
225 | 238 |
|
226 | | - prev_op_precedence = _precedence[op] |
| 239 | + stack.append(StackObj(op_precedence, e)) |
227 | 240 |
|
228 | | - self._infix = flatten_list(stack) |
| 241 | + self._infix = flatten_list(map(lambda x:x.expression, stack)) |
229 | 242 |
|
230 | 243 | return self._infix |
231 | 244 |
|
|
0 commit comments