Skip to content

Commit 4c301ed

Browse files
committed
Add ADT packing helpers and interface tests
1 parent a1303be commit 4c301ed

5 files changed

Lines changed: 148 additions & 1 deletion

File tree

src/include/souffle/RecordTable.h

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -61,4 +61,72 @@ RamDomain pack(RecordTableT&& recordTab, const std::initializer_list<RamDomain>&
6161
return recordTab.pack(std::data(initlist), initlist.size());
6262
}
6363

64+
/**
65+
* @brief Construct a value belonging to an enumerated algebraic data type.
66+
*
67+
* An ADT is enumerated when none of its branches has fields.
68+
*
69+
* An ADT branch ID is the branch's zero-based position in the lexicographical
70+
* ordering of the ADT's qualified branch names.
71+
*/
72+
inline RamDomain packADTEnum(const RamDomain branch) {
73+
return branch;
74+
}
75+
76+
/**
77+
* @brief Construct a value belonging to a non-enumerated algebraic data type.
78+
*
79+
* An ADT is non-enumerated when at least one of its branches has a field. This
80+
* function must also be used for an empty branch of such an ADT.
81+
*
82+
* The arguments must already be represented as RamDomain values, using the
83+
* same symbol and record tables as the program that will consume the ADT. This
84+
* helper hides the special record encodings used for empty, unary, and
85+
* multi-argument branches.
86+
*
87+
* @param branch Zero-based position in the lexicographical ordering of the
88+
* ADT's qualified branch names.
89+
* @param arguments Branch field values in declaration order, encoded as
90+
* RamDomain values.
91+
*/
92+
inline RamDomain packADT(
93+
RecordTable& recordTab, const RamDomain branch, const RamDomain* arguments, const std::size_t arity) {
94+
const RamDomain branchValue = arity == 1 ? arguments[0] : recordTab.pack(arguments, arity);
95+
return recordTab.pack({branch, branchValue});
96+
}
97+
98+
/**
99+
* @brief Construct a non-enumerated ADT value from an initialization list.
100+
* @param branch Zero-based position in lexicographical branch-name order.
101+
* @param arguments Branch field values in declaration order, encoded as
102+
* RamDomain values.
103+
*/
104+
inline RamDomain packADT(
105+
RecordTable& recordTab, const RamDomain branch, const std::initializer_list<RamDomain>& arguments) {
106+
return packADT(recordTab, branch, std::data(arguments), arguments.size());
107+
}
108+
109+
/**
110+
* @brief Construct a non-enumerated ADT value from a fixed-size tuple.
111+
* @param branch Zero-based position in lexicographical branch-name order.
112+
* @param arguments Branch field values in declaration order, encoded as
113+
* RamDomain values.
114+
*/
115+
template <std::size_t Arity>
116+
RamDomain packADT(RecordTable& recordTab, const RamDomain branch, const Tuple<RamDomain, Arity>& arguments) {
117+
return packADT(recordTab, branch, arguments.data(), Arity);
118+
}
119+
120+
/**
121+
* @brief Construct a non-enumerated ADT value from a span.
122+
* @param branch Zero-based position in lexicographical branch-name order.
123+
* @param arguments Branch field values in declaration order, encoded as
124+
* RamDomain values.
125+
*/
126+
template <std::size_t Arity>
127+
RamDomain packADT(
128+
RecordTable& recordTab, const RamDomain branch, const span<const RamDomain, Arity> arguments) {
129+
return packADT(recordTab, branch, arguments.data(), arguments.size());
130+
}
131+
64132
} // namespace souffle

src/tests/record_table_test.cpp

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -70,6 +70,55 @@ TEST(Pack, InitListHelper) {
7070
EXPECT_EQ(3, ptr[2]);
7171
}
7272

