1 // Copyright (c) 2015-2016 The Khronos Group Inc. 2 // 3 // Licensed under the Apache License, Version 2.0 (the "License"); 4 // you may not use this file except in compliance with the License. 5 // You may obtain a copy of the License at 6 // 7 // http://www.apache.org/licenses/LICENSE-2.0 8 // 9 // Unless required by applicable law or agreed to in writing, software 10 // distributed under the License is distributed on an "AS IS" BASIS, 11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 // See the License for the specific language governing permissions and 13 // limitations under the License. 14 15 #include "diagnostic.h" 16 17 #include <cassert> 18 #include <cstring> 19 #include <iostream> 20 21 #include "table.h" 22 23 // Diagnostic API 24 25 spv_diagnostic spvDiagnosticCreate(const spv_position position, 26 const char* message) { 27 spv_diagnostic diagnostic = new spv_diagnostic_t; 28 if (!diagnostic) return nullptr; 29 size_t length = strlen(message) + 1; 30 diagnostic->error = new char[length]; 31 if (!diagnostic->error) { 32 delete diagnostic; 33 return nullptr; 34 } 35 diagnostic->position = *position; 36 diagnostic->isTextSource = false; 37 memset(diagnostic->error, 0, length); 38 strncpy(diagnostic->error, message, length); 39 return diagnostic; 40 } 41 42 void spvDiagnosticDestroy(spv_diagnostic diagnostic) { 43 if (!diagnostic) return; 44 delete[] diagnostic->error; 45 delete diagnostic; 46 } 47 48 spv_result_t spvDiagnosticPrint(const spv_diagnostic diagnostic) { 49 if (!diagnostic) return SPV_ERROR_INVALID_DIAGNOSTIC; 50 51 if (diagnostic->isTextSource) { 52 // NOTE: This is a text position 53 // NOTE: add 1 to the line as editors start at line 1, we are counting new 54 // line characters to start at line 0 55 std::cerr << "error: " << diagnostic->position.line + 1 << ": " 56 << diagnostic->position.column + 1 << ": " << diagnostic->error 57 << "\n"; 58 return SPV_SUCCESS; 59 } else { 60 // NOTE: Assume this is a binary position 61 std::cerr << "error: " << diagnostic->position.index << ": " 62 << diagnostic->error << "\n"; 63 return SPV_SUCCESS; 64 } 65 } 66 67 namespace libspirv { 68 69 DiagnosticStream::~DiagnosticStream() { 70 if (error_ != SPV_FAILED_MATCH && consumer_ != nullptr) { 71 auto level = SPV_MSG_ERROR; 72 switch (error_) { 73 case SPV_SUCCESS: 74 case SPV_REQUESTED_TERMINATION: // Essentially success. 75 level = SPV_MSG_INFO; 76 break; 77 case SPV_WARNING: 78 level = SPV_MSG_WARNING; 79 break; 80 case SPV_UNSUPPORTED: 81 case SPV_ERROR_INTERNAL: 82 case SPV_ERROR_INVALID_TABLE: 83 level = SPV_MSG_INTERNAL_ERROR; 84 break; 85 case SPV_ERROR_OUT_OF_MEMORY: 86 level = SPV_MSG_FATAL; 87 break; 88 default: 89 break; 90 } 91 consumer_(level, "input", position_, stream_.str().c_str()); 92 } 93 } 94 95 void UseDiagnosticAsMessageConsumer(spv_context context, 96 spv_diagnostic* diagnostic) { 97 assert(diagnostic && *diagnostic == nullptr); 98 99 auto create_diagnostic = [diagnostic](spv_message_level_t, const char*, 100 const spv_position_t& position, 101 const char* message) { 102 auto p = position; 103 spvDiagnosticDestroy(*diagnostic); // Avoid memory leak. 104 *diagnostic = spvDiagnosticCreate(&p, message); 105 }; 106 SetContextMessageConsumer(context, std::move(create_diagnostic)); 107 } 108 109 std::string spvResultToString(spv_result_t res) { 110 std::string out; 111 switch (res) { 112 case SPV_SUCCESS: 113 out = "SPV_SUCCESS"; 114 break; 115 case SPV_UNSUPPORTED: 116 out = "SPV_UNSUPPORTED"; 117 break; 118 case SPV_END_OF_STREAM: 119 out = "SPV_END_OF_STREAM"; 120 break; 121 case SPV_WARNING: 122 out = "SPV_WARNING"; 123 break; 124 case SPV_FAILED_MATCH: 125 out = "SPV_FAILED_MATCH"; 126 break; 127 case SPV_REQUESTED_TERMINATION: 128 out = "SPV_REQUESTED_TERMINATION"; 129 break; 130 case SPV_ERROR_INTERNAL: 131 out = "SPV_ERROR_INTERNAL"; 132 break; 133 case SPV_ERROR_OUT_OF_MEMORY: 134 out = "SPV_ERROR_OUT_OF_MEMORY"; 135 break; 136 case SPV_ERROR_INVALID_POINTER: 137 out = "SPV_ERROR_INVALID_POINTER"; 138 break; 139 case SPV_ERROR_INVALID_BINARY: 140 out = "SPV_ERROR_INVALID_BINARY"; 141 break; 142 case SPV_ERROR_INVALID_TEXT: 143 out = "SPV_ERROR_INVALID_TEXT"; 144 break; 145 case SPV_ERROR_INVALID_TABLE: 146 out = "SPV_ERROR_INVALID_TABLE"; 147 break; 148 case SPV_ERROR_INVALID_VALUE: 149 out = "SPV_ERROR_INVALID_VALUE"; 150 break; 151 case SPV_ERROR_INVALID_DIAGNOSTIC: 152 out = "SPV_ERROR_INVALID_DIAGNOSTIC"; 153 break; 154 case SPV_ERROR_INVALID_LOOKUP: 155 out = "SPV_ERROR_INVALID_LOOKUP"; 156 break; 157 case SPV_ERROR_INVALID_ID: 158 out = "SPV_ERROR_INVALID_ID"; 159 break; 160 case SPV_ERROR_INVALID_CFG: 161 out = "SPV_ERROR_INVALID_CFG"; 162 break; 163 case SPV_ERROR_INVALID_LAYOUT: 164 out = "SPV_ERROR_INVALID_LAYOUT"; 165 break; 166 default: 167 out = "Unknown Error"; 168 } 169 return out; 170 } 171 172 } // namespace libspirv 173