Skip to content

Commit 36de66c

Browse files
committed
Update grammar and docs for optional trailing commas in lists
1 parent 7041994 commit 36de66c

18 files changed

+78
-30
lines changed

docs/cpp2/common.md

Lines changed: 51 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -55,6 +55,56 @@ The usual `#!cpp // line comments` and `#!cpp /* stream comments */` are support
5555
```
5656

5757

58+
## <a id="lists"></a> Lists and commas
59+
60+
All lists use `,` commas between list items, and may be enclosed by
61+
62+
- `(` `)` parentheses, for most lists
63+
64+
- `[` `]` brackets, for calling the subscript operator
65+
66+
- `<` `>` angle brackets, for template parameter/argument lists
67+
68+
For example:
69+
70+
``` cpp title="Lists, using optional trailing commas just because we can" hl_lines="1 4 6 7"
71+
print: <T,U> (t: T, u: U) = std::cout << t << u << "\n";
72+
73+
main: () = {
74+
array: std::array = ('A', 'B', 'C');
75+
76+
for (0, 1, 2) do (e) {
77+
print( e, array[e] );
78+
}
79+
// Prints:
80+
// 0A
81+
// 1B
82+
// 2C
83+
}
84+
```
85+
86+
87+
An extra comma at the end of the list, before the closing `)` or `>`, is always allowed but ignored if present (for details, see [Design note: Commas](https://github.com/hsutter/cppfront/wiki/Design-note%3A-Commas)).
88+
89+
For example:
90+
91+
``` cpp title="Lists, using optional trailing commas just because we can" hl_lines="1 4 6 7"
92+
print: <T,U,> (t: T, u: U,) = std::cout << t << u << "\n";
93+
94+
main: () = {
95+
array: std::array = ('A', 'B', 'C',);
96+
97+
for (0, 1, 2,) do (e) {
98+
print( e, array[e,], );
99+
}
100+
// Prints:
101+
// 0A
102+
// 1B
103+
// 2C
104+
}
105+
```
106+
107+
58108
## <a id="keywords"></a> Reserved keywords
59109

60110
Cpp2 has very few globally reserved keywords; nearly all keywords are contextual, where they have their special meaning when they appear in a particular place in the grammar. For example:
@@ -110,7 +160,7 @@ p: const * * const i32;
110160

111161
Cpp2 supports the same `#!cpp 'c'`haracter, `#!cpp "string"`, binary, integer, and floating point literals as Cpp1, including most Unicode encoding prefixes and raw string literals.
112162

