compiler: don't require exceptions to inherit ARTIQException.

This commit is contained in:
whitequark 2015-12-31 21:54:54 +08:00
parent f9e90d90fa
commit 8aa34ee952
8 changed files with 81 additions and 86 deletions

View File

@ -85,7 +85,6 @@ class TException(types.TMono):
# * Message, which can contain substitutions {0}, {1} and {2} (str).
# * Three 64-bit integers, parameterizing the message (int(width=64)).
# Keep this in sync with the function ARTIQIRGenerator.alloc_exn.
attributes = OrderedDict([
("__name__", TStr()),
@ -99,8 +98,9 @@ class TException(types.TMono):
("__param2__", TInt(types.TValue(64))),
])
def __init__(self, name="Exception"):
def __init__(self, name="Exception", id=0):
super().__init__(name)
self.id = id
def fn_bool():
return types.TConstructor(TBool())

View File

@ -42,10 +42,10 @@ class ObjectMap:
self.forward_map.values()))
class ASTSynthesizer:
def __init__(self, type_map, value_map, quote_function=None, expanded_from=None):
def __init__(self, object_map, type_map, value_map, quote_function=None, expanded_from=None):
self.source = ""
self.source_buffer = source.Buffer(self.source, "<synthesized>")
self.type_map, self.value_map = type_map, value_map
self.object_map, self.type_map, self.value_map = object_map, type_map, value_map
self.quote_function = quote_function
self.expanded_from = expanded_from
@ -119,14 +119,16 @@ class ASTSynthesizer:
if typ in self.type_map:
instance_type, constructor_type = self.type_map[typ]
else:
if issubclass(typ, BaseException):
instance_type = builtins.TException("{}.{}".format(typ.__module__, typ.__qualname__),
id=self.object_map.store(typ))
constructor_type = types.TExceptionConstructor(instance_type)
else:
instance_type = types.TInstance("{}.{}".format(typ.__module__, typ.__qualname__),
OrderedDict())
instance_type.attributes['__objectid__'] = builtins.TInt32()
if issubclass(typ, BaseException):
constructor_type = types.TExceptionConstructor(instance_type)
else:
constructor_type = types.TConstructor(instance_type)
constructor_type.attributes['__objectid__'] = builtins.TInt32()
instance_type.constructor = constructor_type
@ -522,6 +524,7 @@ class Stitcher:
def _synthesizer(self, expanded_from=None):
return ASTSynthesizer(expanded_from=expanded_from,
object_map=self.object_map,
type_map=self.type_map,
value_map=self.value_map,
quote_function=self._quote_function)

View File

@ -999,7 +999,7 @@ class Inferencer(algorithm.Visitor):
{"typeb": printer.name(typeb)},
locb)
]
self._unify(node.name_type, builtins.TException(node.filter.type.name),
self._unify(node.name_type, node.filter.type.instance,
node.name_loc, node.filter.loc, makenotes)
def _type_from_arguments(self, node, ret):

View File

@ -1155,7 +1155,8 @@ class LLVMIRGenerator:
self.llty_of_type(ir.TExceptionTypeInfo()), None)
else:
llclauseexnname = self.llconst_of_const(
ir.Constant(typ.name, ir.TExceptionTypeInfo()))
ir.Constant("{}:{}".format(typ.id, typ.name),
ir.TExceptionTypeInfo()))
lllandingpad.add_clause(ll.CatchClause(llclauseexnname))
if typ is None:

View File

@ -5,6 +5,7 @@ from enum import Enum
from fractions import Fraction
from artiq.language import core as core_language
from artiq.coredevice import exceptions
from artiq import __version__ as software_version
@ -447,26 +448,31 @@ class CommGeneric:
self._write_bytes(return_tags)
self._send_rpc_value(bytearray(return_tags), result, result, service)
self._write_flush()
except core_language.ARTIQException as exn:
except Exception as exn:
logger.debug("rpc service: %d %r ! %r", service_id, arguments, exn)
self._write_header(_H2DMsgType.RPC_EXCEPTION)
if hasattr(exn, 'artiq_exception'):
exn = exn.artiq_exception
self._write_string(exn.name)
self._write_string(exn.message)
for index in range(3):
self._write_int64(exn.param[index])
self._write_string(exn.filename)
self._write_int32(exn.line)
self._write_int32(exn.column)
self._write_string(exn.function)
self._write_flush()
except Exception as exn:
logger.debug("rpc service: %d %r ! %r", service_id, arguments, exn)
self._write_header(_H2DMsgType.RPC_EXCEPTION)
self._write_string(type(exn).__name__)
filename, line, column, function = exn.traceback[-1]
self._write_string(filename)
self._write_int32(line)
self._write_int32(column)
self._write_string(function)
else:
exn_type = type(exn)
if exn_type in (ZeroDivisionError, ValueError, IndexError):
self._write_string("0:{}".format(exn_type.__name__))
else:
exn_id = object_map.store(exn_type)
self._write_string("{}:{}.{}".format(exn_id,
exn_type.__module__, exn_type.__qualname__))
self._write_string(str(exn))
for index in range(3):
self._write_int64(0)
@ -479,7 +485,7 @@ class CommGeneric:
self._write_flush()
def _serve_exception(self, symbolizer):
def _serve_exception(self, object_map, symbolizer):
name = self._read_string()
message = self._read_string()
params = [self._read_int64() for _ in range(3)]
@ -493,7 +499,17 @@ class CommGeneric:
traceback = list(reversed(symbolizer(backtrace))) + \
[(filename, line, column, function, None)]
raise core_language.ARTIQException(name, message, params, traceback)
exception = core_language.ARTIQException(name, message, params, traceback)
if hasattr(exceptions, exception.name):
python_exn_type = getattr(exceptions, exception.name)
else:
assert exception.id != 0
python_exn_type = object_map.retrieve(exception.id)
python_exn = python_exn_type(message)
python_exn.artiq_exception = exception
raise python_exn
def serve(self, object_map, symbolizer):
while True:
@ -501,7 +517,7 @@ class CommGeneric:
if self._read_type == _D2HMsgType.RPC_REQUEST:
self._serve_rpc(object_map)
elif self._read_type == _D2HMsgType.KERNEL_EXCEPTION:
self._serve_exception(symbolizer)
self._serve_exception(object_map, symbolizer)
else:
self._read_expect(_D2HMsgType.KERNEL_FINISHED)
return

