Skip to content

Commit

Permalink
[DOC] Update toplevel spec readme
Browse files Browse the repository at this point in the history
  • Loading branch information
haxscramper committed Nov 14, 2021
1 parent ac8d8dc commit 4206347
Show file tree
Hide file tree
Showing 4 changed files with 125 additions and 87 deletions.
1 change: 0 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -114,4 +114,3 @@ nimdoc.out.css
# For anyone who wants to make a workspace out of nimskull repo
*.code-workspace
.vscode
tests/**/*.nim.bin
67 changes: 0 additions & 67 deletions tests/lang/README.md

This file was deleted.

111 changes: 111 additions & 0 deletions tests/lang/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,111 @@
# Language Specification Tests

Contained within are a series of tests which ensure the language behaves exactly as documented. You can consider it to be a form of documentation in itself.

## Organization

Specification is structured and written using bottom-up approach - first we
specify the most fundamental language elements, such as string and integer
literals, variables. Then we add scopes, control flow-altering constructs
and so on. When new language construct is added, it first is described
separately, and then, if needed, revised again to account for preexisting
language features. Separate language constructs should be placed in
different sections or files, but "revisions" can be exemplified in the same
test file.

You might think of specification as an aid to help you to write an own
implementation of nim, or support a new backend. First you implement the
most basic language features, then you progressively iterate them to
correctly match their behavior with everything that has been added prior to
that.

Example of how decision about file structuring is made - we need document
implementation of the iterators - they can return values, overload on
arguments, their behavior can be altered using keywords such as `break`,
`continue` and `yield`. This is already enough for us to decide that this
is not a "basic" feature, and formulate the prerequisites that language
implementation must have before implementing iterators.

1. Language must support overloading, which must've been tested in the
"procedures" section.
2. `break` and `continue` must be at least recognized by the parser - their
behavior might be different inside of an iterator body, so their
behavior on `while`/`block` and so on is only important for the sake of
consistency (you can *expect* `break` to work with iterators the same
way it does with `while`)

When it comes to writing a test for the iterator itself we first start with
the most basic iterator that does not accept any arguments, and can only
`yield` values. We check if order of execution for statements is correct,
and then `yield` does really return the same value. Iterator must also
preserve it's state between execution transfers - we test it too.

Then we got to check how iterator implements `break` and `continue`, then
overloading and so on.

Different language constructs should be specified and tested in the same
order - first you imagine adding new feature to the language, specify it's
core properties (`yield`, control transfer, state preservation), then
expand the definition by providing a specification for interactions with
other language constructs (`break`, `continue`, `defer`).


## Contributing tests

To add new tests please use following template

```nim
discard """
description: '''
Description of the test itself. Brief list of checks
'''
"""
## Language feature documentation.
block example1:
# ...
```

Please note that it is strongly encouraged to comment the tests as much as possible; the main objective is not simply *"list all possible combinations of all features"*; the objective, is instead, to provide a ***literate executable specification*** of the language.

## Error tests & specifications

It is also necessary to document compilation and runtime errors within, preferably with examples on how to fix the particular issue.

For error reporting you can use following template:


```nim
discard """
description: '''
Test description
'''
errormsg: '''
Actual error message
'''
"""
## Detailed! explanation for the error cause and possible solutions to it.
block working_example:
# One or more examples of working code
block failing_example:
# Example of the failing code
```


## File naming

- `t01_feature_name.nim` - start file name with number to explicitly order features.
- `t01_feature_name_run_fail.nim` - show example of the runtime failure
- `t01_feature_name_comp_fail.nim` - show compilation error related to the feature
- `t01_feature_name_warning.nim` - show compilation warning related to the feature
33 changes: 14 additions & 19 deletions tests/lang/s02_core/s03_inline_iterators/t02_inline_iterators.nim
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,13 @@ transfer bettween body of the iterator and main loop.
"""


##[
An iterator is similar to a procedure, except that it can be called in
the context of a `for` loop. Iterators provide a way to specify the
iteration over an abstract type. The yield statement in the called
iterator plays a key role in the execution of a for loop. Whenever
a yield statement is reached, the data is bound to the for loop
variables and control continues in the body of the for loop. The
iterator's local variables and execution state are automatically
saved between calls.
]##
## An iterator is similar to a procedure, except that it can be called in
## the context of a `for` loop. Iterators provide a way to specify the
## iteration over an abstract type. The yield statement in the called
## iterator plays a key role in the execution of a for loop. Whenever a
## yield statement is reached, the data is bound to the for loop variables
## and control continues in the body of the for loop. The iterator's local
## variables and execution state are automatically saved between calls.

block just_yield:
iterator yieldExample(): int =
Expand All @@ -36,7 +31,7 @@ block just_yield:
block order_assertion_example:
var values: seq[string]

iterator orderExample(): int =
iterator orderExample(): int =
## Iterators can access variables outside of the loop just like regular
## procedures.
values.add "started iterator"
Expand All @@ -57,7 +52,7 @@ block order_assertion_example:
]

block iterator_state_preservation:
## When an iterator is executed, its whole state is preserved,
## When an iterator is executed, its whole state is preserved,
## even when control flow is transferred to the `for` loop body.
var values: seq[string]

Expand All @@ -82,8 +77,8 @@ block iterator_state_preservation:
"after yield"
]

## As you can see, the list of values contains the result of the first
## yield, the original state, then second yield and then the value of the changed
## As you can see, the list of values contains the result of the first
## yield, the original state, then second yield and then the value of the changed
## state; this was despite changing the state before the second yield, but adding
## it after the second yield.

Expand All @@ -102,7 +97,7 @@ block iterator_and_break:
values.add "before 2"
yield 2

## If `break` is called while result of the `yield 2` is being
## If `break` is called while result of the `yield 2` is being
## processed then this statement won't be executed.
values.add "after 2"

Expand All @@ -121,7 +116,7 @@ block iterator_and_break:

block break_try_finally:
## If an iterator maintains an internal state that has to be 'cleaned' up
## `try: ... finally:` expressions can be used to allow resources to be
## `try: ... finally:` expressions can be used to allow resources to be
## handled even if a `break` call is made during the `try` body.

var values: seq[string]
Expand All @@ -131,7 +126,7 @@ block iterator_and_break:
try:
values.add "before 1"
yield 1
## If break is called, control flow won't return to this part
## If break is called, control flow won't return to this part
## of the code and it will not be executed
values.add "after 1"

Expand Down

0 comments on commit 4206347

Please sign in to comment.