def _runFunction(self, command, modifiers, count, function): "Run a Python function." nArgs = ((len(self) if modifiers.all else function.nArgs) if count is None else count) if len(self) < nArgs: raise CalculatorError( 'Not enough args on stack! (%s needs %d arg%s, stack has ' '%d item%s)' % (command, nArgs, '' if nArgs == 1 else 's', len(self), '' if len(self) == 1 else 's')) args = self.convertStackArgs(self.stack[-nArgs:]) if nArgs else [] if modifiers.reverse and args: # Reverse the order of args so that the top of the stack (last # element of the stack list) becomes the first argument to the # function instead of the last. args = args[::-1] self.debug('Calling %s with %r' % (function.name, tuple(args))) try: result = function.func(*args) except BaseException as e: raise CalculatorError( 'Exception running %s(%s): %s' % (function.name, ', '.join(map(str, args)), e)) else: self._finalize(result, modifiers, nPop=nArgs) return True, result
def list_(calc, modifiers, count): """Convert some stack items into a list. @param calc: A C{Calculator} instance. @param modifiers: A C{Modifiers} instance. @param count: An C{int} count of the number of stack items to make into a list. """ if modifiers.push: calc._finalize(list, modifiers=modifiers) return list if calc.stack: nArgs = (len(calc) if modifiers.all else 1) if count is None else count if nArgs == 1: value = calc.stack[-1] try: iterator = iter(value) except TypeError: value = [value] else: value = list(iterator) else: if len(calc) >= nArgs: value = calc.stack[-nArgs:] else: raise CalculatorError( 'Cannot list %d item%s (stack length is %d)' % (nArgs, '' if nArgs == 1 else 's', len(calc))) calc._finalize(value, modifiers=modifiers, nPop=nArgs) return value raise CalculatorError('Cannot run list (stack is empty)')
def _trySpecial(self, command, modifiers, count): if command in self._special: try: value = self._special[command](self, modifiers, count) except EOFError: raise except BaseException as e: raise CalculatorError('Could not run special command %r: %s' % (command, e)) return True, value if modifiers.forceCommand: raise CalculatorError('Unknown special command: %s' % command) return False, self.NO_VALUE
def dup(calc, modifiers, count): """Duplicate the top of stack a number of times. @param calc: A C{Calculator} instance. @param modifiers: A C{Modifiers} instance. @param count: An C{int} count of the number of arguments to pass. """ if calc.stack: if modifiers.preserveStack: raise CalculatorError('The /= modifier makes no sense with dup') count = 1 if count is None else count value = calc.stack[-1] calc._finalize(value, modifiers, repeat=count) return value raise CalculatorError('Cannot duplicate (stack is empty)')
def undo(calc, modifiers, _): """Undo the last operation. @param calc: A C{Calculator} instance. @param modifiers: A C{Modifiers} instance. """ if calc._previousStack is None: raise CalculatorError('No undo saved') if modifiers.preserveStack: raise CalculatorError('The /= modifier makes no sense with undo') if modifiers.print: raise CalculatorError('The /p modifier makes no sense with undo') calc.stack = calc._previousStack.copy() calc._variables = calc._previousVariables.copy() return calc.NO_VALUE
def _executeOneCommand(self, command, modifiers, count): """ Execute one command. @param command: A C{str} command to run. @param modifiers: A C{Modifiers} instance. @param count: An C{int} count, or C{None} if no count was given. @return: A C{bool} indicating if the command ran without error. """ if modifiers.split: if not self._splitLines: self.debug('Line splitting switched ON') self._splitLines = True elif modifiers.noSplit: if self._splitLines: self.debug('Line splitting switched OFF') self._splitLines = False if modifiers.all: stackLen = len(self) if count is not None and count != stackLen: self.err( '* modifier conflicts with explicit count %d ' '(stack has %d item%s)' % (count, stackLen, '' if stackLen == 1 else 's')) return False if modifiers.autoPrint: self.toggleAutoPrint() if modifiers.debug: self.toggleDebug() if not command: self.debug('Empty command') return True if count == 0: self.debug('Count was zero - nothing to do!') return True try: for func in (self._tryFunction, self._tryVariable, self._trySpecial, self._tryEvalExec): status, value = func(command, modifiers, count) if status: if (value is not self.NO_VALUE and (modifiers.print or self._autoPrint)): self.pprint(value) return True else: raise CalculatorError('Could not find a way to execute %r' % command) except (CalculatorError, StackError) as e: for err in e.args: self.err(err) return False
def swap(calc, modifiers, _): """Swap the top two items on the stack. @param calc: A C{Calculator} instance. @param modifiers: A C{Modifiers} instance. """ if len(calc) > 1: calc._finalize(calc.stack[-2:][::-1], modifiers=modifiers, nPop=2, extend=True) return calc.NO_VALUE raise CalculatorError('Cannot swap (stack needs 2 items)')
def pop(calc, modifiers, count): """Pop some number of arguments (default 1) off the stack. @param calc: A C{Calculator} instance. @param modifiers: A C{Modifiers} instance. @param count: An C{int} count of the number of arguments to pass. """ nArgs = (len(calc) if modifiers.all else 1) if count is None else count if len(calc) >= nArgs: value = calc.stack[-1] if nArgs == 1 else calc.stack[-nArgs:] calc._finalize(value, modifiers, nPop=nArgs, noValue=True) return value raise CalculatorError('Cannot pop %d item%s (stack length is %d)' % (nArgs, '' if nArgs == 1 else 's', len(calc)))
def reverse(calc, modifiers, count): """Reverse some number of arguments (default 2) on the stack. @param calc: A C{Calculator} instance. @param modifiers: A C{Modifiers} instance. @param count: An C{int} count of the number of arguments to pass. """ nArgs = (len(calc) if modifiers.all else 2) if count is None else count if len(calc) >= nArgs: if nArgs > 1: value = calc.stack[-nArgs:][::-1] calc._finalize(value, modifiers, nPop=nArgs, extend=True) return value raise CalculatorError('Cannot reverse %d item%s (stack length is %d)' % (nArgs, '' if nArgs == 1 else 's', len(calc)))
def _tryEvalExec(self, command, modifiers, count): errors = [] possibleWhiteSpace = False try: value = eval(command, globals(), self._variables) except BaseException as e: err = str(e) errors.append('Could not eval(%r): %s' % (command, err)) if (self._splitLines and err.startswith( 'unexpected EOF while parsing (<string>, line 1)')): possibleWhiteSpace = True try: value = EngNumber(command) except decimal.InvalidOperation: try: exec(command, globals(), self._variables) except BaseException as e: err = str(e) errors.append('Could not exec(%r): %s' % (command, err)) if (not possibleWhiteSpace and self._splitLines and err.startswith( 'unexpected EOF while parsing (<string>, ' 'line 1)')): possibleWhiteSpace = True if possibleWhiteSpace: errors.append('Did you accidentally include ' 'whitespace in a command line?') raise CalculatorError(*errors) else: self.debug('exec(%r) worked.' % command) return True, self.NO_VALUE else: self.debug('EngNumber(%s) worked: %r' % (command, value)) count = 1 if count is None else count self._finalize(value, modifiers=modifiers, repeat=count) return True, value else: self.debug('eval %s worked: %r' % (command, value)) count = 1 if count is None else count self._finalize(value, modifiers=modifiers, repeat=count) return True, value