Skip to content

Commit

Permalink
[DOC} Language specification tests
Browse files Browse the repository at this point in the history
  • Loading branch information
haxscramper committed Nov 7, 2021
1 parent 180a56d commit 1bfc8a5
Show file tree
Hide file tree
Showing 23 changed files with 841 additions and 5 deletions.
8 changes: 8 additions & 0 deletions tests/lang/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -53,3 +53,11 @@ 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_error.nim` - show compilation error related to the feature
- `t01_feature_name_warning.nim` - show compilation warning related to the feature
15 changes: 10 additions & 5 deletions tests/lang/s01_basics/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,16 @@

Here we have tests for the very simple parts of the language, that we often
would not think to test. Mostly this captures minor trivia around:

- comments
- literals
- if statements
- etc
- if, while and case statements
- code block and scopes
- primitive expressions
- Pure-nim user-defined types, without going into details about interfacing
with C and C++ objects, pragmas and any other complications.

Things that we barely think about -- if it fits better somewhere else put it
there. This is a a place for the things too small, rather than too big and fit
nowhere else.
Tests in this section are mostly used to document how most basic interactions
are done - stuff you would find in almost any regular imperative programming
language. Things that are more nim-specific should be placed in `s02_core` or
other sections.
10 changes: 10 additions & 0 deletions tests/lang/s01_basics/s00_atoms/readme.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
This directory contains specification for the most basic language parts -

- what is an expression
- what is a statement
- what is "compile time"

For a lot of these things it is impossible to demonstrate them without using
concepts from subsequent specification parts, but it was decided to put them
as a first entry in the specification. When more "advanced" entries are used
they should be referenced.
50 changes: 50 additions & 0 deletions tests/lang/s01_basics/s00_atoms/t00_builtins.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
## This test specifies basic operations used in other test.

block builtin_assert:
## `doAssert` command is used throughout the specification to assert
## truhfullness of an expression
doAssert true

doAssert 0 == 0

block built_integer_operations:
## Built-in operations on integer values

## Declare integer variable with initial value of `0`
var value: int = 0

## Assert equality of the variable using `==` operator
doAssert value == 0

## Increment value of the variale using `inc` command
inc value

doAssert value == 1

## Decrement value using `dec` command
dec value

## Value of the variable returned to 0
doAssert value == 0

block assert_type_of_the_expression:
## Nim is a statically typed programming language, which means every
## expression has a type. This can be checked for using `is` operator (or it's
## reverse `isnot`).

## Declare variable of type `int` and check if expression `value` has this
## type.
var value: int = 0

doAssert value is int
doAssert value == 0

block get_type_of_the_expression_explicitly:
## It is possible to get type of the expression explicitly, using `typeof()`
## call. Name of the type can be converted to string using `$` operator.

var value: int = 0

doAssert value is int
doAssert $int == "int"
doAssert $typeof(value) == "int"
169 changes: 169 additions & 0 deletions tests/lang/s01_basics/s00_atoms/t01_statement.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
block sequential_control_flow:
## Multiple statements placed on the same level will be sequentially executed
## unless interrupted by a noreturn statement.

## Statement 1 - declares a variable
var value = 0

## Statement 2 - assign 1 to a variable
value = 1

## Statement 3 - asserts value of the variable is equal to 1
doAssert value == 1

block noreturn_statement:
## noreturn statements allow to affect control flow of the program in
## different ways, depending on the context. Each specific type of the control
## flow-altering statement is more thoroughly discussed in the respective
## sections, this one only provides a higher-level overview of the subject.

block break_statement:
## `break` statement can be used inside of loops - (`for`, `while`) and in
## resence of surrounding blocks.

block break_unnamed_block:
var value = 0
block:
value = 1
break
value = 2

## Only single increment took place - `break` prevented second increment
## from being executed.
doAssert value == 1

block break_named_block:
var value = 0
block name_1:
value = 1
block name_2:
value = 2
break name_1
value = 3
value = 4

## `break name_1` prevented third and fourth assignment from being executed.
doAssert value == 2

block break_while_loop:
## `break` in the `while` loop immediately stops loop execution. For more
## details and interactions see tests for a while statements.
var value = 0
while true:
## Break in the `while` loop terminates it's execution.
break
value = 1

doAssert value == 0

block break_for_loop:
## Breka in the `for` loop operates identically to the `while` case - when
## `break` is reached loop body execution is stopped. For more details see
## specification on iterators.

var value = 0
for i in 0 .. 10:
break
value = 2

doAssert value == 2

block continue_statement:
## `continue` statement can be used in the `while` and `for` loops to skip
## execution of the current loop.

block continue_in_while:
var value = 0
var cond = true

while cond:
## First statement in the loop is executed.
cond = false

## Upon reaching `continue` control flow is transferred to the next
## iteration.
continue

## Assignment to value is never reached.
value = 1

doAssert value == 0

block continue_in_for:
## `continue` handling in the `for` loop is also identical to the `while`
## loop - when reached, it transfers control to the next iteration. For
## more details see specification for the iteratrors.
var preContinue = 0
var postContinue = 0

for i in 0 .. 4:
## Statement before `continue` is executed
preContinue = preContinue + i
continue
postContinue = 9

## Statement placed after continue is never reached
doAssert postContinue == 0

## Statement placed before `continue` is executed on every loop iteration
doAssert preContinue == 0 + 1 + 2 + 3 + 4


block return_statement:
## `return` statement can be used in procedure or macro declaration bodies.
## When reached, it immediately trasnfers control flow outside of the
## function body. `return` can also be used to set resulting value of a
## procedure or macros - this functionality is covered in the respective
## sections.

var value = 0

value = 1

proc execReturn() =
value = 2
## When `return` is reached, control flow is immediately transferred out
## of the procedure body
return
value = 3

execReturn()

doAssert value == 2

block raise_statement:
## `raise` statement can be used inside of a procedure body or macro to
## create an exception. Concrete details about exceptions, their types and
## handling can be seen in the respective section of the specification.

var value = 0
proc raiseInside() =
value = 1

## Specific type of the exception is not important in this case -
## `ValueError` would not be any different from `OSError` and alike
raise newException(ValueError, "")
value = 2

try:
## When exception is raised it propagates through all function talls (if
## any) until it reaches topmost level (main module from which the first
## function was called) or a `try` statement. For particular details on
## how exceptions affect control flow see respective part of the
## specification. In this case `try` was needed so subsequent `doAssert`
## would be executed correctly.
raiseInside()

except:
discard

doAssert value == 1

block noreturn_annotation:
## Another type of a noreturn statement is a `quit()` procedure - it
## immediatelly terminates whole execution of the program once called.

quit()

## This statement will never be reached because `quit()` was called before.
doAssert false
100 changes: 100 additions & 0 deletions tests/lang/s01_basics/s00_atoms/t02_expression.nim
Original file line number Diff line number Diff line change
@@ -0,0 +1,100 @@
## Basic expressions. This section explains and tests basic expressions -
## without using `if/when/case` expressions, procedure calls and so on.



block basic_expression:
## Any literal is an expression. Concrete type of the expression depends on
## the type of literal used.

## String literal is an expression of type `string`
doAssert "literal" is string

## Standalone integer literal is an expression of type `int`
doAssert 12 is int

## Floating point value literal is an expression of type `float`
doAssert 3.14 is float

## It is posssible to explicitly specify type of the numeric literal (integer
## or float) using suffix -

## Literal of type "unsigned 8-bit integer"
doAssert 1'u8 is uint8

## "signed 8-bit integer"
doAssert 1'i8 is int8

## Other types of integer literals include `16`, `32` and `64`-bit integers.

doAssert 1'u16 is uint16
doAssert 1'i16 is int16

doAssert 1'u32 is uint32
doAssert 1'i32 is int32

doAssert 1'u64 is uint64
doassert 1'i64 is int64

block block_expressions:
doAssert(
block:
## Block expression might contain multiple statements, including comments
discard
## Value of the last expression in block will be used as a resulting value
## in the whole expression.
true
)

doAssert(
block:
block:
block:
## It is possible to nest block expressions when needed
true
)


## It is also possible to put multiple preceding statements on a single line
## using semicolon (`;`) as a separator.

var value = 0

## This expression allows to implement pre-increment action
doAssert value == 0
doAssert ((inc value; value)) == 1 # QUESTION why double parens are necessary?
doAssert value == 1

## This one is similar, but does a post-increment
doAssert value == 1
doAssert ((let tmp = value; inc value; tmp)) == 1
doAssert value == 2


block statements_as_expressions:
## It is possible to use `if`, `case`, `try` statements as expressions.

## `if` can be used as inline expressions. For more examples on this see
## specification for if statement.
doAssert(if 12 == 12: true else: false)
doAssert(if 12 == 13: true elif 12 == 12: true else: false)

## Case statement cannot be used as a single-line expression, but it is still
## possible to use it in any other form. For more examples and specific rules
## on the case expression see specification for case statement.
let vcase = case range[0..2](0):
of 0: 13
of 1: 14
of 2: 15

doAssert vcase == 13

## `try` can be used as a single-line expression as well. For more examples on
## and specific rules see specification for exception handling.
let vtry = try:
raise (ref OSError)()

except:
12

doAssert vcase == 12
Loading

0 comments on commit 1bfc8a5

Please sign in to comment.