blob: e321a58a1a0b612eae2198f698cbf7c8dcefbade [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 "common/text/macro_definition.h"
#include <iterator>
#include <map>
#include <string>
#include <vector>
#include "absl/status/status.h"
#include "absl/strings/str_cat.h"
#include "absl/strings/string_view.h"
#include "common/text/token_info.h"
#include "common/util/container_util.h"
namespace verible {
using container::FindOrNull;
bool MacroDefinition::AppendParameter(const MacroParameterInfo& param_info) {
is_callable_ = true;
// Record position of this parameter.
const bool inserted = parameter_positions_
.insert({std::string(param_info.name.text()),
parameter_info_array_.size()})
.second;
parameter_info_array_.push_back(param_info);
return inserted;
}
absl::Status MacroDefinition::PopulateSubstitutionMap(
const std::vector<TokenInfo>& macro_call_args,
substitution_map_type* arg_map) const {
if (macro_call_args.size() != parameter_info_array_.size()) {
return absl::InvalidArgumentError(
absl::StrCat("Error calling macro ", name_.text(), " with ",
macro_call_args.size(), " arguments, but definition has ",
parameter_info_array_.size(), " formal parameters."));
// TODO(fangism): also allow one blank argument when number of formals is 0.
}
auto actuals_iter = macro_call_args.begin();
const auto actuals_end = macro_call_args.end();
auto formals_iter = parameter_info_array_.begin();
for (; actuals_iter != actuals_end; ++actuals_iter, ++formals_iter) {
auto& replacement_text = (*arg_map)[formals_iter->name.text()];
if (!actuals_iter->text().empty()) {
// Actual text is provided.
replacement_text = *actuals_iter;
} else if (!formals_iter->default_value.text().empty()) {
// Use default parameter value.
replacement_text = formals_iter->default_value;
}
// else leave blank as empty string.
}
return absl::OkStatus();
}
absl::Status MacroDefinition::PopulateSubstitutionMap(
const std::vector<DefaultTokenInfo>& macro_call_args,
substitution_map_type* arg_map) const {
if (macro_call_args.size() != parameter_info_array_.size()) {
return absl::InvalidArgumentError(
absl::StrCat("Error calling macro ", name_.text(), " with ",
macro_call_args.size(), " arguments, but definition has ",
parameter_info_array_.size(), " formal parameters."));
// TODO(fangism): also allow one blank argument when number of formals is 0.
}
auto actuals_iter = macro_call_args.begin();
const auto actuals_end = macro_call_args.end();
auto formals_iter = parameter_info_array_.begin();
for (; actuals_iter != actuals_end; ++actuals_iter, ++formals_iter) {
auto& replacement_text = (*arg_map)[formals_iter->name.text()];
if (!actuals_iter->text().empty()) {
// Actual text is provided.
replacement_text = *actuals_iter;
} else if (!formals_iter->default_value.text().empty()) {
// Use default parameter value.
replacement_text = formals_iter->default_value;
}
// else leave blank as empty string.
}
return absl::OkStatus();
}
const TokenInfo& MacroDefinition::SubstituteText(
const substitution_map_type& substitution_map, const TokenInfo& token_info,
int actual_token_enum) {
if (actual_token_enum == 0 ||
(actual_token_enum == token_info.token_enum())) {
const auto* replacement = FindOrNull(substitution_map, token_info.text());
if (replacement) {
// Substitute formal parameter for actual text.
return *replacement;
}
}
// Didn't match enum type nor find map entry, so don't substitute.
return token_info;
}
} // namespace verible