aboutsummaryrefslogtreecommitdiffstats
path: root/alv/error.moon
blob: c049f8f1913227164be030278217a124e39528ec (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
----
-- Language error and traceback.
--
-- @classmod Error

unpack or= table.unpack

class Error
--- members
-- @section members

  --- append a traceback frame.
  --
  -- `where` should denote where the Error occured and fit grammatically to
  -- complete the sentence `"{error} occured while {where}"`
  --
  -- @tparam string where
  add_frame: (where) => @trace ..= "\n  while #{where}"

  __tostring: =>
    str = "#{@kind} error: #{@message}"
    if @detail
      str ..= "\n#{@detail}"
    if @trace
      str ..= @trace
    str

--- static functions
-- @section static

  --- create a new Error.
  --
  -- `kind` should be one of:
  --
  -- - `'reference'`: error concerning symbol resolution
  -- - `'argument'`: error concerning Op argument matching
  -- - `'implementation'`: error in the Lua/MoonScript implementation of alive.
  --   Should not occur in normal operation, and constitutes a bug.
  --
  -- @classmethod
  -- @tparam string kind
  -- @tparam string message
  -- @tparam ?string detail
  new: (@kind, @message, @detail) =>
    @trace = ''

  handler = (err) ->
    if err.__class == Error
      err
    else
      trace = debug.traceback "Lua error below:", 2
      Error 'implementation', err, trace

  --- Wrap function errors in a traceback frame.
  --
  -- Execute `fn(...)`, and turn any error thrown as a result into an
  -- `Error` instance, before re-throwing it.
  --
  -- When `Error` instances are caught, `frame` is added to the traceback.
  -- All other error values are turned into `'implementation'` Errors.
  --
  -- @tparam string frame
  -- @tparam function fn
  @wrap: (frame, fn, ...) ->
    results = { xpcall fn, handler, ... }
    ok = table.remove results, 1
    if ok
      unpack results
    else
      results[1]\add_frame frame if frame
      error results[1]

  --- Capture and wrap function errors in traceback frame.
  --
  -- Execute `fn(...)`, and turn any error thrown as a result into an
  -- `Error` instance, before re-throwing it.
  --
  -- When `Error` instances are caught, `frame` is added to the traceback.
  -- All other error values are turned into `'implementation'` Errors.
  --
  -- @tparam ?string frame
  -- @tparam function fn
  -- @treturn boolean `ok` true if exeuction suceeded without errors
  -- @treturn Error|any `error_or_results` the `Error` instance or results
  @try: (frame, fn, ...) ->
    results = { xpcall fn, handler, ... }
    ok = table.remove results, 1
    if ok
      ok, unpack results
    else
      results[1]\add_frame frame if frame
      ok, unpack results
{
  :Error
}