113-
Cpp2 supports using Cpp1 user-defined literals for compatibility, to support seamlessly using existing libraries. However, because Cpp2 has unified function call syntax (UFCS), the preferred way to author the equivalent in Cpp2 is to just write a function or type name as a `.` call suffix. For example:
163+
Cpp2 supports using Cpp1 user-defined literals for compatibility, to support seamlessly using existing libraries. However, because Cpp2 has [unified function call syntax (UFCS)](expressions.md#ufcs), the preferred way to author the equivalent in Cpp2 is to just write a function or type name as a `.` call suffix. For example:
114164

115165
- You can create a `u8` value by writing either `u8(123)` or **`123.u8()`**. [^u8using]
116166

docs/cpp2/declarations.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ f:(x: int = init) = statement; // same, { } is implicit
8585

8686
### <a id="template-parameters"></a> Template parameters
8787

88-
A template parameter list is enclosed by `<` `>` angle brackets, and the parameters separated by commas. Each parameter is declared using the [same syntax as any type or object](declarations.md). If a parameter's **`:`** ***kind*** is not specified, the default is `: type`.
88+
A template parameter list is a [list](common.md#lists) enclosed by `<` `>` angle brackets, and the parameters separated by commas. Each parameter is declared using the [same syntax as any type or object](declarations.md). If a parameter's **`:`** ***kind*** is not specified, the default is `: type`.
8989

9090
For example:
9191

docs/cpp2/expressions.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33

44
## <a id="ufcs"></a> Calling functions: `f(x)` syntax, and `x.f()` UFCS syntax
55

6+
A function argument list is a [list](common.md#lists) of arguments enclosed by `(` `)` parentheses.
7+
68
A function call like `f(x)` is a normal function call that will call non-member functions only, as usual in C++.
79

810
A function call like `x.f()` is a unified function call syntax (aka UFCS) call. It will call a member function if one is available, and otherwise will call `f(x)`. Having UFCS is important for generic code that may want to call a member or a non-member function, whichever is available. It's also important to enable fluid programming styles and natural IDE autocompletion support.

docs/cpp2/functions.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@ func: ( /* no parameters */ ) = { /* empty body */ }
1414
1515
## <a id="parameters"></a> Parameters
1616
17-
The parameter list is enclosed by `(` `)` parentheses and the parameters are separated by commas. Each parameter is declared using the [same unified syntax](declarations.md) as used for all declarations. For example:
17+
The parameter list is a [list](common.md#lists) enclosed by `(` `)` parentheses. Each parameter is declared using the [same unified syntax](declarations.md) as used for all declarations. For example:
1818
1919
``` cpp title="Declaring parameters" hl_lines="2-4"
2020
func: (

include/cpp2util.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1782,8 +1782,6 @@ constexpr auto unsafe_narrow( X&& x ) noexcept -> decltype(auto)
17821782
}
17831783

17841784

1785-
namespace impl {
1786-
17871785
//-----------------------------------------------------------------------
17881786
//
17891787
// args: see main() arguments as a container of string_views
@@ -1845,8 +1843,6 @@ inline auto make_args(int argc, char** argv) -> args_t
18451843
return args_t{argc, argv};
18461844
}
18471845

1848-
} // impl
1849-
18501846

18511847
//-----------------------------------------------------------------------
18521848
//

regression-tests/pure2-trailing-commas.cpp2

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ doubler: (a: int,) -> (i : int,) = {
88

99
vals: @struct type = { i: int; }
1010

11-
main: () -> int = {
11+
main: () = {
1212
(copy a := 42,) while false { a++; }
1313
_ = g(1, 2,);
1414

regression-tests/test-results/mixed-fixed-type-aliases.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,7 @@ auto test(auto const& x) -> void{
4848

4949
#line 19 "mixed-fixed-type-aliases.cpp2"
5050
[[nodiscard]] auto main(int const argc_, char** argv_) -> int{
51-
auto const args = cpp2::impl::make_args(argc_, argv_);
51+
auto const args = cpp2::make_args(argc_, argv_);
5252
#line 20 "mixed-fixed-type-aliases.cpp2"
5353
my::u16 y {42};
5454
test(std::move(y));

regression-tests/test-results/pure2-bugfix-for-discard-precedence.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,7 +45,7 @@ auto main(int const argc_, char** argv_) -> int;
4545

4646
#line 7 "pure2-bugfix-for-discard-precedence.cpp2"
4747
auto main(int const argc_, char** argv_) -> int{
48-
auto const args = cpp2::impl::make_args(argc_, argv_);
48+
auto const args = cpp2::make_args(argc_, argv_);
4949
#line 8 "pure2-bugfix-for-discard-precedence.cpp2"
5050
quantity x {1729};
5151
static_cast<void>(x + x);// Not `(void) x + x`; would attempt to add a `void` to `x`.

regression-tests/test-results/pure2-for-loop-range-with-lambda.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,7 @@ auto main(int const argc_, char** argv_) -> int;
2424

2525
#line 3 "pure2-for-loop-range-with-lambda.cpp2"
2626
auto main(int const argc_, char** argv_) -> int{
27-
auto const args = cpp2::impl::make_args(argc_, argv_);
27+
auto const args = cpp2::make_args(argc_, argv_);
2828
#line 4 "pure2-for-loop-range-with-lambda.cpp2"
2929
std::array const ints {1, 2, 3, 4, 5};
3030
// OK

regression-tests/test-results/pure2-initialization-safety-with-else-if.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ auto main(int const argc_, char** argv_) -> int;
1818

1919
#line 1 "pure2-initialization-safety-with-else-if.cpp2"
2020
auto main(int const argc_, char** argv_) -> int{
21-
auto const args = cpp2::impl::make_args(argc_, argv_);
21+
auto const args = cpp2::make_args(argc_, argv_);
2222
#line 2 "pure2-initialization-safety-with-else-if.cpp2"
2323
cpp2::impl::deferred_init<int*> p;
2424

regression-tests/test-results/pure2-last-use.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1562,7 +1562,7 @@ auto x{cpp2_new<int>(0)};
15621562

15631563
#line 1043 "pure2-last-use.cpp2"
15641564
auto main(int const argc_, char** argv_) -> int{
1565-
auto const args = cpp2::impl::make_args(argc_, argv_);
1565+
auto const args = cpp2::make_args(argc_, argv_);
15661566
#line 1044 "pure2-last-use.cpp2"
15671567
issue_683(args);
15681568
issue_847_2(std::vector<std::unique_ptr<int>>());

regression-tests/test-results/pure2-main-args.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ auto main(int const argc_, char** argv_) -> int;
1818

1919
#line 1 "pure2-main-args.cpp2"
2020
auto main(int const argc_, char** argv_) -> int{
21-
auto const args = cpp2::impl::make_args(argc_, argv_);
21+
auto const args = cpp2::make_args(argc_, argv_);
2222
// Explicit call to string is necessary
2323
// std::filesystem::path is base on and implicitly convertible to
2424
// - std::string (on POSIX systems)

regression-tests/test-results/pure2-statement-scope-parameters.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ auto main(int const argc_, char** argv_) -> int;
2222

2323
#line 2 "pure2-statement-scope-parameters.cpp2"
2424
auto main(int const argc_, char** argv_) -> int{
25-
auto const args = cpp2::impl::make_args(argc_, argv_);
25+
auto const args = cpp2::make_args(argc_, argv_);
2626
#line 3 "pure2-statement-scope-parameters.cpp2"
2727
auto local_int {42};
2828
{

regression-tests/test-results/pure2-trailing-commas.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@ using doubler_ret = int;
2828
#line 9 "pure2-trailing-commas.cpp2"
2929
class vals {public: int i; };
3030

31-
[[nodiscard]] auto main() -> int;
31+
auto main() -> int;
3232

3333
//=== Cpp2 function definitions =================================================
3434

@@ -46,7 +46,7 @@ template<typename T, typename U> [[nodiscard]] auto g(T const& a, U const& b) ->
4646
return std::move(i.value()); }
4747

4848
#line 11 "pure2-trailing-commas.cpp2"
49-
[[nodiscard]] auto main() -> int{
49+
auto main() -> int{
5050
{
5151
auto a{42};
5252
#line 12 "pure2-trailing-commas.cpp2"

regression-tests/test-results/version

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11

2-
cppfront compiler v0.3.0 Build 9314:1742
2+
cppfront compiler v0.3.0 Build 9316:1733
33
Copyright(c) Herb Sutter All rights reserved
44

55
SPDX-License-Identifier: CC-BY-NC-ND-4.0

source/build.info

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
"9314:1742"
1+
"9316:1739"

source/parse.h

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -5630,8 +5630,7 @@ class parser
56305630
//G inspect-expression
56315631
//G id-expression
56325632
//G literal
5633-
//G '(' expression-list ')'
5634-
//GT '{' expression-list '}'
5633+
//G '(' expression-list ','? ')'
56355634
//G unnamed-declaration
56365635
//G
56375636
auto primary_expression()
@@ -5667,7 +5666,7 @@ class parser
56675666
auto close = close_paren_type(open_paren->type());
56685667
auto close_text = [&] () -> std::string { if (close == lexeme::RightParen) { return ")"; } return "}"; }();
56695668
next();
5670-
auto expr_list = expression_list(open_paren, inside_initializer);
5669+
auto expr_list = expression_list(open_paren, lexeme::RightParen, inside_initializer);
56715670
if (!expr_list) {
56725671
error("unexpected text - ( is not followed by an expression-list");
56735672
next();
@@ -5760,8 +5759,8 @@ class parser
57605759
//G postfix-expression:
57615760
//G primary-expression
57625761
//G postfix-expression postfix-operator [Note: without whitespace before the operator]
5763-
//G postfix-expression '[' expression-list? ']'
5764-
//G postfix-expression '(' expression-list? ')'
5762+
//G postfix-expression '[' expression-list? ','? ']'
5763+
//G postfix-expression '(' expression-list? ','? ')'
57655764
//G postfix-expression '.' id-expression
57665765
//G
57675766
auto postfix_expression()
@@ -5839,7 +5838,7 @@ class parser
58395838

58405839
if (term.op->type() == lexeme::LeftBracket)
58415840
{
5842-
term.expr_list = expression_list(term.op);
5841+
term.expr_list = expression_list(term.op, lexeme::RightBracket);
58435842
if (!term.expr_list)
58445843
{
58455844
error("[ is not followed by a valid expression list");
@@ -5860,7 +5859,7 @@ class parser
58605859
// If not, then this wasn't a call expression so backtrack to
58615860
// the '(' which will be part of the next grammar production
58625861

5863-
term.expr_list = expression_list(term.op);
5862+
term.expr_list = expression_list(term.op, lexeme::RightParen);
58645863
if (
58655864
term.expr_list
58665865
&& curr().type() == lexeme::RightParen
@@ -6326,7 +6325,8 @@ class parser
63266325
//G
63276326
auto expression_list(
63286327
token const* open_paren,
6329-
bool inside_initializer = false
6328+
lexeme closer,
6329+
bool inside_initializer = false
63306330
)
63316331
-> std::unique_ptr<expression_list_node>
63326332
{
@@ -6362,7 +6362,7 @@ class parser
63626362
next();
63636363

63646364
// Allow a trailing comma in the list
6365-
if (curr().type() == lexeme::RightParen) {
6365+
if (curr().type() == closer) {
63666366
break;
63676367
}
63686368

@@ -7778,7 +7778,7 @@ class parser
77787778

77797779

77807780
//G parameter-declaration-list:
7781-
//G '(' parameter-declaration-seq? ')'
7781+
//G '(' parameter-declaration-seq? ','? ')'
77827782
//G
77837783
//G parameter-declaration-seq:
77847784
//G parameter-declaration

source/to_cpp1.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4813,7 +4813,7 @@ class cppfront
48134813
n.parameters->position()
48144814
);
48154815
current_functions.back().prolog.statements.push_back(
4816-
"auto const args = cpp2::impl::make_args(argc_, argv_); "
4816+
"auto const args = cpp2::make_args(argc_, argv_); "
48174817
);
48184818
}
48194819
else {

0 commit comments

Comments
 (0)