This repository has been archived by the owner on Apr 9, 2023. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy patherror.cr
133 lines (111 loc) · 2.77 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
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
require "levenshtein" # string distance
class Error
def initialize(@type : String, @message : String, @line : Int32, @col : Int32, @len : Int32, @truncate : Bool = false, @hint : String? = nil)
end
def throw!
print Colors::RED
print @type
print Colors::RESET
print ": "
puts @message
print "On line "
print @line
print ", col "
print @col
print ":\n\n"
print Colors::BLUE
print @line
print " |"
print Colors::RESET
sourceline = (Lexer.original_source.split "\n")[@line]
if @truncate
sourceline = sourceline[0..@col+@len-1]
end
print sourceline
if @truncate
print "..."
end
print "\n"
print " " * (@line.to_s.size + 2 + @col)
print Colors::RED
print Colors::BOLD
print "^" * @len
print "\n\n"
if @hint
print Colors::YELLOW
print Colors::BOLD
print "Hint: "
puts @hint
end
print Colors::RESET
exit 1
end
end
##############
class LexingError < Error
def initialize(message : String, line : Int32, col : Int32, len : Int32)
super("LexingError", message, line, col, len)
end
end
class UnterminatedStringError < LexingError
def initialize(line : Int32, col : Int32)
super("Unterminated string literal", line, col, 5)
@truncate = true
@hint = "You missed a quote somewhere. Add one to terminate the string."
end
end
# todo: maintain
LIST_OF_COMMON_SYMBOLS = [
"==",
">=",
"<=",
"!=",
"->",
"=>",
"=",
"+",
"-",
"*",
"/",
":",
"(",
")",
"{",
"}",
"&&",
"||",
"!",
"**"
]
class InvalidTokenError < LexingError
def initialize(tok : String, @line : Int32, @col : Int32)
super("Invalid token \"#{tok}\"", line, col, tok.size)
@hint = "This is a typo."
full_in_spaces = ((Lexer.original_source.split "\n")[@line].split " ").find { |s| s.includes?(tok) }
if !full_in_spaces # make type system happy
return
end
closest = (LIST_OF_COMMON_SYMBOLS.sort { |x, y| Levenshtein.distance(full_in_spaces, x) <=> Levenshtein.distance(full_in_spaces, y) }) [0]
if !closest
return
end
@hint = "Did you mean " + Colors::MAGENTA + closest +
Colors::YELLOW + "?"
end
end
####
class ParsingError < Error
def initialize(message : String, line : Int32, col : Int32, len : Int32)
super("SyntaxError", message, line, col, len)
end
end
class ExpectError < ParsingError
def initialize(expected : String, found : String, line : Int32, col : Int32, len : Int32, wasparsing : String? = nil, customHint : String? = nil)
super("Expected " + expected + ", found " + found, line, col, len)
if wasparsing
@hint = "While trying to parse " + wasparsing + ", this was found instead."
elsif customHint
@hint = customHint
end
end
end