blob: 3e4ce1c0171e56556bd7fdf69514e58400b5c8a2 [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.
// Test MacroDefinition and its supporting structs.
#include "common/text/macro_definition.h"
#include <vector>
#include "gtest/gtest.h"
#include "absl/status/status.h"
#include "common/text/token_info.h"
#include "common/util/container_util.h"
namespace verible {
namespace {
using verible::container::FindOrNull;
// Fake token enumerations that would come from parser.tab.hh.
enum FakeTokenEnum {
FakeIdEnum = 1,
FakeIntEnum = 2,
FakeDefineEnum = 3,
FakeUnlexedTextEnum = 4,
FakeOtherEnum = 5,
};
// Test default constructed MacroParameterInfo
TEST(MacroParameterInfoTest, Constructor) {
const MacroParameterInfo param_info;
EXPECT_FALSE(param_info.HasDefaultText());
EXPECT_TRUE(param_info.name.isEOF());
EXPECT_TRUE(param_info.default_value.isEOF());
}
// Test named MacroParameterInfo without default value.
TEST(MacroParameterInfoTest, WithoutDefault) {
const TokenInfo param_name(FakeIdEnum, "name");
const MacroParameterInfo param_info{param_name};
EXPECT_FALSE(param_info.HasDefaultText());
EXPECT_EQ(param_info.name, param_name);
EXPECT_TRUE(param_info.default_value.isEOF());
}
// Test named MacroParameterInfo with default value.
TEST(MacroParameterInfoTest, WithDefault) {
const TokenInfo param_name(FakeIdEnum, "name");
const TokenInfo param_default(FakeIntEnum, "0");
const MacroParameterInfo param_info{param_name, param_default};
EXPECT_TRUE(param_info.HasDefaultText());
EXPECT_EQ(param_info.name, param_name);
EXPECT_EQ(param_info.default_value, param_default);
}
// Test default constructed MacroCall.
TEST(MacroCallTest, Constructor) {
const MacroCall macro_call;
EXPECT_TRUE(macro_call.macro_name.isEOF());
EXPECT_FALSE(macro_call.has_parameters);
EXPECT_EQ(macro_call.positional_arguments.size(), 0);
}
// Test default constructed MacroDefinition.
TEST(MacroDefinitionTest, Constructor) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
const MacroDefinition macro(def_header, macro_name);
EXPECT_EQ(macro.Name(), macro_name.text());
EXPECT_FALSE(macro.IsCallable());
}
// Tests attaching definition text to MacroDefinition.
TEST(MacroDefinitionTest, DefinitionText) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
const TokenInfo body(FakeUnlexedTextEnum, "foo + bar");
MacroDefinition macro(def_header, macro_name);
macro.SetDefinitionText(body);
EXPECT_EQ(macro.DefinitionText(), body);
}
// Tests a MacroDefinition with no parameters.
TEST(MacroDefinitionTest, CallableNoArgs) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
MacroDefinition macro(def_header, macro_name);
macro.SetCallable();
EXPECT_TRUE(macro.IsCallable());
}
// Tests a MacroDefinition with one parameter.
TEST(MacroDefinitionTest, CallableOneArg) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
MacroDefinition macro(def_header, macro_name);
const TokenInfo param_name(FakeIdEnum, "clk");
const MacroParameterInfo param{param_name};
const bool appended = macro.AppendParameter(param);
EXPECT_TRUE(appended);
EXPECT_TRUE(macro.IsCallable());
}
// Tests a MacroDefinition with one parameter with default value.
TEST(MacroDefinitionTest, CallableOneArgDefault) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
MacroDefinition macro(def_header, macro_name);
const TokenInfo param_name(FakeIdEnum, "clk");
const TokenInfo param_default(FakeIdEnum, "CLK");
const MacroParameterInfo param{param_name, param_default};
const bool appended = macro.AppendParameter(param);
EXPECT_TRUE(appended);
EXPECT_TRUE(macro.IsCallable());
}
// Tests that duplicate parameter names are rejected.
TEST(MacroDefinitionTest, CallableRepeatedArgRejected) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
MacroDefinition macro(def_header, macro_name);
{
const TokenInfo param_name(FakeIdEnum, "clk");
const MacroParameterInfo param{param_name};
const bool appended = macro.AppendParameter(param);
EXPECT_TRUE(appended);
EXPECT_TRUE(macro.IsCallable());
}
{
const TokenInfo param_name(FakeIdEnum, "clk");
const MacroParameterInfo param{param_name};
const bool appended = macro.AppendParameter(param);
EXPECT_FALSE(appended);
EXPECT_TRUE(macro.IsCallable());
}
}
// Tests that non-conflicting parameters are accepted.
TEST(MacroDefinitionTest, CallableTwoArgs) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
MacroDefinition macro(def_header, macro_name);
{
const TokenInfo param_name(FakeIdEnum, "clk");
const MacroParameterInfo param{param_name};
const bool appended = macro.AppendParameter(param);
EXPECT_TRUE(appended);
EXPECT_TRUE(macro.IsCallable());
}
{
const TokenInfo param_name(FakeIdEnum, "data");
const MacroParameterInfo param{param_name};
const bool appended = macro.AppendParameter(param);
EXPECT_TRUE(appended);
EXPECT_TRUE(macro.IsCallable());
}
}
// Tests creating a token substitution map with parameterless macro.
TEST(MacroDefinitionTest, PopulateSubstitutionMapNonCallable) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
MacroDefinition macro(def_header, macro_name);
std::vector<TokenInfo> call_args;
MacroDefinition::substitution_map_type sub_map;
const auto status = macro.PopulateSubstitutionMap(call_args, &sub_map);
EXPECT_TRUE(status.ok());
auto not_param = FindOrNull(sub_map, "dock");
EXPECT_EQ(not_param, nullptr);
}
// Tests creating a token substitution map with a 1-parameter macro.
TEST(MacroDefinitionTest, PopulateSubstitutionMapOneParam) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
MacroDefinition macro(def_header, macro_name);
{
const TokenInfo param_name(FakeIdEnum, "clk");
const MacroParameterInfo param{param_name};
const bool appended = macro.AppendParameter(param);
EXPECT_TRUE(appended);
}
std::vector<TokenInfo> call_args;
const TokenInfo actual1(FakeIntEnum, "99");
call_args.push_back(actual1);
MacroDefinition::substitution_map_type sub_map;
{
const auto status = macro.PopulateSubstitutionMap(call_args, &sub_map);
EXPECT_TRUE(status.ok());
auto not_param = FindOrNull(sub_map, "dock");
EXPECT_EQ(not_param, nullptr);
auto expect_param = FindOrNull(sub_map, "clk");
EXPECT_EQ(*expect_param, actual1);
}
// checking substitution
{
const TokenInfo num(FakeIntEnum, "732");
const TokenInfo repl = MacroDefinition::SubstituteText(sub_map, num);
EXPECT_EQ(repl, num); // no substitution
}
{
const TokenInfo num(FakeIdEnum, "clk");
const TokenInfo repl = MacroDefinition::SubstituteText(sub_map, num);
EXPECT_EQ(repl, actual1); // substituted
}
{
const TokenInfo num(FakeIdEnum, "rst");
const TokenInfo repl = MacroDefinition::SubstituteText(sub_map, num);
EXPECT_EQ(repl, num); // not substituted
}
{
const TokenInfo num(FakeOtherEnum, "clk");
const TokenInfo repl = MacroDefinition::SubstituteText(sub_map, num);
EXPECT_EQ(repl, actual1); // substituted
}
{
const TokenInfo num(FakeOtherEnum, "clk");
const TokenInfo repl =
MacroDefinition::SubstituteText(sub_map, num, FakeIdEnum);
EXPECT_EQ(repl, num); // not substituted
}
{
const TokenInfo num(FakeOtherEnum, "rst");
const TokenInfo repl =
MacroDefinition::SubstituteText(sub_map, num, FakeIdEnum);
EXPECT_EQ(repl, num); // not substituted
}
}
// Tests creating a token substitution map with a 2-parameter macro.
TEST(MacroDefinitionTest, PopulateSubstitutionMapTwoParams) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
MacroDefinition macro(def_header, macro_name);
{
const TokenInfo param_name(FakeIdEnum, "clk");
const MacroParameterInfo param{param_name};
const bool appended = macro.AppendParameter(param);
EXPECT_TRUE(appended);
}
{
const TokenInfo param_name(FakeIdEnum, "rstn");
const MacroParameterInfo param{param_name};
const bool appended = macro.AppendParameter(param);
EXPECT_TRUE(appended);
}
std::vector<TokenInfo> call_args;
const TokenInfo actual1(FakeIntEnum, "99");
const TokenInfo actual2(FakeIdEnum, "_rst_");
call_args.push_back(actual1);
call_args.push_back(actual2);
MacroDefinition::substitution_map_type sub_map;
const auto status = macro.PopulateSubstitutionMap(call_args, &sub_map);
EXPECT_TRUE(status.ok());
auto not_param = FindOrNull(sub_map, "dock");
EXPECT_EQ(not_param, nullptr);
auto expect_param1 = FindOrNull(sub_map, "clk");
EXPECT_EQ(*expect_param1, actual1);
auto expect_param2 = FindOrNull(sub_map, "rstn");
EXPECT_EQ(*expect_param2, actual2);
}
// Tests failed substitution map creation due to mismatch on parameters.
TEST(MacroDefinitionTest, PopulateSubstitutionMapBadParam) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
MacroDefinition macro(def_header, macro_name);
std::vector<TokenInfo> call_args;
const TokenInfo actual1(FakeIntEnum, "99");
call_args.push_back(actual1);
MacroDefinition::substitution_map_type sub_map;
const auto status = macro.PopulateSubstitutionMap(call_args, &sub_map);
EXPECT_FALSE(status.ok());
}
// Tests creating a token substitution map with a 1-parameter macro with default
// value.
TEST(MacroDefinitionTest, PopulateSubstitutionMapOneParamDefault) {
const TokenInfo def_header(FakeDefineEnum, "`define");
const TokenInfo macro_name(FakeIdEnum, "FF");
MacroDefinition macro(def_header, macro_name);
const TokenInfo param_default(FakeIdEnum, "ticker");
{
const TokenInfo param_name(FakeIdEnum, "clk");
const MacroParameterInfo param{param_name, param_default};
const bool appended = macro.AppendParameter(param);
EXPECT_TRUE(appended);
}
std::vector<TokenInfo> call_args;
const TokenInfo actual1(FakeIntEnum, ""); // blank argument
call_args.push_back(actual1);
MacroDefinition::substitution_map_type sub_map;
const auto status = macro.PopulateSubstitutionMap(call_args, &sub_map);
EXPECT_TRUE(status.ok());
auto not_param = FindOrNull(sub_map, "dock");
EXPECT_EQ(not_param, nullptr);
auto expect_param = FindOrNull(sub_map, "clk");
EXPECT_EQ(*expect_param, param_default);
}
} // namespace
} // namespace verible