Skip to content

Commit 3227164

Browse files
committed
Added contract violation message support
Fixed tokenizer keyword bug Fixed function contract parsing bug Started work to maintain multiline formatting for multiline function argument lists Throw an exception for unexpected EOF to get nicer message
1 parent 5c4ac81 commit 3227164

File tree

4 files changed

+158
-111
lines changed

4 files changed

+158
-111
lines changed

cpp2util.h

Lines changed: 26 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -196,60 +196,70 @@ class out {
196196
#define CPP2_SOURCE_LOCATION_PARAM , std::source_location where
197197
#define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT , std::source_location where = std::source_location::current()
198198
#define CPP2_SOURCE_LOCATION_PARAM_SOLO std::source_location where
199-
#define CPP2_SOURCE_LOCATION_PARAM_SOLO_ANON std::source_location
199+
//#define CPP2_SOURCE_LOCATION_PARAM_SOLO_ANON std::source_location
200200
#define CPP2_SOURCE_LOCATION_ARG , where
201-
#define CPP2_SOURCE_LOCATION_ARG_SOLO where
201+
//#define CPP2_SOURCE_LOCATION_ARG_SOLO where
202202
#else
203203
#define CPP2_SOURCE_LOCATION_PARAM
204204
#define CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT
205205
#define CPP2_SOURCE_LOCATION_PARAM_SOLO
206-
#define CPP2_SOURCE_LOCATION_PARAM_SOLO_ANON
206+
//#define CPP2_SOURCE_LOCATION_PARAM_SOLO_ANON
207207
#define CPP2_SOURCE_LOCATION_ARG
208-
#define CPP2_SOURCE_LOCATION_ARG_SOLO
208+
//#define CPP2_SOURCE_LOCATION_ARG_SOLO
209209
#endif
210210

211211

212212
class contract_group {
213213
public:
214-
using handler = void (*)(CPP2_SOURCE_LOCATION_PARAM_SOLO_ANON) noexcept;
214+
using handler = void (*)(const char* msg CPP2_SOURCE_LOCATION_PARAM) noexcept;
215215

216216
constexpr contract_group (handler h = nullptr) : reporter(h) { }
217217
constexpr auto set_handler(handler h) -> handler { assert(h); auto old = reporter; reporter = h; return old; }
218218
constexpr auto get_handler() const -> handler { return reporter; }
219-
constexpr auto expects (bool b CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) -> void { if (!b) reporter(CPP2_SOURCE_LOCATION_ARG_SOLO); }
219+
constexpr auto expects (bool b, const char* msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT)
220+
-> void { if (!b) reporter(msg CPP2_SOURCE_LOCATION_ARG); }
220221
private:
221222
handler reporter;
222223
};
223224

224-
[[noreturn]] auto report_and_terminate(std::string_view msg CPP2_SOURCE_LOCATION_PARAM) noexcept -> void {
225+
[[noreturn]] auto report_and_terminate(std::string_view group, const char* msg = "" CPP2_SOURCE_LOCATION_PARAM_WITH_DEFAULT) noexcept -> void {
225226
std::cerr
226227
#ifdef CPP2_USE_SOURCE_LOCATION
227228
<< where.file_name() << "2("
228229
<< where.line() << ") "
229230
<< where.function_name() << ": "
230231
#endif
231-
<< msg << " violation\n";
232+
<< group << " violation";
233+
if (msg[0] != '\0') {
234+
std::cerr << ": " << msg;
235+
}
236+
std::cerr << "\n";
232237
std::terminate();
233238
}
234239

235240
auto inline Default = contract_group(
236-
[](CPP2_SOURCE_LOCATION_PARAM_SOLO)noexcept {
237-
report_and_terminate("" CPP2_SOURCE_LOCATION_ARG);
241+
[](const char* msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
242+
report_and_terminate("Contract", msg CPP2_SOURCE_LOCATION_ARG);
238243
}
239244
);
240245
auto inline Bounds = contract_group(
241-
[](CPP2_SOURCE_LOCATION_PARAM_SOLO)noexcept {
242-
report_and_terminate("Bounds safety" CPP2_SOURCE_LOCATION_ARG);
246+
[](const char* msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
247+
report_and_terminate("Bounds safety", msg CPP2_SOURCE_LOCATION_ARG);
243248
}
244249
);
245250
auto inline Null = contract_group(
246-
[](CPP2_SOURCE_LOCATION_PARAM_SOLO)noexcept {
247-
report_and_terminate("Null safety" CPP2_SOURCE_LOCATION_ARG);
251+
[](const char* msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
252+
report_and_terminate("Null safety", msg CPP2_SOURCE_LOCATION_ARG);
253+
}
254+
);
255+
auto inline Type = contract_group(
256+
[](const char* msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
257+
report_and_terminate("Type safety", msg CPP2_SOURCE_LOCATION_ARG);
248258
}
249259
);
250260
auto inline Testing = contract_group(
251-
[](CPP2_SOURCE_LOCATION_PARAM_SOLO)noexcept {
252-
report_and_terminate("Testing" CPP2_SOURCE_LOCATION_ARG);
261+
[](const char* msg CPP2_SOURCE_LOCATION_PARAM)noexcept {
262+
report_and_terminate("Testing", msg CPP2_SOURCE_LOCATION_ARG);
253263
}
254264
);
255265

cppfront.cpp

Lines changed: 59 additions & 40 deletions
Original file line numberDiff line numberDiff line change
@@ -411,6 +411,7 @@ class positional_printer
411411
adjusted_pos.colno = preempt_pos.colno;
412412
}
413413
preempt_pos = {};
414+
assert (preempt_pos == source_position{});
414415
}
415416

416417
// (2) Otherwise, see if there's a previous line's offset to repeat
@@ -568,6 +569,12 @@ class cppfront
568569
parameter_declaration_list_node single_anon;
569570
// special value - hack for now to note single-anon-return type kind in this function_returns working list
570571

572+
struct text_with_pos{
573+
std::string text;
574+
source_position pos;
575+
text_with_pos(std::string const& t, source_position p) : text{t}, pos{p} { }
576+
};
577+
571578
public:
572579
//-----------------------------------------------------------------------
573580
// Constructor
@@ -613,21 +620,30 @@ class cppfront
613620

614621
// Parse
615622
//
616-
for (auto const& [line, entry] : tokens.get_map()) {
617-
if (!parser.parse(entry)) {
623+
try
624+
{
625+
for (auto const& [line, entry] : tokens.get_map()) {
626+
if (!parser.parse(entry)) {
627+
errors.emplace_back(
628+
source_position(line, 0),
629+
"parse failed for section starting here"
630+
);
631+
}
632+
}
633+
634+
// Sema
635+
parser.visit(sema);
636+
if (!sema.apply_local_rules()) {
618637
errors.emplace_back(
619-
source_position(line, 0),
620-
"parse failed for section starting here"
638+
source_position(-1, -1),
639+
"program violates initialization safety guarantee - see previous errors\n"
621640
);
622641
}
623642
}
624-
625-
// Sema
626-
parser.visit(sema);
627-
if (!sema.apply_local_rules()) {
643+
catch (std::runtime_error& e) {
628644
errors.emplace_back(
629645
source_position(-1, -1),
630-
"program violates initialization safety guarantee - see previous errors\n"
646+
"unexpected text or end-of-file - see previous errors\n"
631647
);
632648
}
633649
}
@@ -671,13 +687,16 @@ class cppfront
671687

672688
// First, echo the non-Cpp2 parts
673689
//
674-
auto cpp2_found = false;
690+
auto cpp2_found = false;
675691

676-
for (lineno_t curr_lineno = 0; auto const& line : source.get_lines())
692+
for (
693+
lineno_t curr_lineno = 0;
694+
auto const& line : source.get_lines()
695+
)
677696
{
678697
// Skip dummy line we added to make 0-vs-1-based offsets readable
679-
if (curr_lineno != 0) {
680-
698+
if (curr_lineno != 0)
699+
{
681700
// If it's a Cpp1 line, emit it
682701
if (line.cat != source_line::category::cpp2)
683702
{
@@ -769,8 +788,6 @@ class cppfront
769788
emit(*decl);
770789
}
771790
}
772-
773-
//emit( parser.get_parse_tree() ); // starts at translation_unit_node
774791
}
775792

776793

@@ -1056,7 +1073,7 @@ class cppfront
10561073
{
10571074
assert(n.identifier);
10581075
assert(*n.identifier == "return");
1059-
printer.print_cpp2("return ", n.position());
1076+
printer.print_cpp2("return", n.position());
10601077

10611078
// Return with expression == single anonymous return type
10621079
//
@@ -1219,13 +1236,8 @@ class cppfront
12191236

12201237
// Otherwise, we're going to have to potentially do some work to change
12211238
// some Cpp2 postfix operators to Cpp1 prefix operators, so let's set up...
1222-
struct element {
1223-
std::string text;
1224-
source_position pos;
1225-
element(std::string const& t, source_position p) : text{t}, pos{p} { }
1226-
};
1227-
auto prefix = std::vector<element>{};
1228-
auto suffix = std::vector<element>{};
1239+
auto prefix = std::vector<text_with_pos>{};
1240+
auto suffix = std::vector<text_with_pos>{};
12291241

12301242
auto print = std::string{};
12311243
auto emitted_n = false;
@@ -1359,10 +1371,10 @@ class cppfront
13591371
}
13601372

13611373
printer.print_cpp2("static_cast<", n.position());
1362-
printer.preempt_position(n.position());
1374+
//printer.preempt_position(n.position());
13631375
emit(*n.terms.front().expr);
13641376
printer.print_cpp2(">(", n.position());
1365-
printer.preempt_position(n.position());
1377+
//printer.preempt_position(n.position());
13661378
emit(*n.expr);
13671379
printer.print_cpp2(")", n.position());
13681380
return;
@@ -1408,29 +1420,39 @@ class cppfront
14081420

14091421
//-----------------------------------------------------------------------
14101422
//
1411-
auto emit(expression_list_node const& n) -> void
1423+
auto emit(expression_list_node const& n, std::vector<text_with_pos>* as_text = nullptr) -> void
14121424
{
1425+
auto print = [&](std::string const& text, source_position pos) {
1426+
if (as_text) {
1427+
as_text->emplace_back( text, pos );
1428+
}
1429+
else {
1430+
printer.print_cpp2( text, pos );
1431+
1432+
}
1433+
};
1434+
14131435
auto first = true;
14141436
for (auto const& x : n.expressions) {
14151437
if (!first) {
1416-
printer.print_cpp2(", ", n.position());
1438+
print(", ", n.position());
14171439
}
14181440
first = false;
14191441

14201442
if (x.pass != passing_style::in) {
14211443
assert(to_string_view(x.pass) == "out" || to_string_view(x.pass) == "move");
14221444
if (to_string_view(x.pass) == "out") {
1423-
printer.print_cpp2("&", n.position());
1445+
print("&", n.position());
14241446
}
14251447
else if (to_string_view(x.pass) == "move") {
1426-
printer.print_cpp2("std::move(", n.position());
1448+
print("std::move(", n.position());
14271449
}
1428-
printer.add_pad_in_this_line(-3);
1450+
//printer.add_pad_in_this_line(-3);
14291451
}
14301452
assert(x.expr);
14311453
emit(*x.expr);
14321454
if (to_string_view(x.pass) == "move") {
1433-
printer.print_cpp2(")", n.position());
1455+
print(")", n.position());
14341456
}
14351457
}
14361458
}
@@ -1635,8 +1657,9 @@ class cppfront
16351657
assert (*uid && (**uid).identifier);
16361658
if (
16371659
*(**uid).identifier == "Default" ||
1638-
*(**uid).identifier == "Bounds" ||
1639-
*(**uid).identifier == "Null" ||
1660+
*(**uid).identifier == "Bounds" ||
1661+
*(**uid).identifier == "Null" ||
1662+
*(**uid).identifier == "Type" ||
16401663
*(**uid).identifier == "Testing"
16411664
)
16421665
{
@@ -1658,14 +1681,10 @@ class cppfront
16581681
printer.print_cpp2(".expects(", n.position());
16591682
assert(n.condition);
16601683
emit (*n.condition);
1684+
printer.print_cpp2(", ", n.position());
1685+
assert (n.message);
1686+
emit (*n.message);
16611687
printer.print_cpp2(");", n.position());
1662-
1663-
1664-
1665-
// TODO: pass the message through
1666-
1667-
1668-
16691688
}
16701689

16711690

lex.h

Lines changed: 33 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -400,34 +400,41 @@ auto lex_line(
400400
{
401401
// Cpp2 has a smaller set of the Cpp1 globally reserved keywords, but we continue to
402402
// reserve all the ones Cpp1 has both for compatibility and to not give up a keyword
403+
// Some keywords like "delete" and "union" are not in this list because we reject them elsewhere
403404
// Cpp2 also adds a couple, notably "is" and "as"
404405
const auto keys = std::regex(
405-
"^alignas\\s|^alignof\\s|^asm\\s|^as\\s|^auto\\s|"
406-
"^bool\\s|^break\\s|"
407-
"^case\\s|^catch\\s|^char\\s|^char16_t\\s|^char32_t\\s|^char8_t\\s|^class\\s|^co_await\\s|^co_return\\s|"
408-
"^co_yield\\s|^concept\\s|^const\\s|^const_cast\\s|^consteval\\s|^constexpr\\s|^constinit\\s|^continue\\s|"
409-
"^decltype\\s|^default\\s|^double\\s|^do\\s|^dynamic_cast\\s|"
410-
"^else\\s|^enum\\s|^explicit\\s|^export\\s|^extern\\s|"
411-
"^false\\s|^float\\s|^for\\s|^friend\\s|"
412-
"^goto\\s|"
413-
"^if\\s|^import\\s|^inline\\s|^int\\s|^is\\s|"
414-
"^long\\s|"
415-
"^module\\s|^mutable\\s|"
416-
"^namespace\\s|^new\\s|^noexcept\\s|^nullptr\\s|"
417-
"^operator\\s|"
418-
"^private\\s|^protected\\s|^public\\s|"
419-
"^register\\s|^reinterpret_cast\\s|^requires\\s|^return\\s|"
420-
"^short\\s|^signed\\s|^sizeof\\s|^static\\s|^static_assert\\s|^static_cast\\s|^struct\\s|^switch\\s|"
421-
"^template\\s|^this\\s|^thread_local\\s|^throws\\s|^throw\\s|^true\\s|^try\\s|^typedef\\s|^typeid\\s|^typename\\s|"
422-
"^unsigned\\s|^using\\s|"
423-
"^virtual\\s|^void\\s|^volatile\\s|"
424-
"^wchar_t\\s|^while\\s"
406+
"^alignas|^alignof|^asm|^as|^auto|"
407+
"^bool|^break|"
408+
"^case|^catch|^char|^char16_t|^char32_t|^char8_t|^class|^co_await|^co_return|"
409+
"^co_yield|^concept|^const|^const_cast|^consteval|^constexpr|^constinit|^continue|"
410+
"^decltype|^default|^double|^do|^dynamic_cast|"
411+
"^else|^enum|^explicit|^export|^extern|"
412+
"^false|^float|^for|^friend|"
413+
"^goto|"
414+
"^if|^import|^inline|^int|^is|"
415+
"^long|"
416+
"^module|^mutable|"
417+
"^namespace|^new|^noexcept|^nullptr|"
418+
"^operator|"
419+
"^private|^protected|^public|"
420+
"^register|^reinterpret_cast|^requires|^return|"
421+
"^short|^signed|^sizeof|^static|^static_assert|^static_cast|^struct|^switch|"
422+
"^template|^this|^thread_local|^throws|^throw|^true|^try|^typedef|^typeid|^typename|"
423+
"^unsigned|^using|"
424+
"^virtual|^void|^volatile|"
425+
"^wchar_t|^while"
425426
);
426427

427428
std::cmatch m;
428429
if (std::regex_search(&line[i], m, keys)) {
429430
assert (m.position(0) == 0);
430-
return (int)(m[0].length()-1);
431+
// If we matched and what's next is EOL or a non-identifier char, we matched!
432+
if (i+m[0].length() == line.length() || // EOL
433+
!is_identifier_continue(line[i+m[0].length()]) // non-identifier char
434+
)
435+
{
436+
return (int)(m[0].length());;
437+
}
431438
}
432439
return 0;
433440
};
@@ -795,7 +802,11 @@ auto lex_line(
795802
if (tokens.back() == "delete") {
796803
errors.emplace_back(
797804
source_position(lineno, i),
798-
"'delete' and owning raw pointers are not supported in Cpp2 - use unique.new<T>, shared.new<T>, or gc.new<T> instead (in that order)"
805+
"'delete' and owning raw pointers are not supported in Cpp2"
806+
);
807+
errors.emplace_back(
808+
source_position(lineno, i),
809+
" - use unique.new<T>, shared.new<T>, or gc.new<T> instead (in that order)"
799810
);
800811
}
801812
}

0 commit comments

Comments
 (0)