1 /*
2  * Copyright 2018 WebAssembly Community Group participants
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 #include "src/error-formatter.h"
18 
19 namespace wabt {
20 
21 namespace {
22 
FormatError(const Error & error,Location::Type location_type,const Color & color,LexerSourceLineFinder * line_finder,int source_line_max_length,int indent)23 std::string FormatError(const Error& error,
24                         Location::Type location_type,
25                         const Color& color,
26                         LexerSourceLineFinder* line_finder,
27                         int source_line_max_length,
28                         int indent) {
29   std::string indent_str(indent, ' ');
30   std::string result = indent_str;
31 
32   result += color.MaybeBoldCode();
33 
34   const Location& loc = error.loc;
35   if (!loc.filename.empty()) {
36     result += loc.filename.to_string();
37     result += ":";
38   }
39 
40   if (location_type == Location::Type::Text) {
41     result += StringPrintf("%d:%d: ", loc.line, loc.first_column);
42   } else if (loc.offset != kInvalidOffset) {
43     result += StringPrintf("%07" PRIzx ": ", loc.offset);
44   }
45 
46   result += color.MaybeRedCode();
47   result += GetErrorLevelName(error.error_level);
48   result += ": ";
49   result += color.MaybeDefaultCode();
50 
51   result += error.message;
52   result += '\n';
53 
54   LexerSourceLineFinder::SourceLine source_line;
55   if (line_finder) {
56     line_finder->GetSourceLine(loc, source_line_max_length, &source_line);
57   }
58 
59   if (!source_line.line.empty()) {
60     result += indent_str;
61     result += source_line.line;
62     result += '\n';
63     result += indent_str;
64 
65     size_t num_spaces = (loc.first_column - 1) - source_line.column_offset;
66     size_t num_carets = loc.last_column - loc.first_column;
67     num_carets = std::min(num_carets, source_line.line.size() - num_spaces);
68     num_carets = std::max<size_t>(num_carets, 1);
69     result.append(num_spaces, ' ');
70     result += color.MaybeBoldCode();
71     result += color.MaybeGreenCode();
72     result.append(num_carets, '^');
73     result += color.MaybeDefaultCode();
74     result += '\n';
75   }
76 
77   return result;
78 }
79 
80 }  // End of anonymous namespace
81 
FormatErrorsToString(const Errors & errors,Location::Type location_type,LexerSourceLineFinder * line_finder,const Color & color,const std::string & header,PrintHeader print_header,int source_line_max_length)82 std::string FormatErrorsToString(const Errors& errors,
83                                  Location::Type location_type,
84                                  LexerSourceLineFinder* line_finder,
85                                  const Color& color,
86                                  const std::string& header,
87                                  PrintHeader print_header,
88                                  int source_line_max_length) {
89   std::string result;
90   for (const auto& error : errors) {
91     if (!header.empty()) {
92       switch (print_header) {
93         case PrintHeader::Never:
94           break;
95         case PrintHeader::Once:
96           print_header = PrintHeader::Never;
97           // Fallthrough.
98         case PrintHeader::Always:
99           result += header;
100           result += ":\n";
101           break;
102       }
103     }
104 
105     int indent = header.empty() ? 0 : 2;
106 
107     result += FormatError(error, location_type, color, line_finder,
108                           source_line_max_length, indent);
109   }
110   return result;
111 }
112 
FormatErrorsToFile(const Errors & errors,Location::Type location_type,LexerSourceLineFinder * line_finder,FILE * file,const std::string & header,PrintHeader print_header,int source_line_max_length)113 void FormatErrorsToFile(const Errors& errors,
114                         Location::Type location_type,
115                         LexerSourceLineFinder* line_finder,
116                         FILE* file,
117                         const std::string& header,
118                         PrintHeader print_header,
119                         int source_line_max_length) {
120   Color color(file);
121   std::string s =
122       FormatErrorsToString(errors, location_type, line_finder, color, header,
123                            print_header, source_line_max_length);
124   fwrite(s.data(), 1, s.size(), file);
125 }
126 
127 }  // namespace wabt
128