forked from chipsalliance/verible
-
Notifications
You must be signed in to change notification settings - Fork 0
/
verilog_diff.cc
149 lines (130 loc) · 5.01 KB
/
verilog_diff.cc
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
// 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.
// verilog_diff compares the lexical contents of two Verilog source code
// texts. Inputs only need to be lexically valid, not necessarily syntactically
// valid. Use '-' to read from stdin.
// Differences are reported to stdout.
// The program exits 0 if no differences are found, else non-zero.
//
// Example usage:
// verilog_diff [options] file1 file2
#include <functional>
#include <iostream>
#include <map>
#include <sstream> // IWYU pragma: keep // for ostringstream
#include <string> // for string, allocator, etc
#include "absl/flags/flag.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "common/util/enum_flags.h"
#include "common/util/file_util.h"
#include "common/util/init_command_line.h"
#include "common/util/logging.h"
#include "verilog/analysis/verilog_equivalence.h"
// Enumeration type for selecting
enum class DiffMode {
// TODO(fangism): kNone: none of the existing presets, let the user compose
// the filter predicate and comparator independently.
kFormat,
kObfuscate,
};
static const verible::EnumNameMap<DiffMode> &DiffModeStringMap() {
static const verible::EnumNameMap<DiffMode> kDiffModeStringMap({
{"format", DiffMode::kFormat},
{"obfuscate", DiffMode::kObfuscate},
});
return kDiffModeStringMap;
}
std::ostream &operator<<(std::ostream &stream, DiffMode p) {
return DiffModeStringMap().Unparse(p, stream);
}
bool AbslParseFlag(absl::string_view text, DiffMode *mode, std::string *error) {
return DiffModeStringMap().Parse(text, mode, error, "--mode value");
}
std::string AbslUnparseFlag(const DiffMode &mode) {
std::ostringstream stream;
stream << mode;
return stream.str();
}
ABSL_FLAG(DiffMode, mode, DiffMode::kFormat,
R"(Defines difference functions.
format: ignore whitespaces, compare token texts.
This is useful for verifying formatter (e.g. verilog_format) output.
obfuscate: preserve whitespaces, compare token texts' lengths only.
This is useful for verifying verilog_obfuscate output.
)");
using EquivalenceFunctionType = std::function<verilog::DiffStatus(
absl::string_view, absl::string_view, std::ostream *)>;
static const std::map<DiffMode, EquivalenceFunctionType> diff_func_map({
{DiffMode::kFormat, verilog::FormatEquivalent},
{DiffMode::kObfuscate, verilog::ObfuscationEquivalent},
});
int main(int argc, char **argv) {
const auto usage = absl::StrCat("usage: ", argv[0],
" [options] file1 file2\n"
"Use - as a file name to read from stdin.");
const auto args = verible::InitCommandLine(usage, &argc, &argv);
enum {
// inputs differ or there is some lexical error in one of the inputs
kInputDifferenceErrorCode = 1,
// error with flags or opening/reading one of the files
kUserErrorCode = 2,
};
if (args.size() != 3) {
std::cerr << "Program requires 2 positional arguments for input files."
<< std::endl;
return kUserErrorCode;
}
// Open both files.
const auto content1_or = verible::file::GetContentAsString(args[1]);
if (!content1_or.ok()) {
std::cerr << args[1] << ": " << content1_or.status() << std::endl;
return kUserErrorCode;
}
const auto content2_or = verible::file::GetContentAsString(args[2]);
if (!content2_or.ok()) {
std::cerr << args[1] << ": " << content1_or.status() << std::endl;
return kUserErrorCode;
}
// Selection diff-ing function.
const auto diff_mode = absl::GetFlag(FLAGS_mode);
const auto iter = diff_func_map.find(diff_mode);
CHECK(iter != diff_func_map.end());
const auto diff_func = iter->second;
// Compare.
std::ostringstream errstream;
const auto diff_status = diff_func(*content1_or, *content2_or, &errstream);
// Signal result of comparison.
switch (diff_status) {
case verilog::DiffStatus::kEquivalent: {
std::cout << "Inputs match." << std::endl;
break;
}
case verilog::DiffStatus::kDifferent: {
std::cout << "Inputs differ.\n" << errstream.str() << std::endl;
return kInputDifferenceErrorCode;
}
case verilog::DiffStatus::kLeftError: {
std::cout << "Lexical error in first file.\n"
<< errstream.str() << std::endl;
return kInputDifferenceErrorCode;
}
case verilog::DiffStatus::kRightError: {
std::cout << "Lexical error in second file.\n"
<< errstream.str() << std::endl;
return kInputDifferenceErrorCode;
}
}
return 0;
}