0001class LogoError(Exception):
0002
0003    """
0004    A generic Logo error.  It tracks file position and some
0005    of the (Logo) traceback.
0006    """
0007
0008    def __init__(self, *args, **kw):
0009        Exception.__init__(self, *args)
0010        # We don't always get the tokenizer immediately,
0011        # but sometimes we do...
0012        if 'tokenizer' in kw:
0013            tokenizer = kw.pop('tokenizer')
0014        else:
0015            tokenizer = None
0016        self.kw = kw
0017        if tokenizer is not None:
0018            self.set_tokenizer(tokenizer)
0019        self.msg = ' '.join(args)
0020        self.frame = None
0021        if 'description' in kw:
0022            self.description = kw['description']
0023
0024    def set_frame(self, frame):
0025        if self.frame:
0026            return
0027        self.frame = frame
0028        self.stack = [FrozenFrame(frame, frame.tokenizer,
0029                                  row=self.kw.get('row'),
0030                                  col=self.kw.get('col'))]
0031        self._traceback_initialized = False
0032        self.initialize_traceback()
0033
0034    def initialize_traceback(self):
0035        frame = self.frame
0036        tokenizers = frame.tokenizers[:-1]
0037        while 1:
0038            if not tokenizers:
0039                if frame.root is frame:
0040                    break
0041                frame = frame.parent
0042                tokenizers = frame.tokenizers
0043                continue
0044            self.stack.append(FrozenFrame(frame, tokenizers[-1]))
0045            tokenizers = tokenizers[:-1]
0046        self._traceback_initialized = True
0047        self.stack.reverse()
0048
0049    def traceback(self):
0050        #if not self._tracebackInitialized:
0051        #    self.initializeTraceback()
0052        return ''.join([str(f) for f in self.stack])
0053
0054    def __str__(self):
0055        s = '\n'
0056        s += self.traceback()
0057        s += self.description + ': ' + Exception.__str__(self)
0058        #s += self.msg
0059        return s
0060
0061class FrozenFrame:
0062
0063    def __init__(self, frame, tokenizer, row=None, col=None, pos=None):
0064        self.frame = frame
0065        self.tokenizer = tokenizer
0066        if hasattr(tokenizer, 'list'):
0067            self.file = None
0068            self.list = tokenizer.list
0069            self.pos = pos
0070            if self.pos is None:
0071                try:
0072                    self.pos = self.tokenizer.pos - len(self.tokenizer.peeked)
0073                except AttributeError:
0074                    pass
0075        elif hasattr(tokenizer, 'file'):
0076            self.list = None
0077            self.file = tokenizer.file
0078            self.row = row
0079            self.col = col
0080            if self.row is None:
0081                try:
0082                    self.row = self.file.row
0083                except AttributeError:
0084                    pass
0085            if self.col is None:
0086                try:
0087                    self.col = self.file.col
0088                except AttributeError:
0089                    pass
0090        else:
0091            assert 0, "Unknown tokenizer: %r" % tokenizer
0092
0093    def __repr__(self):
0094        if self.file:
0095            return '<FrozenFrame %x in %s:%s:%s>' %                      (id(self), self.file.name, self.row, self.col)
0097        elif self.list is not None:
0098            return '<FrozenFrame %x for %r>' %                      (id(self), self.list)
0100        else:
0101            assert 0, "Unknown frame/tokenizer type"
0102
0103    def __str__(self):
0104        if self.file:
0105            return error_for_file(self.file, self.row, self.col)
0106        elif self.list is not None:
0107            return error_for_list(self.list, self.pos)
0108        else:
0109            assert 0, "Unknown frame/tokenizer type"
0110
0111def error_for_file(errorFile, row=None, col=None):
0112    try:
0113        name = errorFile.name
0114    except AttributeError:
0115        name = '<string>'
0116    if not row is None:
0117        try:
0118            row = errorFile.row
0119        except AttributeError:
0120            pass
0121    if not col:
0122        try:
0123            col = errorFile.col
0124        except AttributeError:
0125            pass
0126    if row is not None:
0127        s = 'File %s, line %i\n' % (name, row)
0128        l = errorFile.row_line(row)
0129        if l is not None:
0130            s += l
0131            s += '%s^\n' % (' '*col)
0132    else:
0133        s = 'File %s\n' % name
0134    return s
0135
0136def error_for_list(lst, pos=None):
0137    try:
0138        f = lst.sourceList
0139        s = error_for_file(f) + '\n'
0140    except AttributeError:
0141        s = ''
0142    if pos is not None:
0143        segment = '[' + ' '.join(map(str, lst[:pos]))
0144        segment = segment.split('\n')[-1]
0145        rest = ' '.join(map(str, lst[pos:])) + ']'
0146        rest = rest.split('\n')[0]
0147        s += segment + ' ' + rest + '\n'
0148        s += (' '*len(segment)) + '^\n'
0149    else:
0150        s += repr(lst) + '\n'
0151    return s
0152
0153class LogoSyntaxError(LogoError):
0154    description = 'Syntax error'
0155
0156class LogoNameError(LogoError):
0157    description = 'Name not found error'
0158
0159class LogoUndefinedError(LogoNameError):
0160    description = 'Function undefined error'
0161
0162class LogoEndOfLine(LogoError):
0163    description = 'Unexpected end of line error'
0164
0165class LogoEndOfCode(LogoError):
0166    description = 'Unexpected end of code block error'
0167
0168class LogoList(list):
0169
0170    #def __new__(cls, body, sourceFile):
0171    #    self = list.__new__(cls, body)
0172    #    self.file = sourceFile
0173    #    return self
0174
0175    def __init__(self, body=None, source_file=None):
0176        if body is None:
0177            body = []
0178        list.__init__(self, body)
0179        self.file = source_file
0180
0181class LogoControl(Exception):
0182    pass
0183
0184class LogoOutput(LogoControl):
0185
0186    def __init__(self, value):
0187        self.value = value
0188        Exception.__init__(self)
0189
0190class LogoContinue(LogoControl):
0191    pass
0192
0193class LogoBreak(LogoControl):
0194    pass
0195
0196class _EOF:
0197    def __repr__(self):
0198        return '[EOF]'
0199
0200EOF = _EOF()
0201
0202
0203def logofunc(name=None, aliases=None, aware=False,
0204             arity=None, hide=False):
0205    def decorator(func):
0206        func.logo_expose = True
0207        if name is not None:
0208            func.logo_name = name
0209        if arity is not None:
0210            func.arity = arity
0211        if aliases is not None:
0212            func.aliases = aliases
0213        if aware:
0214            func.logo_aware = aware
0215        if hide:
0216            func.logo_hide = hide
0217        return func
0218    return decorator