PageRenderTime 48ms CodeModel.GetById 21ms RepoModel.GetById 0ms app.codeStats 0ms

/pk-core/pk-core/error.lua

http://github.com/logiceditor-com/codebase
Lua | 133 lines | 96 code | 24 blank | 13 comment | 8 complexity | 0620f809b3f2f23e0801c6371c0546c1 MD5 | raw file
  1. --------------------------------------------------------------------------------
  2. -- error.lua: error handling convenience wrapper
  3. -- This file is a part of pk-core library
  4. -- Copyright (c) Alexander Gladysh <ag@logiceditor.com>
  5. -- Copyright (c) Dmitry Potapov <dp@logiceditor.com>
  6. -- See file `COPYRIGHT` for the license
  7. --------------------------------------------------------------------------------
  8. local arguments,
  9. optional_arguments,
  10. method_arguments
  11. = import 'lua-nucleo/args.lua'
  12. {
  13. 'arguments',
  14. 'optional_arguments',
  15. 'method_arguments'
  16. }
  17. local is_table
  18. = import 'lua-nucleo/type.lua'
  19. {
  20. 'is_table'
  21. }
  22. local unique_object
  23. = import 'lua-nucleo/misc.lua'
  24. {
  25. 'unique_object'
  26. }
  27. local make_loggers
  28. = import 'pk-core/log.lua'
  29. {
  30. 'make_loggers'
  31. }
  32. --------------------------------------------------------------------------------
  33. local log, dbg, spam, log_error = make_loggers("pk-core/error", "ERR")
  34. --------------------------------------------------------------------------------
  35. local error_tag = unique_object()
  36. local is_error_object = function(err)
  37. return not not (is_table(err) and err[1] == error_tag)
  38. end
  39. local error_handler_for_call = function(msg)
  40. if not is_error_object(msg) then
  41. msg = debug.traceback(msg)
  42. log_error(msg)
  43. else
  44. spam("caught: ", debug.traceback(msg[2])) -- Required for debugging
  45. end
  46. return msg
  47. end
  48. local create_error_object = function(error_id)
  49. return { error_tag, error_id }
  50. end
  51. local get_error_id = function(err)
  52. if is_error_object(err) then
  53. return err[2]
  54. end
  55. return nil
  56. end
  57. local throw = function(error_id)
  58. return error(create_error_object(error_id))
  59. end
  60. local pcall_adaptor_for_call = function(status, ...)
  61. if not status then
  62. local err = (...)
  63. local error_id = get_error_id(err)
  64. if error_id ~= nil then
  65. return nil, error_id
  66. end
  67. return error(err) -- Not our error, rethrow
  68. end
  69. return ... -- TODO: Shouldn't we return true here?
  70. end
  71. --------------------------------------------------------------------------------
  72. -- TODO: HEAVY! Optimize?
  73. local call = function(fn, ...)
  74. local nargs, args = select("#", ...), { ... }
  75. return pcall_adaptor_for_call(
  76. xpcall(
  77. function()
  78. return fn(unpack(args, 1, nargs))
  79. end,
  80. error_handler_for_call
  81. )
  82. )
  83. end
  84. local fail = function(error_id, msg)
  85. log_error(msg)
  86. throw(error_id)
  87. end
  88. local try = function(error_id, result, err, ...)
  89. if result == nil then
  90. fail(error_id, err)
  91. end
  92. return result, err, ...
  93. end
  94. local rethrow = function(error_id, err)
  95. if not is_error_object(err) then
  96. return fail(error_id, err)
  97. end
  98. error(err) -- Rethrowing our error, ignoring error_id
  99. end
  100. --------------------------------------------------------------------------------
  101. return
  102. {
  103. call = call;
  104. try = try;
  105. fail = fail;
  106. rethrow = rethrow;
  107. --
  108. error_handler_for_call = error_handler_for_call;
  109. }