PageRenderTime 39ms CodeModel.GetById 11ms RepoModel.GetById 0ms app.codeStats 1ms

/DLR_Main/Languages/IronPython/Scripts/generate_exceptions.py

https://bitbucket.org/mdavid/dlr
Python | 500 lines | 466 code | 19 blank | 15 comment | 20 complexity | 5d788fe4c9a665f3e6b78d673b1256de MD5 | raw file
  1. #####################################################################################
  2. #
  3. # Copyright (c) Microsoft Corporation. All rights reserved.
  4. #
  5. # This source code is subject to terms and conditions of the Apache License, Version 2.0. A
  6. # copy of the license can be found in the License.html file at the root of this distribution. If
  7. # you cannot locate the Apache License, Version 2.0, please send an email to
  8. # ironpy@microsoft.com. By using this source code in any fashion, you are agreeing to be bound
  9. # by the terms of the Apache License, Version 2.0.
  10. #
  11. # You must not remove this notice, or any other, from this software.
  12. #
  13. #
  14. #####################################################################################
  15. from generate import generate
  16. import System
  17. import clr
  18. import exceptions
  19. def collect_excs():
  20. ret = []
  21. for e in exceptions.__dict__.values():
  22. if not hasattr(e, '__bases__'): continue
  23. if e.__name__ == "exceptions": continue
  24. if e.__name__ == "__builtin__": continue
  25. assert len(e.__bases__) <= 1, e
  26. if len(e.__bases__) == 0:
  27. continue
  28. #supername = None
  29. else:
  30. supername = e.__bases__[0].__name__
  31. ret.append( (e, supername) )
  32. return ret
  33. excs = collect_excs()
  34. pythonExcs = ['ImportError', 'RuntimeError', 'UnicodeTranslateError', 'PendingDeprecationWarning', 'EnvironmentError',
  35. 'LookupError', 'OSError', 'DeprecationWarning', 'UnicodeError', 'FloatingPointError', 'ReferenceError',
  36. 'FutureWarning', 'AssertionError', 'RuntimeWarning', 'ImportWarning', 'UserWarning', 'SyntaxWarning',
  37. 'UnicodeWarning', 'StopIteration', 'BytesWarning', 'BufferError']
  38. class ExceptionInfo(object):
  39. def __init__(self, name, clrException, args, fields, subclasses, silverlightSupported = True, baseMapping = None):
  40. self.name = name
  41. self.clrException = clrException
  42. self.args = args
  43. self.fields = fields
  44. self.subclasses = subclasses
  45. self.silverlightSupported = silverlightSupported
  46. self.parent = None
  47. self.baseMapping = baseMapping
  48. for child in subclasses:
  49. child.parent = self
  50. @property
  51. def ConcreteParent(self):
  52. while not self.parent.fields:
  53. self = self.parent
  54. if self.parent == None: return exceptionHierarchy
  55. return self.parent
  56. @property
  57. def PythonType(self):
  58. if not self.parent:
  59. return 'DynamicHelpers.GetPythonTypeFromType(typeof(%s))' % self.name
  60. else:
  61. return self.name
  62. @property
  63. def ClrType(self):
  64. if not self.parent:
  65. return 'BaseException'
  66. elif self.fields:
  67. return '_' + self.name
  68. else:
  69. return self.name
  70. @property
  71. def ExceptionMappingName(self):
  72. if self.baseMapping:
  73. return self.baseMapping[self.baseMapping.rfind('.')+1:]
  74. return self.DotNetExceptionName
  75. @property
  76. def DotNetExceptionName(self):
  77. return self.clrException[self.clrException.rfind('.')+1:]
  78. @property
  79. def InternalPythonType(self):
  80. if not self.parent:
  81. return 'PythonExceptions._' + self.name
  82. else:
  83. return 'PythonExceptions.' + self.name
  84. def BeginSilverlight(self, cw):
  85. if not self.silverlightSupported:
  86. cw.writeline('')
  87. cw.writeline('#if !SILVERLIGHT');
  88. def EndSilverlight(self, cw):
  89. if not self.silverlightSupported:
  90. cw.writeline('#endif // !SILVERLIGHT')
  91. cw.writeline('');
  92. def MakeNewException(self):
  93. if self.fields or self.name == 'BaseException':
  94. return 'new PythonExceptions._%s()' % (self.name)
  95. else:
  96. return 'new PythonExceptions.%s(PythonExceptions.%s)' % (self.ConcreteParent.ClrType, self.name)
  97. # format is name, args, (fields, ...), (subclasses, ...)
  98. exceptionHierarchy = ExceptionInfo('BaseException', 'IronPython.Runtime.Exceptions.PythonException', None, None, (
  99. ExceptionInfo('GeneratorExit', 'IronPython.Runtime.Exceptions.GeneratorExitException', None, (), ()),
  100. ExceptionInfo('SystemExit', 'IronPython.Runtime.Exceptions.SystemExitException', None, ('code',), ()),
  101. ExceptionInfo('KeyboardInterrupt', 'Microsoft.Scripting.KeyboardInterruptException', None, (), ()),
  102. ExceptionInfo('Exception', 'IronPython.Runtime.Exceptions.PythonException', None, (), (
  103. ExceptionInfo('StopIteration', 'IronPython.Runtime.Exceptions.StopIterationException', None, (), ()),
  104. ExceptionInfo('StandardError', 'System.ApplicationException', None, (), (
  105. ExceptionInfo('BufferError', 'IronPython.Runtime.Exceptions.BufferException', None, (), ()),
  106. ExceptionInfo('ArithmeticError', 'System.ArithmeticException', None, (), (
  107. ExceptionInfo('FloatingPointError', 'IronPython.Runtime.Exceptions.FloatingPointException', None, (), ()),
  108. ExceptionInfo('OverflowError', 'System.OverflowException', None, (), ()),
  109. ExceptionInfo('ZeroDivisionError', 'System.DivideByZeroException', None, (), ()),
  110. ),
  111. ),
  112. ExceptionInfo('AssertionError', 'IronPython.Runtime.Exceptions.AssertionException', None, (), ()),
  113. ExceptionInfo('AttributeError', 'IronPython.Runtime.Exceptions.AttributeErrorException', None, (), (), baseMapping = 'System.MissingMemberException'),
  114. ExceptionInfo('EnvironmentError', 'System.Runtime.InteropServices.ExternalException', None, ('errno', 'strerror', 'filename'), (
  115. ExceptionInfo('IOError', 'System.IO.IOException', None, (), ()),
  116. ExceptionInfo('OSError', 'IronPython.Runtime.Exceptions.OSException', None, (), (
  117. ExceptionInfo('WindowsError', 'System.ComponentModel.Win32Exception', None, ('winerror',), ()),
  118. ),
  119. ),
  120. ),
  121. ),
  122. ExceptionInfo('EOFError', 'System.IO.EndOfStreamException', None, (), ()),
  123. ExceptionInfo('ImportError', 'IronPython.Runtime.Exceptions.ImportException', None, (), ()),
  124. ExceptionInfo('LookupError', 'IronPython.Runtime.Exceptions.LookupException', None, (), (
  125. ExceptionInfo('IndexError', 'System.IndexOutOfRangeException', None, (), ()),
  126. ExceptionInfo('KeyError', 'System.Collections.Generic.KeyNotFoundException', None, (), ()),
  127. ),
  128. ),
  129. ExceptionInfo('MemoryError', 'System.OutOfMemoryException', None, (), ()),
  130. ExceptionInfo('NameError', 'IronPython.Runtime.UnboundNameException', None, (), (
  131. ExceptionInfo('UnboundLocalError', 'IronPython.Runtime.UnboundLocalException', None, (), ()),
  132. ),
  133. ),
  134. ExceptionInfo('ReferenceError', 'IronPython.Runtime.Exceptions.ReferenceException', None, (), ()),
  135. ExceptionInfo('RuntimeError', 'IronPython.Runtime.Exceptions.RuntimeException', None, (), (
  136. ExceptionInfo('NotImplementedError', 'System.NotImplementedException', None, (), ()),
  137. ),
  138. ),
  139. ExceptionInfo('SyntaxError', 'Microsoft.Scripting.SyntaxErrorException', None, ('text', 'print_file_and_line', 'filename', 'lineno', 'offset', 'msg'), (
  140. ExceptionInfo('IndentationError', 'IronPython.Runtime.Exceptions.IndentationException', None, (), (
  141. ExceptionInfo('TabError', 'IronPython.Runtime.Exceptions.TabException', None, (), ()),
  142. ),
  143. ),
  144. ),
  145. ),
  146. ExceptionInfo('SystemError', 'System.SystemException', None, (), ()),
  147. ExceptionInfo('TypeError', 'IronPython.Runtime.Exceptions.TypeErrorException', None, (), (), baseMapping = 'Microsoft.Scripting.ArgumentTypeException'),
  148. ExceptionInfo('ValueError', 'IronPython.Runtime.Exceptions.ValueErrorException', None, (), (
  149. ExceptionInfo('UnicodeError', 'IronPython.Runtime.Exceptions.UnicodeException', None, (),
  150. (
  151. ExceptionInfo('UnicodeDecodeError', 'System.Text.DecoderFallbackException', ('encoding', 'object', 'start', 'end', 'reason'), ('start', 'reason', 'object', 'end', 'encoding'), ()),
  152. ExceptionInfo('UnicodeEncodeError', 'System.Text.EncoderFallbackException', ('encoding', 'object', 'start', 'end', 'reason'), ('start', 'reason', 'object', 'end', 'encoding'), ()),
  153. ExceptionInfo('UnicodeTranslateError', 'IronPython.Runtime.Exceptions.UnicodeTranslateException', None, ('start', 'reason', 'object', 'end', 'encoding'), ()),
  154. ),
  155. ),
  156. ),
  157. baseMapping = 'System.ArgumentException'
  158. ),
  159. ),
  160. ),
  161. ExceptionInfo('Warning', 'System.ComponentModel.WarningException', None, (), (
  162. ExceptionInfo('DeprecationWarning', 'IronPython.Runtime.Exceptions.DeprecationWarningException', None, (), ()),
  163. ExceptionInfo('PendingDeprecationWarning', 'IronPython.Runtime.Exceptions.PendingDeprecationWarningException', None, (), ()),
  164. ExceptionInfo('RuntimeWarning', 'IronPython.Runtime.Exceptions.RuntimeWarningException', None, (), ()),
  165. ExceptionInfo('SyntaxWarning', 'IronPython.Runtime.Exceptions.SyntaxWarningException', None, (), ()),
  166. ExceptionInfo('UserWarning', 'IronPython.Runtime.Exceptions.UserWarningException', None, (), ()),
  167. ExceptionInfo('FutureWarning', 'IronPython.Runtime.Exceptions.FutureWarningException', None, (), ()),
  168. ExceptionInfo('ImportWarning', 'IronPython.Runtime.Exceptions.ImportWarningException', None, (), ()),
  169. ExceptionInfo('UnicodeWarning', 'IronPython.Runtime.Exceptions.UnicodeWarningException', None, (), ()),
  170. ExceptionInfo('BytesWarning', 'IronPython.Runtime.Exceptions.BytesWarningException', None, (), ()),
  171. ),
  172. ),
  173. ),
  174. ),
  175. ),
  176. )
  177. def get_exception_info(pythonName, curHierarchy):
  178. for exception in curHierarchy.subclasses:
  179. if exception.name == pythonName:
  180. return exception
  181. for exception in curHierarchy.subclasses:
  182. res = get_exception_info(pythonName, exception)
  183. if res is not None:
  184. return res
  185. def get_all_exceps(l, curHierarchy):
  186. # if we have duplicate CLR exceptions (e.g. VMSError and Exception)
  187. # only generate the one highest in the Python hierarchy
  188. for exception in curHierarchy.subclasses:
  189. found = False
  190. for e in l:
  191. if e.clrException == exception.clrException:
  192. found = True
  193. break
  194. if not found:
  195. l.append(exception)
  196. for exception in curHierarchy.subclasses:
  197. get_all_exceps(l, exception)
  198. return l
  199. ip = clr.LoadAssemblyByPartialName('ironpython')
  200. ms = clr.LoadAssemblyByPartialName('Microsoft.Scripting')
  201. md = clr.LoadAssemblyByPartialName('Microsoft.Dynamic')
  202. sysdll = clr.LoadAssemblyByPartialName('System')
  203. def get_type(name):
  204. if name.startswith('IronPython'): return ip.GetType(name)
  205. if name.startswith('Microsoft.Scripting'):
  206. res = ms.GetType(name)
  207. return res if res is not None else md.GetType(name)
  208. if name.startswith('System.ComponentModel'): return sysdll.GetType(name)
  209. return System.Type.GetType(name)
  210. def exception_distance(a):
  211. distance = 0
  212. while a.FullName != "System.Exception":
  213. a = a.BaseType
  214. distance += 1
  215. return distance
  216. def get_compare_name(ex_info):
  217. return ex_info.baseMapping or ex_info.clrException
  218. def compare_exceptions(a, b):
  219. a, b = get_compare_name(a), get_compare_name(b)
  220. ta = get_type(a)
  221. tb = get_type(b)
  222. if ta == None:
  223. raise Exception("Exception class not found %s " % a)
  224. if tb == None:
  225. raise Exception("Exception class not found %s " % b)
  226. if ta.IsSubclassOf(tb): return -1
  227. if tb.IsSubclassOf(ta): return 1
  228. da = exception_distance(ta)
  229. db = exception_distance(tb)
  230. # put exceptions further from System.Exception 1st, those further later...
  231. if da != db: return db - da
  232. return cmp(ta.Name, tb.Name)
  233. def gen_topython_helper(cw):
  234. cw.enter_block("private static BaseException/*!*/ ToPythonHelper(System.Exception clrException)")
  235. allExceps = get_all_exceps([], exceptionHierarchy)
  236. allExceps.sort(cmp=compare_exceptions)
  237. for x in allExceps[:-1]: # skip System.Exception which is last...
  238. if not x.silverlightSupported: cw.writeline('#if !SILVERLIGHT')
  239. cw.writeline('if (clrException is %s) return %s;' % (x.ExceptionMappingName, x.MakeNewException()))
  240. if not x.silverlightSupported: cw.writeline('#endif')
  241. cw.writeline('return new BaseException(Exception);')
  242. cw.exit_block()
  243. def get_clr_name(e):
  244. return e.replace('Error', '') + 'Exception'
  245. FACTORY = """
  246. public static Exception %(name)s(string format, params object[] args) {
  247. return new %(clrname)s(string.Format(format, args));
  248. }"""
  249. def factory_gen(cw):
  250. for e in pythonExcs:
  251. cw.write(FACTORY, name=e, clrname=get_clr_name(e))
  252. CLASS1 = """
  253. [Serializable]
  254. public class %(name)s : %(supername)s, IPythonAwareException {
  255. private object _pyExceptionObject;
  256. private List<DynamicStackFrame> _frames;
  257. private TraceBack _traceback;
  258. public %(name)s() : base() { }
  259. public %(name)s(string msg) : base(msg) { }
  260. public %(name)s(string message, Exception innerException)
  261. : base(message, innerException) {
  262. }
  263. #if !SILVERLIGHT // SerializationInfo
  264. protected %(name)s(SerializationInfo info, StreamingContext context) : base(info, context) { }
  265. [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Security", "CA2123:OverrideLinkDemandsShouldBeIdenticalToBase")]
  266. public override void GetObjectData(SerializationInfo info, StreamingContext context) {
  267. info.AddValue("frames", _frames);
  268. info.AddValue("traceback", _traceback);
  269. base.GetObjectData(info, context);
  270. }
  271. #endif
  272. object IPythonAwareException.PythonException {
  273. get {
  274. if (_pyExceptionObject == null) {
  275. var newEx = %(make_new_exception)s;
  276. newEx.InitializeFromClr(this);
  277. _pyExceptionObject = newEx;
  278. }
  279. return _pyExceptionObject;
  280. }
  281. set { _pyExceptionObject = value; }
  282. }
  283. List<DynamicStackFrame> IPythonAwareException.Frames {
  284. get { return _frames; }
  285. set { _frames = value; }
  286. }
  287. TraceBack IPythonAwareException.TraceBack {
  288. get { return _traceback; }
  289. set { _traceback = value; }
  290. }
  291. }
  292. """
  293. def gen_one_exception(cw, e):
  294. supername = getattr(exceptions, e).__bases__[0].__name__
  295. if not supername in pythonExcs and supername != 'Warning':
  296. supername = ''
  297. cw.write(CLASS1, name=get_clr_name(e), supername=get_clr_name(supername), make_new_exception = get_exception_info(e, exceptionHierarchy).MakeNewException())
  298. def gen_one_exception_maker(e):
  299. def gen_one_exception_specialized(x):
  300. return gen_one_exception(x, e)
  301. return gen_one_exception_specialized
  302. def fix_object(name):
  303. if name == "object": return "@object"
  304. return name
  305. def gen_one_new_exception(cw, exception, parent):
  306. if exception.fields:
  307. exception.BeginSilverlight(cw)
  308. cw.writeline('[MultiRuntimeAware]')
  309. cw.writeline('private static PythonType %sStorage;' % (exception.name, ))
  310. cw.enter_block('public static PythonType %s' % (exception.name, ))
  311. cw.enter_block('get')
  312. cw.enter_block('if (%sStorage == null)' % (exception.name, ))
  313. cw.enter_block('lock (_pythonExceptionsLock)')
  314. cw.writeline('%sStorage = CreateSubType(%s, typeof(_%s), msg => new %s(msg));' % (exception.name, exception.parent.PythonType, exception.name, exception.DotNetExceptionName))
  315. cw.exit_block() # lock
  316. cw.exit_block() # if
  317. cw.writeline('return %sStorage;' % (exception.name, ))
  318. cw.exit_block()
  319. cw.exit_block()
  320. cw.writeline()
  321. cw.writeline('[PythonType("%s"), PythonHidden, DynamicBaseTypeAttribute, Serializable]' % exception.name)
  322. if exception.ConcreteParent.fields:
  323. cw.enter_block('public partial class _%s : _%s' % (exception.name, exception.ConcreteParent.name))
  324. else:
  325. cw.enter_block('public partial class _%s : %s' % (exception.name, exception.ConcreteParent.name))
  326. for field in exception.fields:
  327. cw.writeline('private object _%s;' % field)
  328. if exception.fields:
  329. cw.writeline('')
  330. cw.writeline('public _%s() : base(%s) { }' % (exception.name, exception.name))
  331. cw.writeline('public _%s(PythonType type) : base(type) { }' % (exception.name, ))
  332. cw.writeline('')
  333. cw.enter_block('public new static object __new__(PythonType cls, params object[] args)')
  334. cw.writeline('return Activator.CreateInstance(cls.UnderlyingSystemType, cls);')
  335. cw.exit_block()
  336. cw.writeline('')
  337. if exception.args:
  338. argstr = ', '.join(['object ' + fix_object(x) for x in exception.args])
  339. cw.enter_block('public void __init__(%s)' % (argstr))
  340. for arg in exception.args:
  341. cw.writeline('_%s = %s;' % (arg, fix_object(arg)))
  342. cw.writeline('args = PythonTuple.MakeTuple(' + ', '.join([fix_object(x) for x in exception.args]) + ');')
  343. cw.exit_block()
  344. cw.writeline('')
  345. cw.enter_block('public override void __init__(params object[] args)')
  346. cw.enter_block('if (args == null || args.Length != %d)' % (len(exception.args), ))
  347. cw.writeline('throw PythonOps.TypeError("__init__ takes exactly %d arguments ({0} given)", args.Length);' % len(exception.args))
  348. cw.exit_block()
  349. cw.writeline('__init__(' + ', '.join([fix_object(x) for x in exception.args]) + ');')
  350. cw.exit_block()
  351. cw.writeline('')
  352. for field in exception.fields:
  353. cw.enter_block('public object %s' % fix_object(field))
  354. cw.writeline('get { return _%s; }' % field)
  355. cw.writeline('set { _%s = value; }' % field)
  356. cw.exit_block()
  357. cw.writeline('')
  358. cw.exit_block()
  359. cw.writeline('')
  360. exception.EndSilverlight(cw)
  361. else:
  362. cw.writeline('[MultiRuntimeAware]')
  363. cw.writeline('private static PythonType %sStorage;' % (exception.name, ))
  364. cw.enter_block('public static PythonType %s' % (exception.name, ))
  365. cw.enter_block('get')
  366. cw.enter_block('if (%sStorage == null)' % (exception.name, ))
  367. cw.enter_block('lock (_pythonExceptionsLock)')
  368. cw.writeline('%sStorage = CreateSubType(%s, "%s", msg => new %s(msg));' % (exception.name, exception.parent.PythonType, exception.name, exception.DotNetExceptionName))
  369. cw.exit_block() # lock
  370. cw.exit_block() # if
  371. cw.writeline('return %sStorage;' % (exception.name, ))
  372. cw.exit_block()
  373. cw.exit_block()
  374. cw.writeline()
  375. for child in exception.subclasses:
  376. gen_one_new_exception(cw, child, exception)
  377. def newstyle_gen(cw):
  378. for child in exceptionHierarchy.subclasses:
  379. gen_one_new_exception(cw, child, exceptionHierarchy)
  380. def gen_one_exception_module_entry(cw, exception, parent):
  381. exception.BeginSilverlight(cw)
  382. cw.write("public static PythonType %s = %s;" % (exception.name, exception.InternalPythonType))
  383. exception.EndSilverlight(cw)
  384. for child in exception.subclasses:
  385. gen_one_exception_module_entry(cw, child, exception)
  386. def module_gen(cw):
  387. cw.write("public static object BaseException = DynamicHelpers.GetPythonTypeFromType(typeof(PythonExceptions.BaseException));")
  388. for child in exceptionHierarchy.subclasses:
  389. gen_one_exception_module_entry(cw, child, exceptionHierarchy)
  390. def gen_one_exception_builtin_entry(cw, exception, parent):
  391. exception.BeginSilverlight(cw)
  392. cw.enter_block("public static PythonType %s" % (exception.name, ))
  393. if exception.fields:
  394. cw.write('get { return %s; }' % (exception.InternalPythonType, ))
  395. else:
  396. cw.write('get { return %s; }' % (exception.InternalPythonType, ))
  397. cw.exit_block()
  398. exception.EndSilverlight(cw)
  399. for child in exception.subclasses:
  400. gen_one_exception_builtin_entry(cw, child, exception)
  401. def builtin_gen(cw):
  402. for child in exceptionHierarchy.subclasses:
  403. gen_one_exception_builtin_entry(cw, child, exceptionHierarchy)
  404. def main():
  405. gens = [
  406. ("ToPython Exception Helper", gen_topython_helper),
  407. ("Exception Factories", factory_gen),
  408. ("Python New-Style Exceptions", newstyle_gen),
  409. ("builtin exceptions", builtin_gen),
  410. ]
  411. for e in pythonExcs:
  412. gens.append((get_clr_name(e), gen_one_exception_maker(e)))
  413. return generate(*gens)
  414. if __name__ == "__main__":
  415. main()