73+
TEST(PackADT, Enum) {
74+
EXPECT_EQ(2, packADTEnum(2));
75+
}
76+
77+
TEST(PackADT, EmptyBranch) {
78+
SpecializedRecordTable<0, 2> recordTable;
79+
80+
const RamDomain ref = packADT(recordTable, 3, {});
81+
const RamDomain* adt = recordTable.unpack(ref, 2);
82+
83+
EXPECT_EQ(3, adt[0]);
84+
EXPECT_EQ(recordTable.pack(nullptr, 0), adt[1]);
85+
}
86+
87+
TEST(PackADT, UnaryBranch) {
88+
SpecializedRecordTable<2> recordTable;
89+
90+
const RamDomain ref = packADT(recordTable, 4, {42});
91+
const RamDomain* adt = recordTable.unpack(ref, 2);
92+
93+
EXPECT_EQ(4, adt[0]);
94+
EXPECT_EQ(42, adt[1]);
95+
}
96+
97+
TEST(PackADT, MultiArgumentBranch) {
98+
SpecializedRecordTable<2, 3> recordTable;
99+
const Tuple<RamDomain, 3> arguments = {{10, 20, 30}};
100+
101+
const RamDomain ref = packADT(recordTable, 5, arguments);
102+
const RamDomain* adt = recordTable.unpack(ref, 2);
103+
const RamDomain* unpackedArguments = recordTable.unpack(adt[1], 3);
104+
105+
EXPECT_EQ(5, adt[0]);
106+
EXPECT_EQ(10, unpackedArguments[0]);
107+
EXPECT_EQ(20, unpackedArguments[1]);
108+
EXPECT_EQ(30, unpackedArguments[2]);
109+
}
110+
111+
TEST(PackADT, NestedBranch) {
112+
SpecializedRecordTable<2> recordTable;
113+
114+
const RamDomain inner = packADT(recordTable, 0, {7});
115+
const RamDomain outer = packADT(recordTable, 1, {inner});
116+
const RamDomain* unpackedOuter = recordTable.unpack(outer, 2);
117+
118+
EXPECT_EQ(1, unpackedOuter[0]);
119+
EXPECT_EQ(inner, unpackedOuter[1]);
120+
}
121+
73122
TEST(Enumerate, Empty) {
74123
SpecializedRecordTable<2> recordTable;
75124

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
"$A(1234)"
2+
"$B(""5678"")"
3+
"$C"

tests/interface/functors/functors.cpp

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -147,4 +147,18 @@ souffle::RamDomain my_to_number_fun(
147147
souffle::RamDomain my_identity(souffle::SymbolTable*, souffle::RecordTable*, souffle::RamDomain arg) {
148148
return arg;
149149
}
150+
151+
souffle::RamDomain my_make_a(
152+
souffle::SymbolTable*, souffle::RecordTable* recordTable, souffle::RamDomain arg) {
153+
return souffle::packADT(*recordTable, 0, {arg});
154+
}
155+
156+
souffle::RamDomain my_make_b(
157+
souffle::SymbolTable*, souffle::RecordTable* recordTable, souffle::RamDomain arg) {
158+
return souffle::packADT(*recordTable, 1, {arg});
159+
}
160+
161+
souffle::RamDomain my_make_c(souffle::SymbolTable*, souffle::RecordTable* recordTable) {
162+
return souffle::packADT(*recordTable, 2, {});
163+
}
150164
} // end of extern "C"

tests/interface/functors/functors.dl

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -93,15 +93,22 @@ L(@myappend(l)) :- L(l), l = [x, _l1], x < 10.
9393
.output L
9494

9595
// Testing ADTS
96-
.type MyADT = A { x : number }
96+
// Branches are deliberately declared in reverse lexical order. Their IDs are
97+
// still assigned lexically: A = 0, B = 1, and C = 2.
98+
.type MyADT = C {}
9799
| B { x : symbol }
100+
| A { x : number }
98101

99102
.functor my_to_number_fun(val: MyADT): number stateful
100103
.functor my_identity(val: MyADT): MyADT stateful
104+
.functor my_make_a(val: number): MyADT stateful
105+
.functor my_make_b(val: symbol): MyADT stateful
106+
.functor my_make_c(): MyADT stateful
101107

102108
.decl gen_adt(val: MyADT)
103109
.decl my_to_number(val: number)
104110
.decl identity(val: MyADT)
111+
.decl constructed(val: MyADT)
105112

106113
gen_adt($A(1234)).
107114
gen_adt($B("5678")).
@@ -110,4 +117,10 @@ my_to_number(@my_to_number_fun(v)) :- gen_adt(v).
110117

111118
identity(@my_identity(v)) :- gen_adt(v).
112119

120+
constructed(@my_make_a(1234)).
121+
constructed(@my_make_b("5678")).
122+
constructed($C()).
123+
constructed(@my_make_c()).
124+
113125
.output my_to_number, identity
126+
.output constructed(rfc4180=true)

0 commit comments

Comments
 (0)