| // Copyright 2017-2020 The Verible Authors. | |
| // | |
| // Licensed under the Apache License, Version 2.0 (the "License"); | |
| // you may not use this file except in compliance with the License. | |
| // You may obtain a copy of the License at | |
| // | |
| // http://www.apache.org/licenses/LICENSE-2.0 | |
| // | |
| // Unless required by applicable law or agreed to in writing, software | |
| // distributed under the License is distributed on an "AS IS" BASIS, | |
| // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. | |
| // See the License for the specific language governing permissions and | |
| // limitations under the License. | |
| #include "verilog/transform/strip_comments.h" | |
| #include <iostream> | |
| #include <vector> | |
| #include "absl/strings/str_split.h" | |
| #include "common/strings/comment_utils.h" | |
| #include "common/strings/range.h" | |
| #include "common/text/token_info.h" | |
| #include "common/util/iterator_range.h" | |
| #include "common/util/spacer.h" | |
| #include "verilog/parser/verilog_lexer.h" | |
| #include "verilog/parser/verilog_parser.h" | |
| #include "verilog/parser/verilog_token_enum.h" | |
| namespace verilog { | |
| using verible::make_string_view_range; | |
| using verible::Spacer; | |
| using verible::StripComment; | |
| using verible::TokenInfo; | |
| // Replace non-newline characters with a single char, like <space>. | |
| // Tabs are considered non-newline characters. | |
| static void ReplaceNonNewlines(absl::string_view text, std::ostream* output, | |
| char replacement) { | |
| if (text.empty()) return; | |
| const std::vector<absl::string_view> lines( | |
| absl::StrSplit(text, absl::ByChar('\n'))); | |
| // no newline before first element | |
| *output << Spacer(lines.front().size(), replacement); | |
| for (const auto& line : verible::make_range(lines.begin() + 1, lines.end())) { | |
| *output << '\n' << Spacer(line.size(), replacement); | |
| } | |
| } | |
| void StripVerilogComments(absl::string_view content, std::ostream* output, | |
| char replacement) { | |
| VLOG(1) << __FUNCTION__; | |
| verilog::VerilogLexer lexer(content); | |
| const TokenInfo::Context context(content, [](std::ostream& stream, int e) { | |
| stream << verilog_symbol_name(e); | |
| }); | |
| while (true) { | |
| const verible::TokenInfo& token(lexer.DoNextToken()); | |
| if (token.isEOF()) break; | |
| VLOG(2) << "token: " << verible::TokenWithContext{token, context}; | |
| const absl::string_view text = token.text(); | |
| switch (token.token_enum()) { | |
| case verilog_tokentype::TK_EOL_COMMENT: | |
| switch (replacement) { | |
| case '\0': | |
| // There is always a '\n' that follows, so there is no risk of | |
| // accidentally fusing tokens by deleting these comments. | |
| break; | |
| case ' ': | |
| // The lexer guarantees the text does not contain '\n'. | |
| *output << Spacer(text.length()); | |
| break; | |
| default: { | |
| // Retain the "//" but erase everything thereafter. | |
| const absl::string_view body(StripComment(text)); | |
| const absl::string_view head( | |
| make_string_view_range(text.begin(), body.begin())); | |
| *output << head << Spacer(body.length(), replacement); | |
| break; | |
| } | |
| } | |
| break; | |
| case verilog_tokentype::TK_COMMENT_BLOCK: | |
| switch (replacement) { | |
| case '\0': | |
| // Print one space to prevent accidental token fusion in | |
| // cases like: "a/**/b". | |
| *output << ' '; | |
| break; | |
| case ' ': | |
| // Preserve newlines, but replace everything else with space. | |
| ReplaceNonNewlines(text, output, replacement); | |
| break; | |
| default: { | |
| // Retain the "/*" and "*/" but erase everything in between. | |
| const absl::string_view body(StripComment(text)); | |
| const absl::string_view head( | |
| make_string_view_range(text.begin(), body.begin())); | |
| const absl::string_view tail( | |
| make_string_view_range(body.end(), text.end())); | |
| *output << head; | |
| ReplaceNonNewlines(body, output, replacement); | |
| *output << tail; | |
| break; | |
| } | |
| } | |
| break; | |
| // The following tokens are un-lexed, so they need to be lexed | |
| // recursively. | |
| case verilog_tokentype::MacroArg: | |
| case verilog_tokentype::PP_define_body: | |
| StripVerilogComments(text, output, replacement); | |
| break; | |
| default: | |
| // Preserve all other text, including lexical error tokens. | |
| *output << text; | |
| } // switch | |
| } | |
| VLOG(1) << "end of " << __FUNCTION__; | |
| } | |
| } // namespace verilog |