7 from util import algorithms
18 _VARIABLE_VALIDATION_RE = re.compile("^[a-zA-Z0-9]+$")
21 def validate_variable_name(variableName):
22 match = _VARIABLE_VALIDATION_RE.match(variableName)
24 raise RuntimeError("Invalid characters in '%s'" % variableName)
27 def parse_number(userInput):
29 base = __BASE_MAPPINGS.get(userInput[0:2], 10)
31 userInput = userInput[2:] # Remove prefix
32 value = int(userInput, base)
38 value = float(userInput)
44 value = complex(userInput)
49 raise ValueError('Cannot parse "%s" as a number' % userInput)
52 class AbstractHistory(object):
54 Is it just me or is this class name begging for some jokes?
58 raise NotImplementedError
61 raise NotImplementedError
65 for child in node.get_children():
69 raise NotImplementedError
72 raise NotImplementedError
75 raise NotImplementedError
78 raise NotImplementedError
81 class CalcHistory(AbstractHistory):
84 super(CalcHistory, self).__init__()
88 assert node is not None
89 self.__nodeStack.append(node)
93 popped = self.__nodeStack[-1]
94 del self.__nodeStack[-1]
98 return self.__nodeStack[-1]
101 self.__nodeStack = []
104 return len(self.__nodeStack)
107 return self.__nodeStack[::-1]
110 class RpnCalcHistory(object):
112 def __init__(self, history, entry, errorReporting, constants, operations):
113 self.history = history
114 self.history._parse_value = self._parse_value
115 self.__entry = weakref.ref(entry)
117 self.__errorReporter = errorReporting
118 self.__constants = constants
119 self.__operations = operations
121 self.__serialRenderer = operation.render_number()
124 def errorReporter(self):
125 return self.__errorReporter
128 def OPERATIONS(self):
129 return self.__operations
133 return self.__constants
137 self.__entry().clear()
139 def push_entry(self):
140 value = self.__entry().get_value()
144 valueNode = self._parse_value(value)
145 self.history.push(valueNode)
147 self.__entry().clear()
150 def apply_operation(self, Node):
154 node = self._apply_operation(Node)
156 except StandardError, e:
157 self.errorReporter.push_exception()
160 def serialize_stack(self):
162 stackNode.serialize(self.__serialRenderer)
163 for stackNode in self.history
165 serialized = list(serialized)
168 def deserialize_stack(self, data):
169 for possibleNode in data:
170 for nodeValue in possibleNode:
171 if nodeValue in self.OPERATIONS:
172 Node = self.OPERATIONS[nodeValue]
173 self._apply_operation(Node)
175 node = self._parse_value(nodeValue)
176 self.history.push(node)
178 def _parse_value(self, userInput):
180 value, base = parse_number(userInput)
181 return operation.Value(value, base)
186 return self.CONSTANTS[userInput]
190 validate_variable_name(userInput)
191 return operation.Variable(userInput)
193 def _apply_operation(self, Node):
194 numArgs = Node.argumentCount
196 if len(self.history) < numArgs:
198 "Not enough arguments. The stack has %d but %s needs %d" % (
199 len(self.history), Node.symbol, numArgs
203 args = [arg for arg in algorithms.func_repeat(numArgs, self.history.pop)]
208 except StandardError:
210 self.history.push(arg)
212 self.history.push(node)