| // 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 |