| // Copyright (c) 2014, the Dart project authors.  Please see the AUTHORS file | 
 | // for details. All rights reserved. Use of this source code is governed by a | 
 | // BSD-style license that can be found in the LICENSE file. | 
 |  | 
 | #include "vm/report.h" | 
 |  | 
 | #include "vm/code_patcher.h" | 
 | #include "vm/exceptions.h" | 
 | #include "vm/flags.h" | 
 | #include "vm/longjump.h" | 
 | #include "vm/object.h" | 
 | #include "vm/stack_frame.h" | 
 | #include "vm/symbols.h" | 
 |  | 
 | namespace dart { | 
 |  | 
 | DEFINE_FLAG(bool, silent_warnings, false, "Silence warnings."); | 
 | DEFINE_FLAG(bool, warning_as_error, false, "Treat warnings as errors."); | 
 |  | 
 | StringPtr Report::PrependSnippet(Kind kind, | 
 |                                  const Script& script, | 
 |                                  TokenPosition token_pos, | 
 |                                  bool report_after_token, | 
 |                                  const String& message) { | 
 |   const char* message_header; | 
 |   switch (kind) { | 
 |     case kWarning: | 
 |       message_header = "warning"; | 
 |       break; | 
 |     case kError: | 
 |       message_header = "error"; | 
 |       break; | 
 |     case kBailout: | 
 |       message_header = "bailout"; | 
 |       break; | 
 |     default: | 
 |       message_header = ""; | 
 |       UNREACHABLE(); | 
 |   } | 
 |   String& result = String::Handle(); | 
 |   if (!script.IsNull() && script.HasSource()) { | 
 |     const String& script_url = String::Handle(script.url()); | 
 |     intptr_t line, column; | 
 |     if (script.GetTokenLocation(token_pos, &line, &column)) { | 
 |       const intptr_t token_len = script.GetTokenLength(token_pos); | 
 |       if (report_after_token) { | 
 |         column += token_len < 0 ? 1 : token_len; | 
 |       } | 
 |       // Allocate formatted strings in old space as they may be created during | 
 |       // optimizing compilation. Those strings are created rarely and should not | 
 |       // pollute old space. | 
 |       result = String::NewFormatted( | 
 |           Heap::kOld, "'%s': %s: line %" Pd " pos %" Pd ": ", | 
 |           script_url.ToCString(), message_header, line, column); | 
 |       // Append the formatted error or warning message. | 
 |       const Array& strs = Array::Handle(Array::New(6, Heap::kOld)); | 
 |       strs.SetAt(0, result); | 
 |       strs.SetAt(1, message); | 
 |       // Append the source line. | 
 |       const String& script_line = | 
 |           String::Handle(script.GetLine(line, Heap::kOld)); | 
 |       ASSERT(!script_line.IsNull()); | 
 |       strs.SetAt(2, Symbols::NewLine()); | 
 |       strs.SetAt(3, script_line); | 
 |       strs.SetAt(4, Symbols::NewLine()); | 
 |       // Append the column marker. | 
 |       const String& column_line = String::Handle(String::NewFormatted( | 
 |           Heap::kOld, "%*s\n", static_cast<int>(column), "^")); | 
 |       strs.SetAt(5, column_line); | 
 |       result = String::ConcatAll(strs, Heap::kOld); | 
 |     } else { | 
 |       // Token position is unknown. | 
 |       result = String::NewFormatted( | 
 |           Heap::kOld, "'%s': %s: ", script_url.ToCString(), message_header); | 
 |       result = String::Concat(result, message, Heap::kOld); | 
 |     } | 
 |   } else { | 
 |     // Script is unknown. | 
 |     // Append the formatted error or warning message. | 
 |     result = String::NewFormatted(Heap::kOld, "%s: ", message_header); | 
 |     result = String::Concat(result, message, Heap::kOld); | 
 |   } | 
 |   return result.ptr(); | 
 | } | 
 |  | 
 | void Report::LongJump(const Error& error) { | 
 |   Thread::Current()->long_jump_base()->Jump(1, error); | 
 |   UNREACHABLE(); | 
 | } | 
 |  | 
 | void Report::LongJumpF(const Error& prev_error, | 
 |                        const Script& script, | 
 |                        TokenPosition token_pos, | 
 |                        const char* format, | 
 |                        ...) { | 
 |   va_list args; | 
 |   va_start(args, format); | 
 |   LongJumpV(prev_error, script, token_pos, format, args); | 
 |   va_end(args); | 
 |   UNREACHABLE(); | 
 | } | 
 |  | 
 | void Report::LongJumpV(const Error& prev_error, | 
 |                        const Script& script, | 
 |                        TokenPosition token_pos, | 
 |                        const char* format, | 
 |                        va_list args) { | 
 |   // If an isolate is being killed a [UnwindError] will be propagated up the | 
 |   // stack. In such a case we cannot wrap the unwind error in a new | 
 |   // [LanguageError]. Instead we simply continue propagating the [UnwindError] | 
 |   // upwards. | 
 |   if (prev_error.IsUnwindError()) { | 
 |     LongJump(prev_error); | 
 |     UNREACHABLE(); | 
 |   } | 
 |   const Error& error = Error::Handle(LanguageError::NewFormattedV( | 
 |       prev_error, script, token_pos, Report::AtLocation, kError, Heap::kOld, | 
 |       format, args)); | 
 |   LongJump(error); | 
 |   UNREACHABLE(); | 
 | } | 
 |  | 
 | void Report::MessageF(Kind kind, | 
 |                       const Script& script, | 
 |                       TokenPosition token_pos, | 
 |                       bool report_after_token, | 
 |                       const char* format, | 
 |                       ...) { | 
 |   va_list args; | 
 |   va_start(args, format); | 
 |   MessageV(kind, script, token_pos, report_after_token, format, args); | 
 |   va_end(args); | 
 | } | 
 |  | 
 | void Report::MessageV(Kind kind, | 
 |                       const Script& script, | 
 |                       TokenPosition token_pos, | 
 |                       bool report_after_token, | 
 |                       const char* format, | 
 |                       va_list args) { | 
 |   if (kind < kError) { | 
 |     // Reporting a warning. | 
 |     if (FLAG_silent_warnings) { | 
 |       return; | 
 |     } | 
 |     if (!FLAG_warning_as_error) { | 
 |       const String& msg = String::Handle(String::NewFormattedV(format, args)); | 
 |       const String& snippet_msg = String::Handle( | 
 |           PrependSnippet(kind, script, token_pos, report_after_token, msg)); | 
 |       OS::PrintErr("%s", snippet_msg.ToCString()); | 
 |       return; | 
 |     } | 
 |   } | 
 |   // Reporting an error (or a warning as error). | 
 |   const Error& error = Error::Handle(LanguageError::NewFormattedV( | 
 |       Error::Handle(),  // No previous error. | 
 |       script, token_pos, report_after_token, kind, Heap::kOld, format, args)); | 
 |   LongJump(error); | 
 |   UNREACHABLE(); | 
 | } | 
 |  | 
 | }  // namespace dart |