1 // Copyright 2017 The Fuchsia Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style license that can be
3 // found in the LICENSE file.
4
5 #include "banjo/error_reporter.h"
6 #include "banjo/source_location.h"
7 #include "banjo/string_view.h"
8 #include "banjo/token.h"
9
10 namespace banjo {
11
MakeSquiggle(const std::string & surrounding_line,int column)12 std::string MakeSquiggle(const std::string& surrounding_line, int column) {
13 std::string squiggle;
14 for (int i = 0; i < column; i++) {
15 switch (surrounding_line[i]) {
16 case '\t':
17 squiggle.push_back('\t');
18 default:
19 squiggle.push_back(' ');
20 }
21 }
22 squiggle.push_back('^');
23 return squiggle;
24 }
25
FormatError(const SourceLocation & location,StringView message,size_t squiggle_size=0u)26 std::string FormatError(const SourceLocation& location, StringView message, size_t squiggle_size = 0u) {
27 SourceFile::Position position;
28 std::string surrounding_line = location.SourceLine(&position);
29
30 std::string squiggle = MakeSquiggle(surrounding_line, position.column);
31 if (squiggle_size != 0u) {
32 --squiggle_size;
33 }
34 squiggle += std::string(squiggle_size, '~');
35 // Some tokens (like string literals) can span multiple
36 // lines. Truncate the string to just one line at most. The
37 // containing line contains a newline, so drop it when
38 // comparing sizes.
39 size_t line_size = surrounding_line.size() - 1;
40 if (squiggle.size() > line_size) {
41 squiggle.resize(line_size);
42 }
43
44 // Many editors and IDEs recognize errors in the form of
45 // filename:linenumber:column: error: descriptive-test-here\n
46 std::string error = location.position();
47 error.append(": error: ");
48 error.append(message);
49 error.push_back('\n');
50 error.append(surrounding_line);
51 error.append(squiggle);
52
53 return error;
54 }
55
56 // ReportError records an error with the location, message, source line, and
57 // position indicator.
58 //
59 // filename:line:col: error: message
60 // sourceline
61 // ^
ReportError(const SourceLocation & location,StringView message)62 void ErrorReporter::ReportError(const SourceLocation& location, StringView message) {
63 auto error = FormatError(location, message);
64 errors_.push_back(std::move(error));
65 }
66
67 // ReportError records an error with the location, message, source line,
68 // position indicator, and tildes under the token reported.
69 //
70 // filename:line:col: error: message
71 // sourceline
72 // ^~~~
ReportError(const Token & token,StringView message)73 void ErrorReporter::ReportError(const Token& token, StringView message) {
74 auto token_location = token.location();
75 auto token_data = token_location.data();
76 auto error = FormatError(token_location, message, token_data.size());
77 errors_.push_back(std::move(error));
78 }
79
80 // ReportError records the provided message.
ReportError(StringView message)81 void ErrorReporter::ReportError(StringView message) {
82 std::string error("error: ");
83 error.append(message);
84 errors_.push_back(std::move(error));
85 }
86
PrintReports()87 void ErrorReporter::PrintReports() {
88 for (const auto& error : errors_) {
89 fprintf(stderr, "%s\n", error.data());
90 }
91 }
92
93 } // namespace banjo
94