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
0011
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
0051
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
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
0171
0172
0173
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