Beispiel #1
0
    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
Beispiel #2
0
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)')
Beispiel #3
0
    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
Beispiel #4
0
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)')
Beispiel #5
0
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
Beispiel #6
0
    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
Beispiel #7
0
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)')
Beispiel #8
0
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)))
Beispiel #9
0
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)))
Beispiel #10
0
    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