Skip to content

Commit 4ad7d5b

Browse files
authored
Revise Example Metadata User Guide (#726)
* Add small improvements * Add new template * add new templates and options * add new template and option * Support passing of command-line arguments * add support for multi-file examples
1 parent 4d503b4 commit 4ad7d5b

File tree

2 files changed

+210
-18
lines changed

2 files changed

+210
-18
lines changed

tools/ExampleExtractor/ExampleAnnotationGrammar.g4

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ annotation_directive
1818
| infer_output
1919
| expected_exception
2020
| additional_files
21+
| extern_alias_support
22+
| execution_arguments
2123
;
2224

2325
JSON_string_value
@@ -31,9 +33,15 @@ template
3133
;
3234
3335
template_name
34-
: '"standalone-console"' // actually, a JSON_string_value with this content
35-
| '"standalone-lib"' // actually, a JSON_string_value with this content
36-
| '"code-in-main"' // actually, a JSON_string_value with this content
36+
: '"code-in-class-lib"' // actually, a JSON_string_value with this content
37+
| '"code-in-class-lib-without-using"' // actually, a JSON_string_value with this content
38+
| '"code-in-main"' // actually, a JSON_string_value with this content
39+
| '"code-in-main-without-using"' // actually, a JSON_string_value with this content
40+
| '"code-in-partial-class"' // actually, a JSON_string_value with this content
41+
| '"extern-lib"' // actually, a JSON_string_value with this content
42+
| '"standalone-console"' // actually, a JSON_string_value with this content
43+
| '"standalone-lib"' // actually, a JSON_string_value with this content
44+
| '"standalone-lib-without-using"' // actually, a JSON_string_value with this content
3745
;
3846
3947
name
@@ -97,6 +105,18 @@ additional_files
97105
: 'additionalFiles' ':' '[' filename (',' filename)* ']'
98106
;
99107
108+
extern_alias_support
109+
: 'project' ':' filename
110+
;
111+
112+
execution_arguments
113+
: 'executionArgs' ':' '[' cmdlinearg (',' cmdlinearg)* ']'
114+
;
115+
116+
cmdlinearg
117+
: JSON_string_value
118+
;
119+
100120
filename
101121
: JSON_string_value
102122
;

tools/ExampleExtractor/ExtractorAndTesterUsersGuide.md

Lines changed: 187 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,12 @@
1313
- [Expected Runtime Output](#expected-runtime-output)
1414
- [Expected Exception](#expected-exception)
1515
- [Including Support Files](#including-support-files)
16+
- [Supporting External Aliases](#supporting-external-aliases)
17+
- [Passing Command-Line Arguments](#passing-command-line-arguments)
1618
- [Other Information](#other-information)
1719
- [Unsafe Code](#unsafe-code)
1820
- [Examples Containing Pseudo-Code](#examples-containing-pseudo-code)
21+
- [Examples Involving Multiple Files](#examples-involving-multiple-files)
1922
- [Using Chevron-Quotes for Emphasis](#using-chevron-quotes-for-emphasis)
2023
- [Tips for Creating New Testable Examples](#tips-for-creating-new-testable-examples)
2124

@@ -45,8 +48,11 @@ annotation_directive
4548
| ignored_warnings
4649
| expected_output
4750
| infer_output
51+
| ignore_output
4852
| expected_exception
4953
| additional_files
54+
| extern_alias_support
55+
| execution_arguments
5056
;
5157
```
5258

@@ -80,27 +86,33 @@ In this case, the *example_annotation* is preceded by `> ` to match the example
8086

8187
### Templates
8288

89+
#### General
90+
8391
An annotation’s *template* is used to select certain compiler options, and to provide supporting machinery, as needed. This *annotation_directive* is required.
8492

8593
```ANTLR
8694
template
8795
: 'template' ':' template_name
8896
;
8997
template_name
90-
: '"code-in-class-lib"' // actually, a JSON_string_value with this content
91-
| '"code-in-class-lib-without-using"' // actually, a JSON_string_value with this content
92-
| '"code-in-main"' // actually, a JSON_string_value with this content
93-
| '"code-in-main-without-using"' // actually, a JSON_string_value with this content
94-
| '"standalone-console"' // actually, a JSON_string_value with this content
98+
: '"code-in-class-lib"' // actually, a JSON_string_value with this content
99+
| '"code-in-class-lib-without-using"' // actually, a JSON_string_value with this content
100+
| '"code-in-main"' // actually, a JSON_string_value with this content
101+
| '"code-in-main-without-using"' // actually, a JSON_string_value with this content
102+
| '"code-in-partial-class"' // actually, a JSON_string_value with this content
103+
| '"extern-lib"' // actually, a JSON_string_value with this content
104+
| '"standalone-console"' // actually, a JSON_string_value with this content
95105
| '"standalone-console-without-using"' // actually, a JSON_string_value with this content
96-
| '"standalone-lib"' // actually, a JSON_string_value with this content
97-
| '"standalone-lib-without-using"' // actually, a JSON_string_value with this content
106+
| '"standalone-lib"' // actually, a JSON_string_value with this content
107+
| '"standalone-lib-without-using"' // actually, a JSON_string_value with this content
98108
;
99109
```
100110

101111
The unsuffixed and suffixed versions are identical, *except* that the unsuffixed ones have using directioves for all namespaces used by examples, while the suffixed ones do not. The unsuffixed versions are used by those few examples that begin with `#undef` or `#define`, which *must* precede using directives, and which might then have explicit using directives.
102112

103-
The template `standalone-console` indicates that the example is an application. For example:
113+
#### standalone-console
114+
115+
This template indicates that the example is an application. For example:
104116

105117
````
106118
> <!-- Example: {template:"standalone-console", …} -->
@@ -115,7 +127,9 @@ The template `standalone-console` indicates that the example is an application.
115127
> ```
116128
````
117129

118-
The template `standalone-lib` indicates that the example is a class library. For example:
130+
#### standalone-lib
131+
132+
This template indicates that the example is a class library. For example:
119133

120134
````
121135
> <!-- Example: {template:"standalone-lib", … } -->
@@ -130,7 +144,9 @@ The template `standalone-lib` indicates that the example is a class library. For
130144
> ```
131145
````
132146

133-
The template `code-in-main` indicates that the example needs to be wrapped inside an entry-point method inside a class. For example, the example:
147+
#### code-in-main
148+
149+
This template indicates that the example needs to be wrapped inside an entry-point method inside a class. For example, the example:
134150

135151
````
136152
> <!-- Example: {template:"code-in-main", … } -->
@@ -163,7 +179,9 @@ class Program
163179
}
164180
````
165181

166-
The template `code-in-class-lib` indicates that the example needs to be wrapped inside an entry-point method inside a class. For example, the example:
182+
#### code-in-class-lib
183+
184+
This template indicates that the example needs to be wrapped inside an entry-point method inside a class. For example, the example:
167185

168186
````
169187
> <!-- Example: {template:"code-in-class-lib", ..."} -->
@@ -199,6 +217,73 @@ class Class1
199217
}
200218
````
201219

220+
#### code-in-partial-class
221+
222+
This template indicates that the example is part of a multifile application. For example:
223+
224+
````
225+
> <!-- Example: {template:"code-in-partial-class", name:"...", additionalFiles:["Caller.cs"], ...} -->
226+
> ```csharp
227+
> static D[] F()
228+
> {
229+
> ...
230+
> }
231+
> ```
232+
````
233+
234+
which gets transformed into the following:
235+
236+
````
237+
partial class Class1
238+
{
239+
static D[] F()
240+
{
241+
...
242+
}
243+
}
244+
````
245+
246+
The additional file `Caller.cs` contains the following:
247+
248+
````
249+
delegate void D();
250+
251+
partial class Class1
252+
{
253+
static void Main()
254+
{
255+
foreach (D d in F())
256+
{
257+
d();
258+
}
259+
}
260+
}
261+
````
262+
263+
We use this to supplement the example.
264+
265+
#### extern-lib
266+
267+
This template is used to create and map to one or more external aliases by using the `project` *annotation_directive*. For example:
268+
269+
````
270+
> <!-- Example: {template:"extern-lib", name:"ExternAliasDirectives", project:"ExampleProject"} -->
271+
> ```csharp
272+
> extern alias X;
273+
> extern alias Y;
274+
>
275+
> class Test
276+
> {
277+
> X::N.A a;
278+
> X::N.B b1;
279+
> Y::N.B b2;
280+
> Y::N.C c;
281+
> }
282+
> ```
283+
````
284+
285+
The template causes the example code to be compiled without change, along with definition of, and mapping to, the necessary support files for the referenced external aliases, `X` and `Y` via the file `ExampleProject.csproj` in the `extern-lib` template folder.
286+
202287
### Example Names
203288

204289
An annotation’s *name* is the name of the resulting test file directory, **which must be unique across the whole C# spec**. This *annotation_directive* is required. *name* should be a valid C# idenifier.
@@ -428,7 +513,9 @@ Here’s an *example_annotation* showing both expected and ignored warnings:
428513

429514
### Expected Runtime Output
430515

431-
During execution, some test applications are expected to write one or more lines of output to the console.
516+
During execution, some test applications to write one or more lines of output to the console.
517+
518+
> **The tool trims all whitespace from the end of each output string *before* comparing it against any expected or console-block string. As such, make sure an example does *not* generate output lines containing trailing whitespace.**
432519
433520
**Scenario #1:**
434521

@@ -511,6 +598,15 @@ Consider the following example, which writes two lines to the console:
511598
> ```
512599
````
513600

601+
**Scenario #3:**
602+
603+
In those cases in which the output is nondeterministic, we can ignore that output by using the following *annotation_directive*, which is optional.
604+
605+
```ANTLR
606+
ignore_output
607+
: 'ignoreOutput' ':' ('true' | 'false')
608+
```
609+
514610
### Expected Exception
515611

516612
An expected exception can be identified and checked for. This *annotation_directive* is optional.
@@ -552,7 +648,7 @@ Consider the following example:
552648

553649
### Including Support Files
554650

555-
When an example relies on external support information (such as a type declaration or document-comment include file), one or more files containing that information can be copied to the output directory from the `additional-files` directory within the `template` directory. The *annotation_directive* `additionalFiles` achieves this, and is optional.
651+
When an example relies on external support information (such as a type declaration, a document-comment include file, or an extension method), one or more files containing that information can be copied to the output directory from the `additional-files` directory within the `template` directory. The *annotation_directive* `additionalFiles` achieves this, and is optional.
556652

557653
```ANTLR
558654
additional_files
@@ -592,6 +688,36 @@ namespace Acme
592688
}
593689
````
594690

691+
Regarding extension methods, these are all defined in the file Extensions.cs in the additional-files folder.
692+
693+
### Supporting External Aliases
694+
695+
```ANTLR
696+
extern_alias_support
697+
: 'project' ':' filename
698+
;
699+
filename
700+
: JSON_string_value
701+
;
702+
```
703+
704+
This *annotation_directive* supports the template [`extern-lib`](#extern-lib)).
705+
706+
### Passing Command-Line Arguments
707+
708+
```ANTLR
709+
execution_arguments
710+
: 'executionArgs' ':' '[' cmdlinearg (',' cmdlinearg)* ']'
711+
;
712+
cmdlinearg
713+
: JSON_string_value
714+
;
715+
```
716+
717+
Each *cmdlinearg* corresponds to a command-line argument to be passed to the program's entry point at execution, in the order specified, where the first occurence is array element 0.
718+
719+
This *annotation_directive* supports all templates that create an executable.
720+
595721
## Other Information
596722

597723
### Unsafe Code
@@ -620,6 +746,52 @@ Here’s an example:
620746
> «statement»
621747
> ```
622748
749+
### Examples Involving Multiple Files
750+
751+
Examples containing multiple source files in a single project are supported.
752+
753+
Although the example is written as a single markdown code block, line-oriented comments of the form `// File `*filename* are used to delineate the source files. For example,
754+
755+
````
756+
> <!-- Example: {template:"standalone-lib", name:"ConditionalMethods3"} -->
757+
> ```csharp
758+
> // File Class1.cs:
759+
> using System.Diagnostics;
760+
> class Class1
761+
> {
762+
> [Conditional("DEBUG")]
763+
> public static void F()
764+
> {
765+
> Console.WriteLine("Executed Class1.F");
766+
> }
767+
> }
768+
>
769+
> // File Class2.cs:
770+
> #define DEBUG
771+
> class Class2
772+
> {
773+
> public static void G()
774+
> {
775+
> Class1.F(); // F is called
776+
> }
777+
> }
778+
>
779+
> // File Class3.cs:
780+
> #undef DEBUG
781+
> class Class3
782+
> {
783+
> public static void H()
784+
> {
785+
> Class1.F(); // F is not called
786+
> }
787+
> }
788+
> ```
789+
````
790+
791+
From this code block, the extractor produces four files: Library.cs (based on the template `standalone-lib`), and Class1.cs, Class2.cs, and Class3.cs that contain the text for the corresponding source file (excluding the line-oriented comment delimiter).
792+
793+
As the three supporting files are created without a template, no using directives are implicitly available. As such, file Class1.cs must have an explicit one.
794+
623795
### Using Chevron-Quotes for Emphasis
624796
625797
In the Expressions chapter, we use «…» notation for emphasis, as follows:
@@ -681,7 +853,7 @@ If the runtime behavior is undefined, and the annotation is incomplete, use
681853
<!-- Undefined$Example: { … } -->
682854
````
683855
684-
If the example involves multiple source files, use
856+
If the example involves multiple source files in multiple projects, use
685857
````
686-
<!-- RequiresSeparateFiles$Example: { … } -->
858+
<!-- RequiresSeparateProjects$Example: { … } -->
687859
````

0 commit comments

Comments
 (0)