/
error.cr
100 lines (84 loc) · 2.61 KB
/
error.cr
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
96
97
98
99
100
module Novika
# Holds and accepts information about an error.
#
# Errors are raised when a certain case is undesired, unhandleable,
# or otherwise inappropriate to some form of computation.
#
# Errors can be *handled* and *unhandled*. *Unhandled* errors
# generate an error `report` (generally to STDERR, but this
# depends on the frontend). They are fatal for the program
# they occur in.
#
# *Death handlers*, or *death traps*, when set up in code blocks
# and/or their relatives, allow errors to be *handled*. For this
# reason, errors are Novika `Form`s, and can be manipulated,
# reported, and inspected from Novika.
class Error < Exception
include Form
# How many trace entries to display at max.
MAX_TRACE = 64
# Returns a string describing the reasons of this error.
getter details : String
# Returns the form that (speculatively) caused this error.
getter! form : Form
# Holds a reference to the continuations block at the time
# of death.
property conts : Block?
def initialize(@details, @form = nil)
end
def desc(io : IO)
io << "error: '" << details << "'"
end
def self.typedesc
"error"
end
# Reports about this error to *io*.
#
# Note: Colorize is used for colors and emphasis. If you
# do not want Colorize in *io*, you can temporarily disable
# it by setting `Colorize.enabled = false`.
def report(io : IO)
if conts = self.conts
b = Math.max(0, conts.count - MAX_TRACE)
e = conts.count
unless b.zero?
io << " │ … " << b - 1 << " continuation(s) omitted …"
io.puts
end
(b...e).each do |index|
io << " ╿ due to "
cont = conts.at(index).as?(Block)
code = cont.try &.at?(Engine::C_BLOCK_AT).as?(Block)
unless cont && code
io.puts "[malformed continuation]"
next
end
if top = code.top?
io << "'" << (top || "[nothing]").colorize.bold << "', which was opened here:"
else
io << "the following block:"
end
io.puts
io << " │ "
code.spot(io)
io.puts
end
end
if form?
io.puts " ╿ this form is invalid, and is the cause of death:"
io << " │ " << form
io.puts
end
io << "Sorry: ".colorize.red.bold << details
case details.byte_at?(details.bytesize - 1)
when '!', '?', '.'
else
io << '.'
end
io.puts
end
def to_s(io)
io << "[" << details << "]"
end
end
end