View File

@ -1,39 +1,31 @@
import builtins
from artiq.language.core import ARTIQException
class ZeroDivisionError(ARTIQException):
"""Python's :class:`ZeroDivisionError`, mirrored in ARTIQ."""
ZeroDivisionError = builtins.ZeroDivisionError
ValueError = builtins.ValueError
IndexError = builtins.IndexError
class ValueError(ARTIQException):
"""Python's :class:`ValueError`, mirrored in ARTIQ."""
class IndexError(ARTIQException):
"""Python's :class:`IndexError`, mirrored in ARTIQ."""
class InternalError(ARTIQException):
class InternalError(Exception):
"""Raised when the runtime encounters an internal error condition."""
class RTIOUnderflow(ARTIQException):
class RTIOUnderflow(Exception):
"""Raised when the CPU fails to submit a RTIO event early enough
(with respect to the event's timestamp).
The offending event is discarded and the RTIO core keeps operating.
"""
class RTIOSequenceError(ARTIQException):
class RTIOSequenceError(Exception):
"""Raised when an event is submitted on a given channel with a timestamp
not larger than the previous one.
The offending event is discarded and the RTIO core keeps operating.
"""
class RTIOCollisionError(ARTIQException):
class RTIOCollisionError(Exception):
"""Raised when an event is submitted on a given channel with the same
coarse timestamp as the previous one but with a different fine timestamp.
@ -44,8 +36,7 @@ class RTIOCollisionError(ARTIQException):
The offending event is discarded and the RTIO core keeps operating.
"""
class RTIOOverflow(ARTIQException):
class RTIOOverflow(Exception):
"""Raised when at least one event could not be registered into the RTIO
input FIFO because it was full (CPU not reading fast enough).
@ -54,8 +45,7 @@ class RTIOOverflow(ARTIQException):
the exception is caught, and events will be partially retrieved.
"""
class DDSBatchError(ARTIQException):
class DDSBatchError(Exception):
"""Raised when attempting to start a DDS batch while already in a batch,
or when too many commands are batched.
"""

View File

@ -131,6 +131,10 @@ def run(with_file=False):
except CompileError as error:
print(error.render_string(colored=True), file=sys.stderr)
return
except Exception as exn:
if hasattr(exn, 'artiq_exception'):
print(exn.artiq_exception, file=sys.stderr)
raise exn
finally:
device_mgr.close_devices()

View File

@ -365,41 +365,20 @@ class TerminationRequested(Exception):
pass
class ARTIQException(Exception):
"""Base class for exceptions raised or passed through the core device."""
# Try and create an instance of the specific class, if one exists.
def __new__(cls, name, message, params, traceback):
def find_subclass(cls):
if cls.__name__ == name:
return cls
else:
for subclass in cls.__subclasses__():
cls = find_subclass(subclass)
if cls is not None:
return cls
more_specific_cls = find_subclass(cls)
if more_specific_cls is None:
more_specific_cls = cls
exn = Exception.__new__(more_specific_cls)
exn.__init__(name, message, params, traceback)
return exn
class ARTIQException:
"""Information about an exception raised or passed through the core device."""
def __init__(self, name, message, params, traceback):
Exception.__init__(self, name, message, *params)
self.name, self.message, self.params = name, message, params
if ':' in name:
exn_id, self.name = name.split(':', 2)
self.id = host_int(exn_id)
else:
self.id, self.name = 0, name
self.message, self.params = message, params
self.traceback = list(traceback)
def __str__(self):
lines = []
if type(self).__name__ == self.name:
lines.append(self.message.format(*self.params))
else:
lines.append("({}) {}".format(self.name, self.message.format(*self.params)))
lines.append("Core Device Traceback (most recent call last):")
for (filename, line, column, function, address) in self.traceback:
stub_globals = {"__name__": filename, "__loader__": source_loader}
@ -426,4 +405,6 @@ class ARTIQException(Exception):
lines.append(" {}".format(source_line.strip() if source_line else "<unknown>"))
lines.append(" {}^".format(" " * (column - indentation)))
lines.append("{}({}): {}".format(self.name, self.id,
self.message.format(*self.params)))
return "\n".join(lines)