blob: 96b62475112edfbbd2b86ba093fe1bc0fe3948f5 [file] [log] [blame]
// 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 "common/strings/comment_utils.h"
#include "common/strings/range.h"
#include "common/strings/split.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) {
const std::vector<absl::string_view> lines(verible::SplitLines(text));
if (lines.empty()) return;
// 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