Skip to content

Commit a21bcb5

Browse files
hsutterDyXelgregmarrbluetarpmedia
authored
Merge 1.0 documentation into main (#1016)
* Initial files to test MkDocs with Material * Update checkout version * Trying checkout with no version * Back to v3 * Try renaming to docs * Test push to renamed docs branch * Try moving mkdocs.yml to root to unblock CI * Further cleanup to get things in the right directories * Finish moving from `/docs/docs` to `/docs` Added local hosting instructions in the YAML file This renders beautifully locally, but for some reason it doesn't render properly on GitHub Pages yet. One possible reason is the `pages-build-deployment` workflow that GitHub Pages created on my initial attempt to use Pages (before trying MkDocs) is still running (and I can't figure out how to get rid of it) and it appears to be interfering with the `docs` workflow I created for MkDocs If someone has ideas on how to debug this, please open an issue or email me - thx! * Add "Cppfront reference," and start writing "Cpp2 reference" * Merged documentation from blog posts, and unary operators `_` wildcard, including in `inspect` and explicit discard Named `break` and `continue` `type` declaration syntax Explicit `this` `operator=` Chained comparisons Metafunctions overview `@enum` and `@flag_enum` `@union` * Integrate links to wiki design notes * Add more sections Type qualifiers Binary operators `is` and update chained comparisons * Add `as` and `inspect` * Document declarations, improve `inspect` discussion * Fix a few typos * Add Hello-world xref * Update mkdocs.yml * Improve mixed files examples and flow * Overview editorial improvements * Minor cleanup * docs: fix some typos and confusing wording (#976) * docs: fix some typos and confusing wording * restore std::ssize * Fix table of content display -> rhs of page * Add section navigation Reorganize sources Fix long code lines to avoid horizontal scroll bars * Organize the welcome info into three pages And try to use extra CSS to tweak the navigation pane * Disable regression tests on this branch * Add more types and `operator=` material And do further cleanup on the docs structure * Add keywords, objects, and heap allocation * Add `main` * Reviewing cppfront docs (#982) * Reviewing cppfront docs * integrations.md * expressions and objects * Fix "lines 8, 9, and 15" wording * Mention UFCS * Function outputs and explicit discard * Add definite initialization section And: - add placeholder for contracts - add some is/as side-by-side examples - add parameter passing styles * Update CTAD description in hello-world.md (#984) Signed-off-by: Neil Henderson <[email protected]> * Embiggen text font, add `move` and `out` arguments And code block cleanup: - highlight key lines in all code blocks - remove redundant "Example:" in code block titles - add a chained comparisons example * Fix small typo in common.md (#985) Signed-off-by: Neil Henderson <[email protected]> * Changes to expressions.md (#986) * Update expressions.md Signed-off-by: Neil Henderson <[email protected]> * Minor tweak to not lose "dynamic" types --------- Signed-off-by: Neil Henderson <[email protected]> Co-authored-by: Herb Sutter <[email protected]> * Another round of docs updates (#983) * types * metafunctions * Taking a pass over the updates, and adding that `that` must be `in` or `move` * Remove TODO comment for now Not sure of its meaning, we can add again later --------- Co-authored-by: Herb Sutter <[email protected]> * Add syntax highlighting for inline code blocks using `#!cpp` shebangs Note: I deliberately did not add shebangs for: - `inline code` that wouldn't benefit from them (e.g., had nothing significant to highlight) so as to keep the Markdown more readable - `inline code` that I didn't want to highlight, mainly Cpp2 code that used Cpp1 reserved keywords in a non-reserved way (mainly metafunctions like @enum and @union) * Move function calls to expressions * Add capture section And add Cpp1 lowering notes for parameter passing * Add Mermaid build diagram * Add TODO for `member = _;` * Add interpolation formatting, and other minor cleanup * Expand comparisons section Also add short anchor names to all subsections that don't already have them And make anchor names all lowercase-like-this * Update declarations.md (#988) Signed-off-by: Neil Henderson <[email protected]> * Follow up merge with additional examples, and update highlighted linenos * Update Capture sections in expressions.md (#987) * Update expressions.md Signed-off-by: Neil Henderson <[email protected]> * Update highlighted linenos And a couple of other fixes, including that I meant to write "ish" not "sh" (fixing my own typo!) --------- Signed-off-by: Neil Henderson <[email protected]> Signed-off-by: Herb Sutter <[email protected]> Co-authored-by: Herb Sutter <[email protected]> * More docs reviews (#990) * Add more functions material Return values Branches Loops Template parameters * Changes to functions.md (#998) * Update functions.md Signed-off-by: Neil Henderson <[email protected]> * Tweak comments for divide example --------- Signed-off-by: Neil Henderson <[email protected]> Co-authored-by: Herb Sutter <[email protected]> * Fill in some TODO's * Add requires, namespaces, using, and namespace/type/function/object aliases * Update aliases.md (#1005) Signed-off-by: Neil Henderson <[email protected]> * Add generality notes: Function defaults, and function <-> block/stmt unification * Merge previous commit * Update functions.md (#1011) Signed-off-by: Neil Henderson <[email protected]> * Update declarations.md (#1010) Signed-off-by: Neil Henderson <[email protected]> * Complete the metafunctions section * Update metafunctions.md (#1015) Signed-off-by: Neil Henderson <[email protected]> * Add contracts documentation * Remove modules documentation stub since that's not supported yet * Fix comment typo --------- Signed-off-by: Neil Henderson <[email protected]> Signed-off-by: Herb Sutter <[email protected]> Co-authored-by: Dylam De La Torre <[email protected]> Co-authored-by: gregmarr <[email protected]> Co-authored-by: Neil Henderson <[email protected]>
1 parent d59ef7c commit a21bcb5

17 files changed

+2711
-50
lines changed

Diff for: .github/workflows/docs.yml

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
name: docs
2+
on:
3+
push:
4+
branches:
5+
- docs
6+
permissions:
7+
contents: write
8+
jobs:
9+
deploy:
10+
runs-on: ubuntu-latest
11+
steps:
12+
- uses: actions/checkout@v3
13+
- uses: actions/setup-python@v4
14+
with:
15+
python-version: 3.x
16+
- uses: actions/cache@v2
17+
with:
18+
key: ${{ github.ref }}
19+
path: .cache
20+
- run: pip install mkdocs-material
21+
- run: mkdocs gh-deploy --force

Diff for: docs/cpp2/common.md

+201
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,201 @@
1+
# Common programming concepts
2+
3+
## <a id="main"></a> `main`
4+
5+
As always, `main` is the entry point of the program. For example:
6+
7+
`main` can have either:
8+
9+
- No parameters: &emsp; **`#!cpp main: () /*etc.*/`**
10+
11+
- One parameter of implicit type named `args`: &emsp; **`#!cpp main: (args) /*etc.*/`**
12+
13+
- The type of `args` cannot be explicitly specified. It is always `cpp2::args_t`, which behaves similarly to a `#!cpp const std::array<std::string_view>`.
14+
15+
- Using `args` performs zero heap allocations. Every `string_view` is directly bound to the string storage provided by host environment.
16+
17+
- `args.argc` and `args.argv` additionally provide access to the raw C/C++ `main` parameters.
18+
19+
``` cpp title="main with (args)" hl_lines="5 9"
20+
// Print out command line arguments, then invoke
21+
// a Qt event loop for a non-UI Qt application
22+
main: (args) -> int
23+
= {
24+
for args do (arg) {
25+
std::cout << arg << "\n";
26+
}
27+
28+
app: QCoreApplication = (args.argc, args.argv);
29+
return app.exec();
30+
}
31+
```
32+
33+
`main` can return:
34+
35+
- `#!cpp void`, the default return value for functions. No `#!cpp return` statement is allowed in the body. In this case, the compiled Cpp1 code behaves as if `main` returned `#!cpp int`.
36+
37+
- `#!cpp int`. If the body has no `#!cpp return` statement, the default is to `#!cpp return 0;` at the end of the function body.
38+
39+
- Some other type that your Cpp1 compiler(s) supports as a nonstandard extension.
40+
41+
42+
## <a id="comments"></a> Comments
43+
44+
The usual `#!cpp // line comments` and `#!cpp /* stream comments */` are supported. For example:
45+
46+
``` cpp title="Writing comments"
47+
// A line comment: After //, the entire
48+
// rest of the line is part of the comment
49+
50+
/*
51+
A stream comment: After /*, everything until the
52+
next * / (without a space between) is part of the
53+
comment. Note that stream comments do not nest.
54+
*/
55+
```
56+
57+
58+
## <a id="keywords"></a> Reserved keywords
59+
60+
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:
61+
62+
- `new` is used as an ordinary function to do allocation (e.g., `shared.new<widget>(1, 2, 3)`).
63+
64+
- `struct` and `enum` are used as function names in the metafunctions library.
65+
66+
- `type` can be used as an ordinary name (e.g., `std::common_type<T1,T2>::type`).
67+
68+
In rare cases, usually when consuming code written in other languages, you may need to write a name that is a reserved keyword. The way to do that is to prefix it with `__identifer__`, which treats it as an ordinary identifier (without the prefix).
69+
70+
71+
## <a id="fundamental-types"></a> Fundamental data types
72+
73+
Cpp2 supports the same fundamental types as today's Cpp1, but additionally provides the following aliases in namespace `cpp2`:
74+
75+
| Fixed-width types | Synonym for |
76+
|---|---|
77+
| `i8` | `std::int8_t` |
78+
| `i16` | `std::int16_t` |
79+
| `i32` | `std::int32_t` |
80+
| `i64` | `std::int64_t` |
81+
| `u8` | `std::uint8_t` |
82+
| `u16` | `std::uint16_t` |
83+
| `u32` | `std::uint32_t` |
84+
| `u64` | `std::uint64_t` |
85+
86+
| Variable-width types <br> (Cpp2-compatible single-word names) | Synonym for (these multi-word<br> names are not allowed in Cpp2) |
87+
|---|---|
88+
| `ushort` | `#!cpp unsigned short` |
89+
| `uint` | `#!cpp unsigned int` |
90+
| `ulong` | `#!cpp unsigned long` |
91+
| `longlong` | `#!cpp long long` |
92+
| `ulonglong` | `#!cpp unsigned long long` |
93+
| `longdouble` | `#!cpp long double` |
94+
95+
| For compatibility/interop only,<br> so deliberately ugly names | Synonym for (these multi-word<br> names are not allowed in Cpp2) | Notes |
96+
|---|---|---|
97+
| `_schar` | `#!cpp signed char` | Normally, prefer `i8` instead |
98+
| `_uchar` | `#!cpp unsigned char` | Normally, prefer `u8` instead |
99+
100+
## <a id="type-qualifiers"></a> Type qualifiers
101+
102+
Types can be qualified with `#!cpp const` and `#!cpp *`. Types are written left-to-right, so a qualifier always applies to what immediately follows it. For example, to declare a `#!cpp const` pointer to a non-`#!cpp const` pointer to a `#!cpp const i32` object, write:
103+
104+
``` cpp title="Using type qualifiers"
105+
// A const pointer to a non-const pointer to a const i32 object
106+
p: const * * const i32;
107+
```
108+
109+
## <a id="literals"></a> Literals
110+
111+
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.
112+
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:
114+
115+
- You can create a `u8` value by writing either `u8(123)` or **`123.u8()`**. [^u8using]
116+
117+
- You can write a 'constexpr' function like `#!cpp nm: (value: i64) -> my_nanometer_type == { /*...*/ }` that takes an integer and returns a value of a strongly typed "nanometer" type, and then create a `nm` value by writing either `nm(123)` or **`123.nm()`**.
118+
119+
Both **`123.nm()`** and **`123.u8()`** are very similar to user-defined literal syntax, and more general.
120+
121+
## <a id="operators"></a> Operators
122+
123+
Operators have the same precedence and associativity as in Cpp1, but some unary operators that are prefix (always or sometimes) in Cpp1 are postfix (always) in Cpp2.
124+
125+
### <a id="unary-operators"></a> Unary operators
126+
127+
The operators `!`, `+`, and `-` are prefix, as in Cpp1. For example:
128+
129+
``` cpp title="Using prefix operators"
130+
if !vec.empty() {
131+
vec.emplace_back( -123.45 );
132+
}
133+
```
134+
135+
| Unary operator | Cpp2 example | Cpp1 equivalent |
136+
|---|---|---|
137+
| `!` | `!vec.empty()` | `!vec.empty()` |
138+
| `+` | `#!cpp +100` | `#!cpp +100` |
139+
| `-` | `#!cpp -100` | `#!cpp -100` |
140+
141+
The operators `.`, `*`, `&`, `~`, `++`, `--`, `()`, `[]`, and `$` are postfix. For example:
142+
143+
``` cpp title="Using postfix operators"
144+
// Cpp1 examples, from cppfront's own source code:
145+
// address = &(*tokens)[pos + num];
146+
// is_void = *(*u)->identifier == "void";
147+
// Cpp2 equivalents:
148+
address = tokens*[pos + num]&;
149+
is_void = u**.identifier* == "void";
150+
```
151+
152+
Postfix notation lets the code read fluidly left-to-right, in the same order in which the operators will be applied, and lets declaration syntax be consistent with usage syntax. For more details, see [Design note: Postfix operators](https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-operators).
153+
154+
> Note: The function call syntax `f(x)` calls a namespace-scope function, or a function object, named `f`. The function call syntax `x.f()` is a unified function call syntax (aka UFCS) that calls a type-scope function in the type of `x` if available, otherwise calls the same as `f(x)`. For details, see [Design note: UFCS](https://github.com/hsutter/cppfront/wiki/Design-note%3A-UFCS).
155+
156+
| Unary operator | Cpp2 example | Cpp1 equivalent |
157+
|---|---|---|
158+
| `#!cpp .` | `#!cpp obj.f()` | `#!cpp obj.f()` |
159+
| `#!cpp *` | `#!cpp pobj*.f()` | `#!cpp (*pobj).f()` or `#!cpp pobj->f()` |
160+
| `#!cpp &` | `#!cpp obj&` | `#!cpp &obj` |
161+
| `#!cpp ~` | `#!cpp val~` | `#!cpp ~val` |
162+
| `#!cpp ++` | `#!cpp iter++` | `#!cpp ++iter` |
163+
| `#!cpp --` | `#!cpp iter--` | `#!cpp --iter` |
164+
| `(` `)` | `#!cpp f( 1, 2, 3)` | `#!cpp f( 1, 2, 3)` |
165+
| `[` `]` | `#!cpp vec[123]` | `#!cpp vec[123]` |
166+
| `$` | `val$` | _reflection — no Cpp1 equivalent yet_ |
167+
168+
> Because `++` and `--` always have in-place update semantics, we never need to remember "use prefix `++`/`--` unless you need a copy of the old value." If you do need a copy of the old value, just take the copy before calling `++`/`--`.
169+
170+
Unary suffix operators must not be preceded by whitespace. When `*`, `&`, and `~` are used as binary operators they must be preceded by whitespace. For example:
171+
172+
| Unary postfix operators that<br>are also binary operators | Cpp2 example | Cpp1 equivalent |
173+
|---|---|---|
174+
| `#!cpp *` | `#!cpp pobj* * 42` | `#!cpp (*pobj)*42` |
175+
| `#!cpp &` | `#!cpp obj& & mask` <p> (note: allowed in unsafe code only) | `#!cpp &obj & mask` |
176+
| `#!cpp ~` | `#!cpp ~val ~ bitcomplement` | `#!cpp val~ ~ bitcomplement` |
177+
178+
For more details, see [Design note: Postfix unary operators vs binary operators](https://github.com/hsutter/cppfront/wiki/Design-note%3A-Postfix-unary-operators-vs-binary-operators).
179+
180+
181+
### <a id="binary-operators"></a> Binary operators
182+
183+
Binary operators are the same as in Cpp1. From highest to lowest precedence:
184+
185+
| Binary operators grouped by precedence |
186+
|---|
187+
| `*`, `/`, `%` |
188+
| `+`, `-` |
189+
| `<<`, `>>` |
190+
| `<=>` |
191+
| `<`, `>`, `<=`, `>=` |
192+
| `==`, `!=` |
193+
| `&` |
194+
| `^` |
195+
| `|` |
196+
| `&&` |
197+
| `||` |
198+
| `=` and compound assignment |
199+
200+
201+
[^u8using]: Or `123.cpp2::u8()` if you aren't `using` the namespace or that specific name.

Diff for: docs/cpp2/contracts.md

+125
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,125 @@
1+
2+
# Contracts
3+
4+
## Overview
5+
6+
Cpp2 currently supports three kinds of contracts:
7+
8+
- **Preconditions and postconditions.** A function declaration can include `pre(condition)` and `post(condition)` before the `= /* function body */`. Before entering the function body, preconditions are fully evaluated and postconditions are captured (and performs their captures, if any). Immediately before exiting the function body via a normal return, postconditions are evaluated. If the function exits via an exception, postconditions are not evaluated.
9+
10+
- **Assertions.** Inside a function body, writing `assert(condition)` assertion statements. Assertions are evaluated when control flow passes through them.
11+
12+
Notes:
13+
14+
- `condition` is an expression that evaluates to `#!cpp true` or `#!cpp false`.
15+
16+
- Optionally, `condition` may be followed by `, "message"`, a message to include if a violation occurs. For example, `pre(condition, "message")`.
17+
18+
- Optionally, a `<Group>` can be written inside `<` `>` angle brackets immediately before the `(`, to designate that this test is part of the [contract group](#contract-groups) named `Group`. If a violation occurs, `Group.report_violation()` will be called. For example, `pre<Group>(condition)`.
19+
20+
For example:
21+
22+
``` cpp title="Precondition and postcondition examples" hl_lines="2 3"
23+
insert_at: (container, where: int, val: int)
24+
pre<Bounds>( 0 <= where <= vec.ssize(), "position (where)$ is outside 'val'" )
25+
post ( container.ssize() == container.ssize()$ + 1 )
26+
= {
27+
_ = container.insert( container.begin()+where, val );
28+
}
29+
```
30+
31+
In this example:
32+
33+
- The `$` captures are performed before entering the function.
34+
35+
- The precondition is part of the `Bounds` safety contract group and is checked before entering the function. If the check fails, say because `where` is `#!cpp -1`, then `#!cpp cpp2::Bounds.report_violation("position -1 is outside 'val'")` is called.
36+
37+
- The postcondition is part of the `Default` safety contract group. If the check fails, then `#!cpp cpp2::Default.report_violation()` is called.
38+
39+
40+
## <a id="contract-groups"></a> Contract groups
41+
42+
Contract groups are useful to enable or disable or [set custom handlers](#violation-handlers) independently for different groups of contracts. A contract group `G` is just the name of an object that can be called with `G.report_violation()` and `G.report_violation(message)`, where `message` is a `* const char` C-style text string.
43+
44+
You can create new contract groups just by creating new objects that have a `.report_violation` function. The object's name is the contract group's name. The object can be at any scope: local, global, or heap.
45+
46+
For example, here are some ways to use contract groups, for convenience using [`cpp2::contract_group`](#violation_handlers) which is a convenient group type:
47+
48+
``` cpp title="Using contract groups" hl_lines="1 4 6 10-12"
49+
GroupA: cpp2::contract_group = (); // a global group
50+
51+
func: () = {
52+
GroupB: cpp2::contract_group = (); // a local group
53+
54+
GroupC := new<cpp2::contract_group>(); // a dynamically allocated group
55+
56+
// ...
57+
58+
assert<GroupA >( some && condition );
59+
assert<GroupB >( another && condition );
60+
assert<GroupC*>( another && condition );
61+
}
62+
```
63+
64+
You can make all the objects in a class hierarchy into a contract group by having a `.report_violation` function in a base class, and then writing contracts in that hierarchy using `<this>` as desired. This technique used in cppfront's own reflection API:
65+
66+
``` cpp title="Example of using 'this' as a contract group, from cppfront 'reflect.h2'" hl_lines="8 9"
67+
function_declaration: @copyable type =
68+
{
69+
// inherits from a base class that provides '.report_violation'
70+
71+
// ...
72+
73+
add_initializer: (inout this, source: std::string_view)
74+
pre<this> (!has_initializer(), "cannot add an initializer to a function that already has one")
75+
pre<this> (parent_is_type(), "cannot add an initializer to a function that isn't in a type scope")
76+
= { /*...*/ }
77+
78+
// ...
79+
80+
}
81+
```
82+
83+
84+
## <a id="violation-handlers"></a> `cpp2::contract_group`, and customizable violation handling
85+
86+
The contract group object could also provide additional functionality. For example, Cpp2 comes with the `cpp2::contract_group` type which allows installing a customizable handler for each object. Each object can only have one handler at a time, but the handler can change during the course of the program. `contract_group` supports:
87+
88+
- `.set_handler(pfunc)` accepts a pointer to a handler function with signature `#!cpp * (* const char)`.
89+
90+
- `.get_handler()` returns the current handler function pointer, or null if none is installed.
91+
92+
- `.has_handler()` returns whether there is a current handler installed.
93+
94+
- `.enforce(condition, message)` evaluates `condition`, and if it is `false` then calls `.report_violation(message)`.
95+
96+
Cpp2 comes with five predefined `contract group` global objects in namespace `cpp2`:
97+
98+
- `Default`, which is used as the default contract group for contracts that don't specify a group.
99+
100+
- `Type` for type safety checks.
101+
102+
- `Bounds` for bounds safety checks.
103+
104+
- `Null` for null safety checks.
105+
106+
- `Testing` for general test checks.
107+
108+
For these groups, the default handler is `cpp2::report_and_terminate`, which prints information about the violation to `std::cerr` and then calls `std::terminate()`. But you can customize it to do anything you want, including to integrate with any third-party or in-house error reporting system your project is already using. For example:
109+
110+
``` cpp title="Example of customized contract violation handler" hl_lines="2 8-9"
111+
main: () -> int = {
112+
cpp2::Default.set_handler(call_my_framework&);
113+
assert<Default>(false, "this is a test, this is only a test");
114+
std::cout << "done\n";
115+
}
116+
117+
call_my_framework: (msg: * const char) = {
118+
// You can do anything you like here, including arbitrary work
119+
// and integration with your current error reporting libraries
120+
std::cout
121+
<< "sending error to my framework... ["
122+
<< msg << "]\n";
123+
exit(0);
124+
}
125+
```

0 commit comments

Comments
 (0)