Skip to content

Commit

Permalink
Fix bugs in generating flag enum string representations
Browse files Browse the repository at this point in the history
  • Loading branch information
hsutter committed Sep 10, 2023
1 parent 43822ae commit ecd3726
Show file tree
Hide file tree
Showing 11 changed files with 246 additions and 33 deletions.
2 changes: 1 addition & 1 deletion include/cpp2util.h
Original file line number Diff line number Diff line change
Expand Up @@ -286,7 +286,7 @@ using __uchar = unsigned char; // normally use u8 instead
//-----------------------------------------------------------------------
//

auto max(auto... values) {
constexpr auto max(auto... values) {
return std::max( { values... } );
}

Expand Down
9 changes: 8 additions & 1 deletion regression-tests/pure2-enum.cpp2
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@


skat_game: @enum type = {
diamonds := 9;
hearts; // 10
Expand Down Expand Up @@ -71,6 +70,14 @@ main: () = {

f2 := file_attributes::cached;

std::cout << "f is " << f << "\n";
std::cout << "f2 is " << f2 << "\n";

f2.clear( f2 );
std::cout << "f2 is " << f2 << "\n";
f2.set(file_attributes::cached);
std::cout << "f2 is " << f2 << "\n";

std::cout << "f as int is (f as int )$\n";
std::cout << "f2 as int is (f2 as int )$\n";

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ using << prints clubs
with if else: clubs
with inspect: clubs

f is (cached)
f2 is (cached)
f2 is (none)
f2 is (cached)
f as int is 1
f2 as int is 1
f is (f2) is 1
Expand Down
4 changes: 4 additions & 0 deletions regression-tests/test-results/gcc-10/pure2-enum.cpp.execution
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ using << prints clubs
with if else: clubs
with inspect: clubs

f is (cached)
f2 is (cached)
f2 is (none)
f2 is (cached)
f as int is 1
f2 as int is 1
f is (f2) is 1
Expand Down
4 changes: 4 additions & 0 deletions regression-tests/test-results/gcc-13/pure2-enum.cpp.execution
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ using << prints clubs
with if else: clubs
with inspect: clubs

f is (cached)
f2 is (cached)
f2 is (none)
f2 is (cached)
f as int is 1
f2 as int is 1
f is (f2) is 1
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,10 @@ using << prints clubs
with if else: clubs
with inspect: clubs

f is (cached)
f2 is (cached)
f2 is (none)
f2 is (cached)
f as int is 1
f2 as int is 1
f is (f2) is 1
Expand Down
36 changes: 23 additions & 13 deletions regression-tests/test-results/pure2-enum.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,22 +7,22 @@
#include "cpp2util.h"


#line 3 "pure2-enum.cpp2"
#line 2 "pure2-enum.cpp2"
class skat_game;


#line 12 "pure2-enum.cpp2"
#line 11 "pure2-enum.cpp2"
class rgb;


#line 18 "pure2-enum.cpp2"
#line 17 "pure2-enum.cpp2"
class file_attributes;


//=== Cpp2 type definitions and function declarations ===========================


#line 3 "pure2-enum.cpp2"
#line 2 "pure2-enum.cpp2"
class skat_game: public cpp2::strict_value<cpp2::i8,skat_game,0> {
public: skat_game(cpp2::in<cpp2::strict_value<cpp2::i8,skat_game,0>> value);
public: auto static constexpr diamonds = cpp2::strict_value<cpp2::i8,skat_game,0>(9);
Expand All @@ -42,7 +42,7 @@ public: explicit skat_game();
// 11
// 12

#line 10 "pure2-enum.cpp2"
#line 9 "pure2-enum.cpp2"
};

class rgb: public cpp2::strict_value<cpp2::i8,rgb,0> {
Expand All @@ -59,7 +59,7 @@ public: explicit rgb();
// 0
// 1
// 2
#line 16 "pure2-enum.cpp2"
#line 15 "pure2-enum.cpp2"
};

class file_attributes: public cpp2::strict_value<cpp2::u8,file_attributes,1> {
Expand All @@ -79,7 +79,7 @@ public: explicit file_attributes();
// 2
// 4

#line 23 "pure2-enum.cpp2"
#line 22 "pure2-enum.cpp2"
};

auto main() -> int;
Expand Down Expand Up @@ -142,12 +142,14 @@ file_attributes::file_attributes(cpp2::in<cpp2::strict_value<cpp2::u8,file_attri
[[nodiscard]] auto file_attributes::to_string(cpp2::in<cpp2::strict_value<cpp2::u8,file_attributes,1>> value) -> std::string{

std::string ret {};

std::string comma {};
ret = "(";
if (value & (cached)) {ret += "cached";}
if (value & (current)) {ret += std::string(", ") + "current";}
if (value & (obsolete)) {ret += std::string(", ") + "obsolete";}
if (value & (cached_and_current)) {ret += std::string(", ") + "cached_and_current";}
if (value & (none)) {ret += std::string(", ") + "none";}
if ((value & cached) == cached) {ret += comma + "cached";comma = ", ";}
if ((value & current) == current) {ret += comma + "current";comma = ", ";}
if ((value & obsolete) == obsolete) {ret += comma + "obsolete";comma = ", ";}
if ((value & cached_and_current) == cached_and_current) {ret += comma + "cached_and_current";comma = ", ";}
if (value == none) {ret += comma + "none";comma = ", ";}
if (CPP2_UFCS_0(empty, ret)) {ret = "(invalid file_attributes enumerator value)";}
return ret + ")";
}
Expand All @@ -158,7 +160,7 @@ file_attributes::file_attributes(file_attributes const& that)
file_attributes::file_attributes()
: cpp2::strict_value<cpp2::u8,file_attributes,1>{ }{}

#line 25 "pure2-enum.cpp2"
#line 24 "pure2-enum.cpp2"
auto main() -> int{
// x : skat_game = 9; // error, can't construct skat_game from integer

Expand Down Expand Up @@ -208,6 +210,14 @@ auto main() -> int{

auto f2 {file_attributes::cached};

std::cout << "f is " << f << "\n";
std::cout << "f2 is " << f2 << "\n";

CPP2_UFCS(clear, f2, f2);
std::cout << "f2 is " << f2 << "\n";
CPP2_UFCS(set, f2, file_attributes::cached);
std::cout << "f2 is " << f2 << "\n";

std::cout << "f as int is " + cpp2::to_string(cpp2::as_<int>(f)) + "\n";
std::cout << "f2 as int is " + cpp2::to_string(cpp2::as_<int>(f2)) + "\n";

Expand Down
2 changes: 1 addition & 1 deletion regression-tests/test-results/version
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@

cppfront compiler v0.2.1 Build 8910:0856
cppfront compiler v0.2.1 Build 8910:1255
Copyright(c) Herb Sutter All rights reserved

SPDX-License-Identifier: CC-BY-NC-ND-4.0
Expand Down
2 changes: 1 addition & 1 deletion source/build.info
Original file line number Diff line number Diff line change
@@ -1 +1 @@
"8910:0856"
"8910:1255"
116 changes: 104 additions & 12 deletions source/reflect.h
Original file line number Diff line number Diff line change
Expand Up @@ -38,7 +38,7 @@ class alias_declaration;
#line 807 "reflect.h2"
class value_member_info;

#line 1030 "reflect.h2"
#line 1115 "reflect.h2"
}
}

Expand Down Expand Up @@ -627,7 +627,7 @@ struct basic_enum__ret { std::string underlying_type; std::string strict_underly
cpp2::in<bool> bitwise
) -> basic_enum__ret;

#line 967 "reflect.h2"
#line 974 "reflect.h2"
//-----------------------------------------------------------------------
//
// "An enum[...] is a totally ordered value type that stores a
Expand All @@ -639,7 +639,7 @@ struct basic_enum__ret { std::string underlying_type; std::string strict_underly
//
auto cpp2_enum(meta::type_declaration& t) -> void;

#line 992 "reflect.h2"
#line 999 "reflect.h2"
//-----------------------------------------------------------------------
//
// "flag_enum expresses an enumeration that stores values
Expand All @@ -652,8 +652,34 @@ auto cpp2_enum(meta::type_declaration& t) -> void;
//
auto flag_enum(meta::type_declaration& t) -> void;

#line 1027 "reflect.h2"
#line 1034 "reflect.h2"
//-----------------------------------------------------------------------
//
// "As with void*, programmers should know that unions [...] are
// inherently dangerous, should be avoided wherever possible,
// and should be handled with special care when actually needed."
//
// -- Stroustrup (The Design and Evolution of C++, 14.3.4.1)
//
// "C++17 needs a type-safe union... The implications of the
// consensus `variant` design are well understood and have been
// explored over several LEWG discussions, over a thousand emails,
// a joint LEWG/EWG session, and not to mention 12 years of
// experience with Boost and other libraries."
//
// -- Axel Naumann, in P0088 (wg21.link/p0088),
// the adopted proposal for C++17 std::variant
//
//-----------------------------------------------------------------------
//
// union
//
// a type that contains exactly one of a fixed set of values at a time
//

auto cpp2_union(meta::type_declaration& t) -> void;

#line 1113 "reflect.h2"
//=======================================================================
// Switch to Cpp1 and close subnamespace meta
}
Expand Down Expand Up @@ -722,8 +748,11 @@ auto parser::apply_type_meta_functions( declaration_node& n )
else if (name == "flag_enum") {
flag_enum( rtype );
}
else if (name == "union") {
cpp2_union( rtype );
}
else {
error( "(temporary alpha limitation) unrecognized metafunction name '" + name + "' - currently the supported names are: interface, polymorphic_base, ordered, weakly_ordered, partially_ordered, copyable, basic_value, value, weakly_ordered_value, partially_ordered_value, struct, enum, flag_enum" );
error( "(temporary alpha limitation) unrecognized metafunction name '" + name + "' - currently the supported names are: interface, polymorphic_base, ordered, weakly_ordered, partially_ordered, copyable, basic_value, value, weakly_ordered_value, partially_ordered_value, struct, enum, flag_enum, union" );
return false;
}
}
Expand Down Expand Up @@ -1442,16 +1471,23 @@ cpp2::i64 value = -1;
to_string += " ret: std::string = ();\n";
auto first {true};

if (bitwise) {
to_string += " comma: std::string = ();\n";
}

for (

auto const& e : enumerators ) { do {
if (bitwise) {
std::string comma {"std::string(\", \") + "};
if (first) {
to_string += " ret = \"(\";\n";
comma = "";
}
to_string += " if value & (" + cpp2::to_string(e.name) + ") { ret += " + cpp2::to_string(comma) + "\"" + cpp2::to_string(e.name) + "\"; }\n";
if (e.name == "none") { // a "none" flag should match if no bits set
to_string += " if value == " + cpp2::to_string(e.name) + " { ret += comma + \"" + cpp2::to_string(e.name) + "\"; comma = \", \"; }\n";
}
else { // other flags need to be &-ed
to_string += " if (value & " + cpp2::to_string(e.name) + ") == " + cpp2::to_string(e.name) + " { ret += comma + \"" + cpp2::to_string(e.name) + "\"; comma = \", \"; }\n";
}
}
else {
std::string else_ {"else "};
Expand All @@ -1477,13 +1513,13 @@ cpp2::i64 value = -1;
CPP2_UFCS(require, t, CPP2_UFCS(add_member, t, " to_string: (this) -> std::string = { return " + cpp2::to_string(CPP2_UFCS_0(name, t)) + "::to_string(this); }"),
"could not add to_string member function");

#line 961 "reflect.h2"
#line 968 "reflect.h2"
// 3. A basic_enum is-a value type

CPP2_UFCS_0(basic_value, t);
return { std::move(underlying_type), std::move(strict_underlying_type.value()) }; }

#line 976 "reflect.h2"
#line 983 "reflect.h2"
auto cpp2_enum(meta::type_declaration& t) -> void
{
// Let basic_enum do its thing, with an incrementing value generator
Expand All @@ -1499,7 +1535,7 @@ auto cpp2_enum(meta::type_declaration& t) -> void
));
}

#line 1002 "reflect.h2"
#line 1009 "reflect.h2"
auto flag_enum(meta::type_declaration& t) -> void
{
// Add "none" member as a regular name to signify "no flags set"
Expand All @@ -1524,7 +1560,63 @@ auto flag_enum(meta::type_declaration& t) -> void
));
}

#line 1030 "reflect.h2"
#line 1058 "reflect.h2"
auto cpp2_union(meta::type_declaration& t) -> void
{
std::vector<value_member_info> alternatives {};

// 1. Gather: All the user-written members, and find/compute the max size

//(copy first := true)
for (
//next first = false
auto const& m : CPP2_UFCS_0(get_members, t) )
{
CPP2_UFCS(require, m, (CPP2_UFCS_0(is_public, m) || CPP2_UFCS_0(is_default_access, m)) && CPP2_UFCS_0(is_object, m),
"a union alternative cannot be protected or private");

if (CPP2_UFCS_0(is_object, m)) {
auto mo {CPP2_UFCS_0(as_object, m)};

// Adding local variable 'e' to work around a Clang warning
value_member_info e {cpp2::as_<std::string>(CPP2_UFCS_0(name, mo)), CPP2_UFCS_0(type, mo), cpp2::as_<std::string>(CPP2_UFCS_0(initializer, mo))};
CPP2_UFCS(push_back, alternatives, e);
}
}

#line 1082 "reflect.h2"
// 2. Replace: Erase the contents and replace with modified contents

CPP2_UFCS_0(remove_all_members, t);

// Compute the size
std::string Size {"Size :== cpp2::max( "};
{
std::string comma = "";

#line 1090 "reflect.h2"
for (

auto const& e : alternatives ) { do {
Size += comma + "sizeof(" + cpp2::to_string(e.type) + ")";
} while (false); comma = ", "; }
}

#line 1096 "reflect.h2"
Size += " );\n";
CPP2_UFCS(require, t, CPP2_UFCS(add_member, t, std::move(Size)),
"could not add Size");

#line 1102 "reflect.h2"
// TODO

#line 1106 "reflect.h2"
//// 3. A basic_enum is-a value

//t.value();
}

#line 1115 "reflect.h2"
}
}

Expand Down
Loading

0 comments on commit ecd3726

Please sign in to comment.