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 OPERATIONS(self):
125 return self.__operations
129 return self.__constants
133 self.__entry().clear()
135 def push_entry(self):
136 value = self.__entry().get_value()
140 valueNode = self._parse_value(value)
141 self.history.push(valueNode)
143 self.__entry().clear()
146 def apply_operation(self, Node):
150 node = self._apply_operation(Node)
152 except StandardError, e:
153 self.__errorReporter.push_exception()
156 def serialize_stack(self):
158 stackNode.serialize(self.__serialRenderer)
159 for stackNode in self.history
161 serialized = list(serialized)
164 def deserialize_stack(self, data):
165 for possibleNode in data:
166 for nodeValue in possibleNode:
167 if nodeValue in self.OPERATIONS:
168 Node = self.OPERATIONS[nodeValue]
169 self._apply_operation(Node)
171 node = self._parse_value(nodeValue)
172 self.history.push(node)
174 def _parse_value(self, userInput):
176 value, base = parse_number(userInput)
177 return operation.Value(value, base)
182 return self.CONSTANTS[userInput]
186 validate_variable_name(userInput)
187 return operation.Variable(userInput)
189 def _apply_operation(self, Node):
190 numArgs = Node.argumentCount
192 if len(self.history) < numArgs:
194 "Not enough arguments. The stack has %d but %s needs %d" % (
195 len(self.history), Node.symbol, numArgs
199 args = [arg for arg in algorithms.func_repeat(numArgs, self.history.pop)]
204 except StandardError:
206 self.history.push(arg)
208 self.history.push(node)