Line | Branch | Exec | Source |
---|---|---|---|
1 | #include "parsing_error.h" | ||
2 | |||
3 | #include "ast/magic.h" | ||
4 | #include "ast/ops.h" | ||
5 | #include "lexer/lexer.h" | ||
6 | #include "lexer/unlex.h" | ||
7 | #include "utilities/strings.h" | ||
8 | |||
9 | namespace lython { | ||
10 | |||
11 | ParsingError::ParsingError(Array<int> expected, Token token, Node* obj, CodeLocation loc): | ||
12 | ✗ | ParsingError(expected, token, loc) { | |
13 | ✗ | switch (obj->family()) { | |
14 | ✗ | case NodeFamily::Expression: expr = (ExprNode*)obj; | |
15 | ✗ | case NodeFamily::Pattern: pat = (Pattern*)obj; | |
16 | ✗ | case NodeFamily::Statement: stmt = (StmtNode*)obj; | |
17 | ✗ | default: break; | |
18 | } | ||
19 | ✗ | } | |
20 | |||
21 | void add_wip_expr(ParsingError& err, StmtNode* stmt) { err.stmt = stmt; } | ||
22 | |||
23 | void add_wip_expr(ParsingError& err, ExprNode* expr) { err.expr = expr; } | ||
24 | |||
25 | void add_wip_expr(ParsingError& err, Node* expr) { | ||
26 |
4/4✓ Branch 1 taken 124 times.
✓ Branch 2 taken 28 times.
✓ Branch 3 taken 346 times.
✓ Branch 4 taken 67 times.
|
565 | switch (expr->family()) { |
27 | 124 | case NodeFamily::Expression: err.expr = (ExprNode*)expr; | |
28 | 152 | case NodeFamily::Pattern: err.pat = (Pattern*)expr; | |
29 | 498 | case NodeFamily::Statement: err.stmt = (StmtNode*)expr; | |
30 | 565 | default: break; | |
31 | } | ||
32 | 565 | } | |
33 | |||
34 | Node* get_expr(ParsingError const& error) { | ||
35 |
2/2✓ Branch 0 taken 498 times.
✓ Branch 1 taken 67 times.
|
565 | if (error.stmt) { |
36 | 498 | return error.stmt; | |
37 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
|
67 | } else if (error.expr) { |
38 | ✗ | return error.expr; | |
39 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
|
67 | } else if (error.pat) { |
40 | ✗ | return error.pat; | |
41 | } | ||
42 | 67 | return nullptr; | |
43 | } | ||
44 | |||
45 | CommonAttributes* get_code_loc(ParsingError const& error) { | ||
46 |
2/2✓ Branch 0 taken 498 times.
✓ Branch 1 taken 67 times.
|
565 | if (error.stmt) { |
47 |
1/2✓ Branch 0 taken 498 times.
✗ Branch 1 not taken.
|
498 | return error.stmt; |
48 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
|
67 | } else if (error.expr) { |
49 | ✗ | return error.expr; | |
50 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
|
67 | } else if (error.pat) { |
51 | ✗ | return error.pat; | |
52 | } | ||
53 | 67 | return nullptr; | |
54 | } | ||
55 | |||
56 | String get_parent(ParsingError const& error) { | ||
57 |
2/2✓ Branch 0 taken 498 times.
✓ Branch 1 taken 67 times.
|
565 | if (error.stmt) { |
58 | 498 | return shortprint(get_parent(error.stmt)); | |
59 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
|
67 | } else if (error.expr) { |
60 | ✗ | return shortprint(get_parent(error.expr)); | |
61 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 67 times.
|
67 | } else if (error.pat) { |
62 | ✗ | return shortprint(get_parent(error.pat)); | |
63 | } | ||
64 | |||
65 |
1/1✓ Branch 2 taken 67 times.
|
67 | return "<module>"; |
66 | } | ||
67 | |||
68 | String get_filename(ParsingErrorPrinter* printer) { | ||
69 | ✗ | if (printer->lexer) { | |
70 | ✗ | return printer->lexer->file_name(); | |
71 | } | ||
72 | ✗ | return "<input>"; | |
73 | } | ||
74 | |||
75 | void ParsingErrorPrinter::print_ast(ParsingError const& error, | ||
76 | Node* node, | ||
77 | CommonAttributes* srcloc) { | ||
78 | // Print what we were able to parse | ||
79 | { | ||
80 | ✗ | bool written = false; | |
81 | |||
82 | ✗ | if (node) { | |
83 | ✗ | auto noline_buf = NoNewLine(out); | |
84 | ✗ | std::ostream noline(&noline_buf); | |
85 | ✗ | codeline(); | |
86 | ✗ | noline << str(node); | |
87 | ✗ | noline.flush(); | |
88 | ✗ | written = true; | |
89 | ✗ | } | |
90 | |||
91 | // Print the tokens that we were not able to parse | ||
92 | ✗ | if (error.remaining.size() > 0) { | |
93 | ✗ | Unlex unlex; | |
94 | ✗ | unlex.format(out, error.remaining); | |
95 | ✗ | written = true; | |
96 | } | ||
97 | |||
98 | ✗ | if (written) { | |
99 | // Underline error if possible | ||
100 | ✗ | if (srcloc) { | |
101 | ✗ | underline(*srcloc); | |
102 | } else { | ||
103 | ✗ | underline(error.received_token); | |
104 | } | ||
105 | } | ||
106 | } | ||
107 | ✗ | } | |
108 | |||
109 | void ParsingErrorPrinter::print_tok(ParsingError const& error, CommonAttributes* srcloc) { | ||
110 | 565 | Unlex unlex; | |
111 | |||
112 |
1/1✓ Branch 1 taken 565 times.
|
565 | codeline(); |
113 |
1/1✓ Branch 1 taken 565 times.
|
565 | unlex.format(out, error.line); |
114 | |||
115 | // Underline error if possible | ||
116 |
1/1✓ Branch 1 taken 565 times.
|
565 | underline(error.received_token); |
117 | 565 | } | |
118 | |||
119 | void ParsingErrorPrinter::print(ParsingError const& error) { | ||
120 |
1/1✓ Branch 1 taken 565 times.
|
565 | String filename = get_filename(); |
121 | 565 | Node* node = get_expr(error); | |
122 | 565 | CommonAttributes* srcloc = get_code_loc(error); | |
123 |
1/1✓ Branch 1 taken 565 times.
|
565 | String parent = get_parent(error); |
124 | |||
125 | 565 | int line = error.received_token.line(); | |
126 | |||
127 |
7/7✓ Branch 1 taken 565 times.
✓ Branch 4 taken 565 times.
✓ Branch 7 taken 565 times.
✓ Branch 10 taken 565 times.
✓ Branch 13 taken 565 times.
✓ Branch 16 taken 565 times.
✓ Branch 19 taken 565 times.
|
565 | firstline() << "File \"" << filename << "\", line " << line << ", in " << parent; |
128 | |||
129 | // Lython own code loc | ||
130 | #if WITH_LOG | ||
131 |
1/2✓ Branch 0 taken 565 times.
✗ Branch 1 not taken.
|
565 | if (with_compiler_code_loc) { |
132 |
3/3✓ Branch 1 taken 565 times.
✓ Branch 4 taken 565 times.
✓ Branch 7 taken 565 times.
|
565 | newline() << error.loc.repr(); |
133 | } | ||
134 | #endif | ||
135 | |||
136 | // Error message | ||
137 | if (false) { | ||
138 | print_ast(error, node, srcloc); | ||
139 | } else { | ||
140 |
1/1✓ Branch 1 taken 565 times.
|
565 | print_tok(error, srcloc); |
141 | } | ||
142 | |||
143 |
3/3✓ Branch 1 taken 565 times.
✓ Branch 4 taken 565 times.
✓ Branch 7 taken 565 times.
|
565 | errorline() << error.error_kind << ": "; |
144 |
2/2✓ Branch 1 taken 251 times.
✓ Branch 2 taken 314 times.
|
565 | if (error.expected_tokens.size() > 0) { |
145 | 251 | Array<String> toks; | |
146 |
2/2✓ Branch 1 taken 251 times.
✓ Branch 5 taken 251 times.
|
502 | std::transform(std::begin(error.expected_tokens), |
147 | 251 | std::end(error.expected_tokens), | |
148 | std::back_inserter(toks), | ||
149 | [](int tok) -> String { return to_human_name(tok); }); | ||
150 | |||
151 |
2/2✓ Branch 2 taken 251 times.
✓ Branch 5 taken 251 times.
|
251 | String expected = join("|", toks); |
152 | |||
153 |
5/5✓ Branch 1 taken 251 times.
✓ Branch 4 taken 251 times.
✓ Branch 7 taken 251 times.
✓ Branch 11 taken 251 times.
✓ Branch 14 taken 251 times.
|
251 | out << "Expected: " << expected << " token but got " << to_human_name(error.received_token); |
154 | 251 | } else { | |
155 |
1/1✓ Branch 1 taken 314 times.
|
314 | out << error.message; |
156 | } | ||
157 | |||
158 |
1/1✓ Branch 1 taken 565 times.
|
565 | end(); |
159 | 565 | } | |
160 | |||
161 | String shortprint(Node const* node) { | ||
162 |
2/2✓ Branch 0 taken 99 times.
✓ Branch 1 taken 532 times.
|
631 | if (node->kind == NodeKind::FunctionDef) { |
163 | 99 | FunctionDef const* fun = static_cast<FunctionDef const*>(node); | |
164 | 99 | return str(fun->name); | |
165 | } | ||
166 |
1/2✗ Branch 0 not taken.
✓ Branch 1 taken 532 times.
|
532 | if (node->kind == NodeKind::ClassDef) { |
167 | ✗ | ClassDef const* def = static_cast<ClassDef const*>(node); | |
168 | ✗ | return str(def->name); | |
169 | } | ||
170 |
2/2✓ Branch 0 taken 524 times.
✓ Branch 1 taken 8 times.
|
532 | if (node->kind == NodeKind::Module) { |
171 |
1/1✓ Branch 2 taken 524 times.
|
524 | return "<module>"; |
172 | } | ||
173 | 8 | return str(node); | |
174 | } | ||
175 | |||
176 | Node const* get_parent(Node const* parent) { | ||
177 | 623 | Node const* n = parent->get_parent(); | |
178 | 623 | Node const* p = parent; | |
179 | |||
180 |
1/2✓ Branch 0 taken 711 times.
✗ Branch 1 not taken.
|
711 | while (n != nullptr) { |
181 | |||
182 |
2/2✓ Branch 0 taken 524 times.
✓ Branch 1 taken 187 times.
|
711 | if (n->kind == NodeKind::Module) { |
183 | 524 | return n; | |
184 | } | ||
185 | |||
186 |
2/2✓ Branch 0 taken 99 times.
✓ Branch 1 taken 88 times.
|
187 | if (n->kind == NodeKind::FunctionDef) { |
187 | 99 | return n; | |
188 | } | ||
189 | 88 | p = n; | |
190 | 88 | n = n->get_parent(); | |
191 | } | ||
192 | |||
193 | ✗ | return p; | |
194 | } | ||
195 | |||
196 | } // namespace lython | ||
197 |