# Technická specifikace jazyka BASIX

**Stav dokumentu:** Živý dokument, průběžně doplňovaný.
**Cílová platforma:** BASIX je kompilovaný jazyk — zdrojový kód se překládá do C++.
**Implementace kompilátoru:** Python.
**Podporovaný C++ toolchain:** GCC nebo Clang. Generovaný kód využívá
rozšíření `__int128`, které oba tyto kompilátory poskytují jako nestandardní,
ale běžně dostupný typ. MSVC (`cl.exe`) **není podporovaným cílem**, protože
`__int128` nepodporuje.

---

## Obsah

1. [Přehled](#1-přehled)
2. [Datové typy](#2-datové-typy)
   - [2.6 Priorita a asociativita operátorů](#26-priorita-a-asociativita-operátorů)
3. [Lexikální pravidla](#3-lexikální-pravidla)
   - [3.3 Syntaxe výrazů](#33-syntaxe-výrazů)
   - [3.4 Explicitní konverze typu](#34-explicitní-konverze-typu)
4. [Příkazy](#4-příkazy)
   - [4.1 Deklarace a inicializace proměnné (`var`)](#41-deklarace-a-inicializace-proměnné-var)
   - [4.2 Přiřazení hodnoty do proměnné (`set`)](#42-přiřazení-hodnoty-do-proměnné-set)
   - [4.3 Složený příkaz s návěštím (`code`) a jeho ukončení (`break`)](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break)
   - [4.4 Cyklus s podmínkou (`while`)](#44-cyklus-s-podmínkou-while)
   - [4.5 Předčasné ukončení a přeskočení iterace (`break`, `continue`)](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue)
   - [4.6 Cyklus s krokováním (`loop`)](#46-cyklus-s-krokováním-loop)
   - [4.7 Cyklus přes pole (`for`)](#47-cyklus-přes-pole-for)
   - [4.8 Cyklus s podmínkou na konci (`dowhile`)](#48-cyklus-s-podmínkou-na-konci-dowhile)
   - [4.9 Podmíněný příkaz (`if`)](#49-podmíněný-příkaz-if)
   - [4.10 Řetězený podmíněný příkaz (`if(...; first)`)](#410-řetězený-podmíněný-příkaz-ifthis-first)
   - [4.11 Vícenásobný podmíněný příkaz (`if(...; every)`)](#411-vícenásobný-podmíněný-příkaz-ifthis-every)
   - [4.12 Postupný podmíněný příkaz (`if(...; dive)`)](#412-postupný-podmíněný-příkaz-ifthis-dive)
5. [Jednorozměrné pole (`array`)](#5-jednorozměrné-pole-array)
   - [5.1 Přehled](#51-přehled)
   - [5.2 Deklarace a inicializace — varianta A (`(array, typ)`, výchozí nuly)](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly)
   - [5.3 Deklarace a inicializace — varianta B (`{hodnoty}`, velikost dle počtu)](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)
   - [5.4 Čtení prvku (`jmeno[index]`)](#54-čtení-prvku-jmenoindex)
   - [5.5 Zápis do prvku (`set(jmeno[index], [výraz])`)](#55-zápis-do-prvku-setjmenoindex-výraz)
   - [5.6 Index mimo meze — saturace](#56-index-mimo-meze--saturace)
   - [5.7 Souhrnný příklad](#57-souhrnný-příklad)
   - [5.8 Zápis celého pole jako čísla, textu nebo kopie jiného pole (`set`)](#58-zápis-celého-pole-jako-čísla-textu-nebo-kopie-jiného-pole-set)
6. [Vícerozměrné pole](#6-vícerozměrné-pole)
   - [6.1 Přehled](#61-přehled)
   - [6.2 Deklarace a inicializace (výchozí nuly)](#62-deklarace-a-inicializace-výchozí-nuly)
   - [6.3 Čtení prvku (`jmeno[vyraz][vyraz]...`)](#63-čtení-prvku-jmenovyrazvyraz)
   - [6.4 Zápis do prvku (`set(jmeno[vyraz][vyraz], [vyraz])`)](#64-zápis-do-prvku-setjmenovyrazvyraz-vyraz)
   - [6.5 Index mimo meze — saturace](#65-index-mimo-meze--saturace)
   - [6.6 Souhrnný příklad](#66-souhrnný-příklad)
   - [6.7 Porovnání polí operátory rovnosti](#67-porovnání-polí-operátory-rovnosti)
   - [6.8 Implicitní konverze mezi poli a mezi polem a skalárem](#68-implicitní-konverze-mezi-poli-a-mezi-polem-a-skalárem)
7. [Příkaz pro výstup (`print`)](#7-příkaz-pro-výstup-print)
   - [7.1 Přehled](#71-přehled)
   - [7.2 Syntaxe](#72-syntaxe)
   - [7.3 Sémantika](#73-sémantika)
   - [7.4 Souhrnný příklad](#74-souhrnný-příklad)
8. [Příkaz pro vstup (`input`)](#8-příkaz-pro-vstup-input)
   - [8.1 Přehled](#81-přehled)
   - [8.2 Syntaxe](#82-syntaxe)
   - [8.3 Sémantika](#83-sémantika)
   - [8.4 Souhrnný příklad](#84-souhrnný-příklad)
9. [Vestavěné funkce `max`/`min`](#9-vestavěné-funkce-maxmin)
   - [9.1 Přehled](#91-přehled)
   - [9.2 Syntaxe](#92-syntaxe)
   - [9.3 Sémantika — skalární podoba (mez typu)](#93-sémantika--skalární-podoba-mez-typu)
   - [9.4 Sémantika — podoba nad polem (poslední rozměr, holé jméno)](#94-sémantika--podoba-nad-polem-poslední-rozměr-holé-jméno)
   - [9.5 Sémantika — podoba nad vícerozměrným polem (konkrétní rozměr)](#95-sémantika--podoba-nad-vícerozměrným-polem-konkrétní-rozměr)
   - [9.6 Sémantika — podoba nad `obj` (holé jméno instance)](#96-sémantika--podoba-nad-obj-holé-jméno-instance)
   - [9.7 Souhrnný příklad](#97-souhrnný-příklad)
10. [Složený datový typ (`obj`)](#10-složený-datový-typ-obj)
    - [10.1 Definice typu (`obj(jmeno) ... end obj`)](#101-definice-typu-objjmeno--end-obj)
    - [10.2 Deklarace proměnné (instance) typu `obj`](#102-deklarace-proměnné-instance-typu-obj)
    - [10.3 Čtení hodnoty člena (`jmeno_instance.jmeno_clenu`)](#103-čtení-hodnoty-člena-jmeno_instancejmeno_clenu)
    - [10.4 Zápis do člena (`set(jmeno_instance.jmeno_clenu, [výraz])`)](#104-zápis-do-člena-setjmeno_instancejmeno_clenu-výraz)
    - [10.5 Výchozí hodnota člena — vyhodnocuje se při každé instanci](#105-výchozí-hodnota-člena--vyhodnocuje-se-při-každé-instanci)
    - [10.6 Jmenný prostor `obj` typů a kolizní pravidla](#106-jmenný-prostor-obj-typů-a-kolizní-pravidla)
    - [10.7 Souhrnný příklad](#107-souhrnný-příklad)
    - [10.8 Konverze mezi `obj` a jinými typy — tiché vynechání](#108-konverze-mezi-obj-a-jinými-typy--tiché-vynechání)
11. [Funkce (`fun`)](#11-funkce-fun)
    - [11.1 Přehled](#111-přehled)
    - [11.2 Definice funkce](#112-definice-funkce)
    - [11.3 Návratová hodnota (`return`)](#113-návratová-hodnota-return)
    - [11.4 Volání funkce](#114-volání-funkce)
    - [11.5 Jmenný prostor funkcí a kolizní pravidla](#115-jmenný-prostor-funkcí-a-kolizní-pravidla)
    - [11.6 Rekurze](#116-rekurze)
    - [11.7 Globální úroveň definic a nezávislost na pořadí](#117-globální-úroveň-definic-a-nezávislost-na-pořadí)
    - [11.8 Volání jako příkaz vs. jako součást výrazu](#118-volání-jako-příkaz-vs-jako-součást-výrazu)

---

## 1. Přehled

BASIX je jednoduchý programovací jazyk s vlastní syntaxí, který se kompiluje
do C++. Jazyk používá dva základní datové typy — `int`, `real` — a definuje
přesná, deterministická pravidla pro chování při přetečení a implicitních
konverzích mezi typy, na rozdíl od C++, kde je chování v těchto případech
často nedefinované nebo závislé na platformě.

Dvě návrhové zásady se táhnou celou specifikací:

1. **Žádná operace ani konverze v BASIXu nesmí vést k nedefinovanému chování
   (UB) jazyka C++**, do kterého se program překládá. Kdekoliv by
   ekvivalentní C++ konstrukce UB měla, BASIX pro ni definuje vlastní,
   deterministické chování — typicky saturací.
2. **Meze hodnot obou typů sdílejí stejnou magnitudu, `2^53`**, zvolenou
   nezávisle na fyzické šířce jejich reprezentace v C++. Magnituda `2^53`
   odpovídá hranici, do které `double` (53bitová mantisa) dokáže přesně
   reprezentovat celá čísla — díky tomu je převod `int → real` vždy
   bezeztrátový. Jediným zdrojem ztráty informace mezi oběma typy je tak
   ořezání desetinné části při převodu `real → int` — viz
   [2.4](#24-implicitní-konverze-mezi-typy).

---

## 2. Datové typy

### 2.1 Základní typy

| Typ | Rozsah hodnot | Reprezentace v C++ | Literál | Účel |
|-------|------------------|---------------------|---------|------|
| `int` | `[-2^53, 2^53]` | `int64_t` | `42`, `-5` | celočíselná aritmetika se znaménkem |
| `real` | `[-2^53, 2^53]` | `double` | `3.14`, `-0.5` | desetinná aritmetika |

Meze v tabulce jsou **inclusive** na obou stranách u obou typů.

Literál smí být uvozen volitelným znaménkem `-` jako součástí svého
vlastního lexikálního zápisu (`-5`, `-0.5`) — nejde o aplikaci
unárního operátoru `-` z [2.6](#26-priorita-a-asociativita-operátorů).
Průkazně to potvrzuje i použití záporných literálů bez obalujících
`[]` ve formě 1 seznamu `{}` u pole
([5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)),
kde operátor (vyžadující dle [3.3](#33-syntaxe-výrazů) vlastní `[]`)
stát nemůže. Unární `-` jako operátor se nadále uplatňuje na
libovolný jiný operand (proměnnou, uzávorkovaný podvýraz, nebo i na
literál znovu, je-li výraz zapsán např. jako `[- -5]`).

**BASIX nezavádí žádný samostatný typ `string`.** „Řetězec" je
čistě jednorozměrné pole ([5](#5-jednorozměrné-pole-array)) typu
`int`, jehož prvky jsou UTF-32 kódové body jednotlivých znaků —
pohodlnější zápis takového pole zavádí řetězcový literál v
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu).
Nejde tedy o novou kategorii hodnot s vlastními pravidly
pravdivosti, konverze či hierarchie z této kapitoly — ty se řídí
beze změny typem `int`.

**Proč meze neodpovídají fyzické šířce typu.** U tradičních pevných
celočíselných typů (např. `int64_t` používaný v mezích svého plného rozsahu)
jsou meze hodnot přímým důsledkem bitové šířky reprezentace. BASIX tento
vztah záměrně rozpojuje: fyzická reprezentace `int` (`int64_t`, 64 bitů) je
širší, než by pro logický rozsah `2^53` bylo nutné (`2^53` by se vešlo i do
o dost užšího typu), ze dvou důvodů:

1. **Bezeztrátové převody mezi typy.** `2^53` je přesně hranice, do které
   `double` dokáže přesně reprezentovat celá čísla (53bitová mantisa).
   Díky tomu je převod `int → real` vždy přesný, bez zaokrouhlování — o
   jakoukoliv větší magnitudu už by tato záruka neplatila.
2. **Mezivýpočet bez přetečení probíhá v odděleném, širším typu.**
   Ochranu proti přetečení mezivýsledku nezajišťuje šířka samotného
   `int64_t`, ale widening operandů i mezivýsledku do `__int128`
   před provedením operace (viz
   [2.3](#23-saturace-přetečení-a-widening)); `int64_t` je zde zvolen jen
   jako přirozené, dostatečně velké trvalé úložiště pro hodnoty v
   mezích `[-2^53, 2^53]`, nezávisle na mechanismu mezivýpočtu.

### 2.2 Pravdivost

BASIX nemá vlastní typ `bool`. Kdekoliv se hodnota vyhodnocuje jako
pravdivostní platí jednotné pravidlo, shodné pro `int` i `real`:

- hodnota `0` (resp. `0.0`) → **false**
- jakákoliv jiná hodnota → **true**

### 2.3 Saturace, přetečení a widening

Oba typy používají stejnou strategii — **saturaci** na meze z
[2.1](#21-základní-typy) — lišící se pouze mechanismem výpočtu podle toho,
zda jde o celočíselný, nebo desetinný typ.

**`int`.** Aritmetické operátory (`+`, `-`, `*`, `/`, `%` a unární mínus) se
nikdy nepřekládají na čisté C++ operátory nad `int64_t`. Místo toho se oba
operandy i mezivýsledek rozšíří (widening) na `__int128`, operace se provede
tam, mezivýsledek se porovná s mezemi `[-2^53, 2^53]` a případně se saturuje
před uložením zpět do `int64_t`.

Výsledek `%` u `int` nese znaménko dělence (levého operandu) —
stejná konvence, jakou pro celočíselné `%` používá C++ (truncující
dělení). Např. `-7 % 2 = -1`, `7 % -2 = 1`.

Tento mechanismus je **jednotný pro všechny operátory, bez výjimky**. Důvod
je čistě aritmetický: protože se saturace uplatňuje po každé operaci, každá
hodnota vstupující do další operace je vždy už v mezích `[-2^53, 2^53]`.
Nejnáročnější případ co do velikosti mezivýsledku je násobení dvou
hraničních hodnot: `2^53 × 2^53 = 2^106` — číslo o mnoho řádů menší, než je
kapacita `__int128` (přibližně `±1.7 × 10^38`, tedy `2^127`). Žádná
kombinace operandů u žádného z podporovaných operátorů tedy nemůže widening
krok sama o sobě přetéct.

**Důsledek — žádné speciální případy.** Se symetrickými, inclusive mezemi
neexistuje kombinace operandů, jejíž matematický výsledek by widening do
`__int128` nezachytil běžným porovnáním s mezemi. Negace dolní meze
(`-(-2^53) = 2^53`) i dělení dolní meze číslem `-1` dávají výsledek přesně na
horní mezi, tedy stále v platném rozsahu — nejde o žádnou zvláštní
kombinaci vyžadující samostatné pravidlo.

**Dělení a modulo nulou.** Na rozdíl od C++, kde je celočíselné dělení/modulo
nulou UB, BASIX definuje pro `/` i `%` u obou typů (`int`, `real`) jednotné
pravidlo, které se uplatní **před** samotným výpočtem — u `int` tedy před
widening/saturačním mechanismem popsaným výše, u `real` před vyhodnocením
v `double` (viz níže) — dělení nulou se fakticky neprovede:

- `x / 0` → výsledkem je `x` (beze změny).
- `x % 0` → výsledkem je nulová hodnota cílového typu (`0` pro `int`, `0.0`
  pro `real`).

Tím se BASIX zároveň vyhýbá nutnosti řešit `inf`/`NaN`, které by jinak u
`real` dělení nulou v C++ vznikaly.

U operace se smíšenými typy (`int`/`real`) se toto pravidlo uplatní
až po promoci na `real` dle [2.5](#25-hierarchie-typů-u-binárních-operací) —
jde tedy vždy o výše popsanou `real` variantu pravidla, bez ohledu na
to, že jeden z operandů byl původně `int`.

**`real`.** Aritmetika nad `real` se počítá přímo v `double`, bez widening
kroku: přetečení `double` je v C++ definované chování (výsledkem je
nekonečno), nikoliv UB, a mez saturace `2^53` je o mnoho řádů menší než
maximální reprezentovatelná hodnota `double` (~`1.8 × 10^308`). Mezivýsledek
se tedy vždy spočítá přímo v `double` a poté porovná s mezemi
`[-2^53, 2^53]`; při přetečení výsledek saturuje na `2^53`, při záporném
přetečení na `-2^53`.

Poznámka: díky saturaci uplatňované po každé operaci k přetečení
`double` na `inf` v běžném běhu programu ve skutečnosti nikdy
nedojde — mechanismus je zde popsán jen pro úplnost/robustnost
(a jako doklad, proč by ani teoreticky nevznikalo UB, kdyby k němu
přesto někdy dojít mohlo).

**Modulo (`%`) nad `real`.** Na rozdíl od C++, kde `%` vyžaduje integrální
operandy, BASIX definuje `%` i pro `real` (nenulový dělitel): výsledek
odpovídá C++ `std::fmod` — zbytek po dělení v plovoucí řádové čárce se
znaménkem **dělence**, stejnou konvencí, jakou pro `%` u `int` zavádí
pravidlo výše. Např. `5.3 % 2.0 = 1.3`, `-5.3 % 2.0 = -1.3`.

Saturace zde není potřeba: platí matematická vlastnost `|fmod(a, b)| < |b|`,
a protože dělitel `b` je vždy v mezích `real` (tedy `|b| ≤ 2^53`), je i
výsledek vždy automaticky uvnitř `[-2^53, 2^53]` — stejný typ argumentu,
jaký tato specifikace používá u `int` widening a u `int → real` konverze.

**Literál mimo rozsah saturuje staticky při kompilaci — není to chyba
kompilace.** Literál (celočíselný i desetinný) nikdy nezpůsobí chybu
kompilace kvůli přesahu rozsahu; místo toho se saturuje stejným způsobem
jako běžný runtime výsledek, jen se tak děje už staticky, v době kompilace.

Platí jediné, jednotné pravidlo — literál **vždy** saturuje vůči mezím
svého vlastního **intrinsického typu**: `int`, pokud je zapsán bez
desetinné tečky, `real`, pokud je zapsán s ní (viz [2.1](#21-základní-typy)).
To platí bez ohledu na to, kde přesně se literál v kódu nachází — jako
jediný obsah `[]` u `var(typ, jmeno, [literál])`
(viz [4.1](#41-deklarace-a-inicializace-proměnné-var)), jako holý obsah
explicitní konverze `[typ; literál]` (viz
[3.4](#34-explicitní-konverze-typu)), nebo jako operand uvnitř složitějšího
výrazu (viz [2.6](#26-priorita-a-asociativita-operátorů)). Žádný ze
zvláštních případů zde totiž ve skutečnosti neexistuje: literál se nikdy
nezapisuje "napřímo" mimo `[]` (syntaxe [3.3](#33-syntaxe-výrazů) a
[4.1](#41-deklarace-a-inicializace-proměnné-var) vyžaduje, aby byl vždy
součástí nějakého `výrazu`) — je tedy vždy vyhodnocován stejným, obecným
způsobem.

Případná následná konverze na jiný cílový typ — ať už implicitní dle
[2.4](#24-implicitní-konverze-mezi-typy) při uložení výsledku výrazu do
proměnné, nebo explicitní dle [3.4](#34-explicitní-konverze-typu) — se
uplatní až poté, stejně jako u kteréhokoliv jiného výsledku výrazu. Protože
`int` i `real` sdílí stejnou mez `2^53`, dává toto pravidlo vždy číselně
stejný výsledek, jako by literál saturoval rovnou vůči cílovému typu — obě
meze jsou totožné, liší se jen to, kterým typem prochází mezivýsledek.
Např. `var(int, x, [-99999999999999999999])`: literál nemá desetinnou
tečku, saturuje jako `int` na `-2^53`; typ výrazu (`int`) se shoduje s typem
`x`, žádná další konverze není potřeba, `x` dostane `-2^53`. Obdobně
`var(real, y, [-99999999999999999999])`: stejná saturace na `int` hodnotu
`-2^53`, poté se dle [2.4](#24-implicitní-konverze-mezi-typy) bezeztrátově
převede na `real`, `y` dostane `-2^53.0`.

**Mechanismus výpočtu saturace.** Hodnota literálu (bez ohledu na to, jak
dlouhý je jeho zápis ve zdrojovém kódu) se nejprve vyhodnotí přesně, tj.
jako matematicky exaktní číslo — ne přes zaokrouhlení `double` — a porovná
se s mezemi `[-2^53, 2^53]` stejným způsobem, jaký [2.3](#23-saturace-přetečení-a-widening)
používá u běžné `real` saturace (přímé porovnání s mezí, bez widening kroku
jako u `int`, protože kompilátor pracuje s přesnou hodnotou ze zdrojového
textu, nikoliv s hardwarově omezenou reprezentací). Pokud je hodnota mimo
meze, saturuje se na příslušnou mez. Teprve takto získaná, případně již
saturovaná exaktní hodnota se materializuje do skutečné reprezentace
odpovídající intrinsickému typu literálu — `int64_t` u `int`, `double` u
`real`. Tento mezikrok (dočasné zacházení s hodnotou jako s exaktním číslem
kvůli porovnání s mezí) je čistě implementační detail výpočtu saturace —
**nemění intrinsický typ literálu** pro účely hierarchie popsané výše; na
rozdíl od konverze v [2.4](#24-implicitní-konverze-mezi-typy) se zde
nejedná o přechod mezi `int` a `real`, ale o uložení hodnoty do jejího
vlastního, neměnného intrinsického typu.

### 2.4 Implicitní konverze mezi typy

BASIX povoluje automatickou (implicitní) konverzi mezi `int` a `real`.
Protože oba typy sdílejí stejnou magnitudu meze (`2^53`), je jediným zdrojem
ztráty informace při konverzi ztráta desetinné části — nikdy rozdíl v
rozsahu:

| Z typu → do typu | Pravidlo konverze | Ztrátová? |
|---|---|---|
| `int → real` | hodnota se přenese beze změny (přesně reprezentovatelná, viz [2.1](#21-základní-typy)) | ne, nikdy |
| `real → int` | desetinná část se ořízne (trunc); celočíselná část je vždy již v mezích `int` (oba typy sdílejí mez `2^53`) | jen u desetinné části |

### 2.5 Hierarchie typů u binárních operací

Pokud se aritmetický nebo porovnávací operátor použije nad dvěma operandy různých typů, platí hierarchie:

```
real > int
```

Postup vyhodnocení:

1. Operand typu `int` se zkonvertuje na `real` podle
   [2.4](#24-implicitní-konverze-mezi-typy). Tato promoce je díky sdílené
   magnitudě mezí vždy bezeztrátová.
2. Samotná operace se provede nad oběma operandy převedenými na `real`.
3. **U aritmetických operátorů** se na výsledek uplatní saturace na meze
   výsledného typu ([2.3](#23-saturace-přetečení-a-widening)). **U
   porovnávacích operátorů** se saturace neuplatní — výsledkem je vždy `int`
   hodnota `0`/`1`.

Příklad (aritmetika): `int_hodnota + real_hodnota` → `int_hodnota` se
zkonvertuje na `real` (beze ztráty), operace `+` proběhne nad `real`,
případné přetečení se řeší saturací na meze `real`.

Příklad (porovnání): `[a < b]`, kde `a` je `int` a `b` je `real` → `a` se
zkonvertuje na `real`, porovnání proběhne mezi dvěma `real` hodnotami,
výsledkem je `int` `0` nebo `1`.

**Logické operátory** (`and`, `or`, `not`) hierarchii typů neřeší vůbec —
každý operand se posuzuje samostatně podle pravidla pravdivosti z
[2.2](#22-pravdivost) (bez ohledu na typ), teprve poté se provede logická
operace nad výslednými pravdivostními hodnotami.

**Vyhodnocení `and`/`or` je short-circuit**, stejně jako C++ `&&`/`||`: u
`a and b` se `b` vůbec nevyhodnotí, pokud je `a` už "false" (dle
[2.2](#22-pravdivost)); u `a or b` se `b` vůbec nevyhodnotí, pokud je `a` už
"true".

**Výsledek `and`, `or` i `not` je vždy `int` hodnota `0`/`1`** — analogicky k
porovnávacím operátorům, nikoliv jeden z původních operandů. Typ výsledku je
tedy vždy staticky `int`, nezávisle na typech i hodnotách operandů. Např.
`a and b`, kde `a` je `real` a `b` je `int`, vyhodnotí pravdivost obou
operandů podle 2.2 a vrátí `int` `0` nebo `1` — samotné hodnoty `a`/`b` se do
výsledku nepřenášejí.

**Modulo (`%`) podléhá hierarchii stejně jako ostatní aritmetické operátory,
bez výjimky.** Je definováno pro oba typy (viz
[2.3](#23-saturace-přetečení-a-widening) pro sémantiku `%` nad `real`).
Např. `int_hodnota % real_hodnota` → `int` operand se promuje na `real`
(bezeztrátově), operace proběhne jako `fmod` nad dvěma `real` hodnotami,
výsledek je `real`.

Pokud je výsledek operace následně přiřazen do proměnné jiného typu,
uplatní se navíc konverze dle [2.4](#24-implicitní-konverze-mezi-typy) při
samotném přiřazení — platí jak pro aritmetické výsledky, tak pro výsledky
porovnání/logických operátorů (vždy `int`).

**Porovnání dvou polí.** Hierarchie typů popsaná výše se týká **skalárních**
operandů `==`/`!=`. Použijí-li se `==`/`!=` nad dvěma holými jmény polí
(`array`, jednorozměrné, nebo vícerozměrné), řídí se odlišným, samostatným pravidlem
nezávislým na deklarovaném typu prvků — viz
[6.7](#67-porovnání-polí-operátory-rovnosti).

**Implicitní konverze mezi poli, a mezi polem a skalárem.** Nad rámec
skalární `int ↔ real` konverze popsané výše existuje v BASIXu i obecná
implicitní konverze mezi dvěma poli (jednorozměrnými i vícerozměrnými,
v libovolné kombinaci) a mezi polem a skalárem (`int`/`real`) — mechanismus není
vlastností konkrétního příkazu, ale uplatňuje se v uzavřené množině
míst popsaných v [6.8](#68-implicitní-konverze-mezi-poli-a-mezi-polem-a-skalárem).
Explicitně se nevztahuje na argumenty typu pole/`obj` u
volání funkce ([11.4](#114-volání-funkce)), kde se místo toho vyžaduje
přesná shoda typů.

### 2.6 Priorita a asociativita operátorů

BASIX přejímá prioritu a asociativitu operátorů z C++, omezenou na
podmnožinu operátorů, které BASIX skutečně podporuje (BASIX **nemá** bitové
operátory — viz níže). Řazeno od nejvyšší priority k nejnižší:

| Priorita | Operátory | Asociativita |
|---|---|---|
| 1 (nejvyšší) | unární `-`, `not` | zprava doleva |
| 2 | `*`, `/`, `%` | zleva doprava |
| 3 | binární `+`, `-` | zleva doprava |
| 4 | `<`, `<=`, `>`, `>=` | zleva doprava |
| 5 | `==`, `!=` | zleva doprava |
| 6 | `and` | zleva doprava |
| 7 (nejnižší) | `or` | zleva doprava |

Závorky `()` slouží ke změně přirozeného pořadí vyhodnocení stejně jako v
C++.

Za zmínku stojí, že relační operátory (`<`, `<=`, `>`, `>=`) mají v této
tabulce **vyšší** prioritu než rovnostní (`==`, `!=`) — to je přesná shoda s
C++, nikoliv chyba: např. `a < b == c < d` se vyhodnotí jako
`(a < b) == (c < d)`.

**Bitové operátory BASIX neobsahuje.** Na rozdíl od C++ (`&`, `|`, `^`, `~`,
`<<`, `>>`) BASIX žádnou obdobu bitových operátorů nemá — nejsou tedy ani
součástí tabulky priorit výše.

---

## 3. Lexikální pravidla

Obecné syntaktické konvence, platné napříč celým jazykem.

### 3.1 Oddělování příkazů

BASIX používá **jeden příkaz na řádek** — konec příkazu je určen koncem
řádku; žádný explicitní oddělovač (středník na konci řádku) není potřeba.

### 3.2 Pojmenování identifikátorů

- Povolené znaky: `a`–`z`, `A`–`Z`, `0`–`9`, `_`.
- Název musí **začínat** písmenem nebo podtržítkem — nesmí začínat číslicí.
- Identifikátory jsou **case-sensitive** (`promenna` ≠ `Promenna`).
- BASIX nepodporuje konstanty — všechny hodnoty vytvořené přes `var` jsou
  proměnlivé.

**Identifikátor nesmí být shodný s žádným klíčovým slovem jazyka.**
Platí to jednotně pro jména proměnných, polí, labelů, `obj` typů i
funkcí — pokus o `var(int, var, [5])`, `obj(if) ... end obj` apod. je
chyba při kompilaci.

**Úplný seznam klíčových slov:**

- příkazy a konstrukce s vlastní `(` hned za sebou: `var`, `set`,
  `code`, `while`, `loop`, `for`, `dowhile`, `if`, `case`, `break`,
  `continue`, `obj`, `max`, `min`, `input`, `print`, `fun`, `ret`,
  `par`;
- holá klíčová slova bez vlastní `(`: `end`, `return`, `true`,
  `false`;
- klíčová slova typového popisu: `int`, `real`.

Slova `first`, `every`, `dive` ([4.10](#410-řetězený-podmíněný-příkaz-ifthis-first),
[4.11](#411-vícenásobný-podmíněný-příkaz-ifthis-every),
[4.12](#412-postupný-podmíněný-příkaz-ifthis-dive)) se do tohoto
seznamu záměrně nezařazují: na rozdíl od `true`/`false`, které se
opakovaně vyskytují jako hodnota `case` napříč několika konstrukcemi,
se `first`/`every`/`dive` vyskytují vždy jen na jediném konkrétním
místě — jako druhý argument `if(...; first/every/dive)`. Kdyby
identifikátor nesl jméno `first`, nevznikla by tím žádná syntaktická
nejednoznačnost, protože `first` se jako hodnota výrazu ani jako
identifikátor nikde jinde v jazyce nepoužívá a použít nemůže.

### 3.3 Syntaxe výrazů

**Kdekoli se v kódu používá hodnota výrazu, musí být výraz obklopen
hranatými závorkami `[]`.** Toto pravidlo platí pro výraz jako celek —
nezávisle na tom, zda jde o samotnou proměnnou, literál, nebo složenou
operaci — a nezávisle na tom, kde přesně se hodnota výrazu použije
(přiřazení, podmínka a další místa, jejichž přesná syntaxe bude doplněna
spolu se syntaxí příslušných příkazů).

Toto pravidlo platí pro obecnou pozici `[vyraz]`, jak ji používají
příkazy a konstrukce popsané v hlavní specifikaci (`var`, `set`,
podmínky atd.). Konkrétní, samostatně definované konstrukce mohou
zavádět vlastní syntaxi prvků bez tohoto obalu — takové výjimky jsou
vždy vyjmenované přímo u dané konstrukce, nikoliv implicitní. K datu
psaní tohoto pravidla jde o tato místa:

- přímý číselný a řetězcový literál ve formě 1/2 seznamu
  `{hodnota1, ..., hodnotaN}` u deklarace pole
  ([5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu))
  i u `print({...})` ([7.2](#72-syntaxe));
- holé jméno proměnné (skalární i pole) jako cíl `set(...)`
  ([4.2](#42-přiřazení-hodnoty-do-proměnné-set)) a `input(...)`
  ([8.2](#82-syntaxe));
- holé jméno pole/`obj` instance u `max`/`min`
  ([9](#9-vestavěné-funkce-maxmin));
- holé jméno pole/`obj` jako argument volání funkce a čtvrtá
  varianta `set(cil, jmeno(...))` ([11.4](#114-volání-funkce),
  [11.8](#118-volání-jako-příkaz-vs-jako-součást-výrazu)).

Tento výčet slouží jen jako přehled, kde se výjimka aktuálně
vyskytuje — závazné znění každé výjimky je vždy u příslušné
konstrukce, ne zde.

**Gramatika výrazu.** `výraz` uvnitř `[]` je jedno z následujícího:

- **literál** (viz [2.1](#21-základní-typy)) — celočíselný, nebo desetinný,
- **proměnná** (viz [3.2](#32-pojmenování-identifikátorů)),
- **operace** (unární, nebo binární — viz [2.6](#26-priorita-a-asociativita-operátorů))
  nad operandy, kde je každý operand opět literál, proměnná, anebo (případně
  kulatými závorkami `()` uzávorkovaná) další operace.

Tento výčet je základní, ne uzavřený — konkrétní konstrukce mohou
zavádět vlastní další druhy operandu; takové rozšíření je vždy
vyhlášeno přímo u dané konstrukce, nikoliv implicitní. K datu psaní
tohoto pravidla jde o tato místa:

- **přístup k prvku/členu** — `jmeno[index]` u jednorozměrného pole
  ([5.4](#54-čtení-prvku-jmenoindex)), `jmeno[vyraz]...[vyraz]` u
  vícerozměrného pole ([6.3](#63-čtení-prvku-jmenovyrazvyraz)),
  `jmeno_instance.jmeno_clenu` (případně řetězené) u `obj`
  ([10.3](#103-čtení-hodnoty-člena-jmeno_instancejmeno_clenu));
- **odkaz na pole jako celek** (bez indexu) — jako položka seznamu
  `{...}` ([5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu),
  „tvar 4"), jako argument `print`
  ([7.2](#72-syntaxe)), jako zdroj `set`
  ([5.8](#58-zápis-celého-pole-jako-čísla-textu-nebo-kopie-jiného-pole-set)),
  a jako operand `==`/`!=` ([6.7](#67-porovnání-polí-operátory-rovnosti)) —
  na rozdíl od ostatních položek tohoto výčtu **není** obecně
  použitelné jako operand libovolné jiné operace (`[pole + 1]`
  zůstává neplatné).

Tento výčet slouží jen jako přehled, kde se rozšíření aktuálně
vyskytuje — závazné znění každého z nich je vždy u příslušné
konstrukce, ne zde.

Poslední bod je rekurzivní: díky němu je operandem operace nejen samotný
literál nebo proměnná, ale i libovolně složená podvýraz — právě to
demonstruje `[(a + b) * c]` níže, kde je jeden z operandů `*` sám výsledkem
operace `+`.

Příklady: `[a + b]`, `[a < b]`, `[5]`, `[x]`.

`[]` je čistě vnější, povinný oddělovač celého výrazu na daném místě —
nenahrazuje kulaté závorky `()` z [2.6](#26-priorita-a-asociativita-operátorů),
které se nadále používají pro seskupování (grouping) uvnitř samotného
výrazu, např. `[(a + b) * c]`.

### 3.4 Explicitní konverze typu

Kromě prostého `[výraz]` z [3.3](#33-syntaxe-výrazů) podporuje BASIX i
**explicitní konverzi** výsledku výrazu na zvolený typ, pomocí syntaxe:

```
[typ; výraz]
```

kde `typ` je `int`, nebo `real`. Jde o rozšíření téhož vnějšího oddělovače
`[]` o volitelný prefix `typ;` — obě formy (`[výraz]` i `[typ; výraz]`)
sdílejí stejné hranaté závorky, liší se jen přítomností cíle konverze.

Postup vyhodnocení:

1. `výraz` se vyhodnotí přesně podle pravidel platných pro obyčejný výraz
   v hranatých závorkách — tedy včetně hierarchie typů
   ([2.5](#25-hierarchie-typů-u-binárních-operací)), saturace při přetečení
   ([2.3](#23-saturace-přetečení-a-widening)), pravidla pro dělení nulou
   atd. Výsledkem tohoto kroku je hodnota s vlastním, plně určeným typem
   (`int`, nebo `real`) — zcela nezávisle na tom, že bude v dalším kroku
   explicitně konvertována. Přítomnost `typ;` tedy nijak nemění, jak se
   samotný `výraz` uvnitř `[]` vyhodnocuje (ani intrinsický typ literálů
   dle [2.3](#23-saturace-přetečení-a-widening), bodu o literálech jako
   operandech).
2. Teprve takto získaná hodnota se zkonvertuje na cílový `typ` podle
   pravidel implicitní konverze z [2.4](#24-implicitní-konverze-mezi-typy)
   — tedy `int → real` beze změny hodnoty, `real → int` ořezáním desetinné
   části (trunc). Žádná další saturace zde není potřeba, protože oba typy
   sdílejí stejnou mez `2^53` (viz [1](#1-přehled)).

Příklady:

- `[int; 3.7]` → výraz `3.7` je typu `real`; po explicitní konverzi na
  `int` dá `3` (ořezání desetinné části).
- `[real; 5]` → výraz `5` je typu `int`; po explicitní konverzi na `real`
  dá `5.0` (beze ztráty).
- `[real; a + b]`, kde `a`, `b` jsou `int` → sčítání proběhne v `int`
  (hierarchie z [2.5](#25-hierarchie-typů-u-binárních-operací) se
  neuplatní, oba operandy jsou stejného typu); teprve výsledný `int` se
  následně explicitně zkonvertuje na `real`.
- `[int; a + b]`, kde `a` je `int` a `b` je `real` → dle
  [2.5](#25-hierarchie-typů-u-binárních-operací) se `a` promuje na `real`,
  sčítání proběhne v `real` a případně saturuje na meze `real`; teprve tento
  `real` výsledek se explicitně ořízne na `int`.

Explicitní konverze tedy vždy působí až **po** úplném vyhodnocení výrazu
uvnitř `[]` — mění pouze typ (a případně, ořezáním, hodnotu) výsledku,
nikoliv způsob, jakým byl výraz samotný spočítán.

---

## 4. Příkazy

### 4.1 Deklarace a inicializace proměnné (`var`)

BASIX zavádí novou proměnnou vždy současně s její inicializací, syntaxí:

```
var(typ, jmeno, [výraz])
```

kde:

- `typ` je `int`, nebo `real` (viz [2.1](#21-základní-typy)),
- `jmeno` je identifikátor proměnné dle pravidel [3.2](#32-pojmenování-identifikátorů),
- `[výraz]` je hranatými závorkami uzavřený výraz dle
  [3.3](#33-syntaxe-výrazů) — může jít i o jeho variantu s explicitní
  konverzí, `[typ; výraz]`, dle [3.4](#34-explicitní-konverze-typu).

Jako každý příkaz, i `var(...)` stojí samostatně na jednom řádku (viz
[3.1](#31-oddělování-příkazů)).

**Sémantika.** Příkaz zavádí novou proměnnou `jmeno` se statickým typem
`typ` a rovnou ji inicializuje hodnotou `výrazu`. Typ `výrazu` přitom nemusí
odpovídat `typu` proměnné — pokud se liší, uplatní se automaticky implicitní
konverze podle [2.4](#24-implicitní-konverze-mezi-typy), stejně jako u
kteréhokoliv jiného přiřazení výsledku výrazu jiného typu do proměnné (viz
poznámka na konci [2.5](#25-hierarchie-typů-u-binárních-operací)). Žádná
saturace při této konverzi není potřeba, protože `int` i `real` sdílejí
stejnou mez `2^53` ([1](#1-přehled)) — jediné, co se při `real → int`
případně ztrácí, je desetinná část.

**Zkrácená forma bez explicitní inicializace — `var(typ, jmeno)`.**
Vedle výše popsané tříargumentové syntaxe existuje i **dvouargumentový**
tvar:

```
var(typ, jmeno)
```

kde `typ` a `jmeno` mají stejný význam jako výše. Obě varianty (`2`, resp.
`3` argumenty) koexistují — počet argumentů je vždy staticky patrný ze
zdrojového textu, takže je kompilátor jednoznačně rozliší; stejnou zásadu
už `var(...)` používá k odlišení skalární a polní formy podle tvaru prvního
argumentu ([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly)).

Tento tvar zavádí proměnnou `jmeno` se statickým typem `typ` a rovnou ji
inicializuje **výchozí nulovou hodnotou** daného typu — `0` pro `int`,
`0.0` pro `real`. Jde čistě o **zkratku** za `var(typ, jmeno, [výraz])`
s `výraz` rovným nulovému literálu odpovídajícího typu — sémanticky zcela
ekvivalentní `var(int, jmeno, [0])`, resp. `var(real, jmeno, [0.0])`; žádná
další konverze ani saturace se neuplatní (nulová hodnota je vždy triviálně
uvnitř mezí `[-2^53, 2^53]`, [2.1](#21-základní-typy)). Nejde tedy o
nedefinovaný/neinicializovaný stav — takový by odporoval zásadě „žádné UB"
([1](#1-přehled)) — proměnná je i zde od svého vzniku inicializovaná, jen
na implicitní, nulovou hodnotu.

Příklady:

- `var(int, a)` → `a` je `int` s hodnotou `0`.
- `var(real, b)` → `b` je `real` s hodnotou `0.0`.

Příklady s explicitní inicializací (tříargumentová forma):

- `var(int, x, [5])` → `x` je `int` s hodnotou `5`.
- `var(real, y, [x + 1])`, kde `x` je `int` s hodnotou `5` z předchozího
  příkladu → literál `1` je zapsán bez desetinné tečky, má tedy intrinsický
  typ `int` (viz [2.3](#23-saturace-přetečení-a-widening)); operandy `x` a
  `1` jsou tak oba `int`, hierarchie z
  [2.5](#25-hierarchie-typů-u-binárních-operací) se vůbec neuplatní a
  sčítání proběhne celé v `int` — výraz `[x + 1]` dá `int` hodnotu `6`.
  Teprve při uložení do `real` proměnné `y` se uplatní implicitní konverze
  [2.4](#24-implicitní-konverze-mezi-typy) a `y` dostane hodnotu `6.0`.
- `var(int, z, [3.7])` → výraz `[3.7]` je typu `real`; při uložení do `int`
  proměnné `z` se uplatní implicitní konverze [2.4](#24-implicitní-konverze-mezi-typy)
  (ořezání desetinné části), `z` tedy dostane hodnotu `3`.
- `var(real, w, [int; 3.7])` → zde explicitní konverze skutečně něco mění:
  literál `3.7` je typu `real`, explicitní konverze `[int; ...]` ho nejprve
  ořízne na `int` hodnotu `3`; teprve tato již ořezaná hodnota se při
  uložení do `real` proměnné `w` implicitně (a bezeztrátově) převede zpět
  na `real` — `w` tak dostane `3.0`, **nikoliv** `3.7`. Bez explicitní
  konverze (`var(real, w, [3.7])`) by `w` dostalo `3.7` beze změny, protože
  typ výrazu (`real`) by se rovnou shodoval s typem `w`. Rozdíl mezi oběma
  zápisy ukazuje, že pořadí konverzí (explicitní ořezání *před* uložením,
  vs. žádné ořezání) může výsledek reálně změnit — na rozdíl od
  `var(int, w, [real; 3.7])`, kde by explicitní konverze na `real` byla
  no-op (literál už `real` je) a jediná skutečná konverze (zpět na `int`)
  by proběhla až implicitně při samotném uložení, se stejným výsledkem,
  jako by tam `real;` vůbec nebylo.

### 4.2 Přiřazení hodnoty do proměnné (`set`)

Na rozdíl od `var(...)` z [4.1](#41-deklarace-a-inicializace-proměnné-var),
který proměnnou zavádí, slouží `set(...)` výhradně ke **změně hodnoty již
existující proměnné** — sám žádnou novou proměnnou nedeklaruje. Syntaxe:

```
set(jmeno, [výraz])
```

kde:

- `jmeno` je identifikátor **již dříve deklarované** proměnné (tedy
  proměnné zavedené dřívějším příkazem `var(...)`, viz
  [4.1](#41-deklarace-a-inicializace-proměnné-var)); `set` sám o sobě typ
  proměnné nijak neurčuje ani nemění — ten zůstává navždy daný jejím
  původním `var(...)`,
- `[výraz]` je hranatými závorkami uzavřený výraz dle
  [3.3](#33-syntaxe-výrazů), případně s explicitní konverzí `[typ; výraz]`
  dle [3.4](#34-explicitní-konverze-typu).

Jako každý příkaz, i `set(...)` stojí samostatně na jednom řádku (viz
[3.1](#31-oddělování-příkazů)).

**Sémantika.** Příkaz vyhodnotí `výraz` a jeho výslednou hodnotou přepíše
dosavadní hodnotu proměnné `jmeno` — typ proměnné se tímto nemění, zůstává
takový, jaký byl určen při deklaraci. Pokud se typ `výrazu` liší od
(neměnného) typu proměnné `jmeno`, uplatní se automaticky implicitní
konverze podle [2.4](#24-implicitní-konverze-mezi-typy) — zcela stejně,
jako při inicializaci v `var(...)` (viz sémantika v
[4.1](#41-deklarace-a-inicializace-proměnné-var)). Žádná saturace při této
konverzi není potřeba, protože `int` i `real` sdílejí stejnou mez `2^53`
([1](#1-přehled)).

Příklady (navazující na proměnné `x`, `y`, `z`, `w` z
[4.1](#41-deklarace-a-inicializace-proměnné-var)):

- `set(x, [10])` → `x` (deklarované jako `int`) dostane novou hodnotu `10`,
  beze změny typu.
- `set(x, [y])` → `y` je `real`; při uložení do `int` proměnné `x` se
  uplatní implicitní konverze [2.4](#24-implicitní-konverze-mezi-typy)
  (ořezání desetinné části).
- `set(y, [x])`, kde `x` je `int` → implicitní konverze `int → real` je
  bezeztrátová, `y` dostane přesnou hodnotu `x`, jen jako `real`.
- `set(w, [int; 9.9])` → i zde funguje explicitní konverze stejně jako v
  `var(...)`: `9.9` se explicitně ořízne na `int` hodnotu `9`, ta se poté
  implicitně (bezeztrátově) převede na `real` proměnné `w`, která tak
  dostane `9.0`.

### 4.3 Složený příkaz s návěštím (`code`) a jeho ukončení (`break`)

Kromě jednoduchých příkazů `var(...)` a `set(...)` z
[4.1](#41-deklarace-a-inicializace-proměnné-var) a
[4.2](#42-přiřazení-hodnoty-do-proměnné-set) zavádí BASIX i **složený
příkaz** `code`, který sdružuje sekvenci dalších příkazů do jednoho
pojmenovaného bloku:

```
code(label)
tělo
end code
```

kde:

- `label` je identifikátor dle pravidel
  [3.2](#32-pojmenování-identifikátorů), pojmenovávající tento konkrétní
  blok,
- `tělo` je sekvence libovolného počtu (včetně nuly) příkazů BASIXu —
  `var(...)`, `set(...)`, vnořený `code(...)`, `break(...)` atd. — každý na
  vlastním řádku dle [3.1](#31-oddělování-příkazů).

Řádky `code(label)` a `end code` tvoří hranice bloku a stojí, stejně jako
každý příkaz, samostatně na svém řádku.

**Odsazení těla.** `tělo` bloku se zapisuje odsazené doprava vůči řádkům
`code(label)` a `end code` (viz příklady níže). Jde ale čistě o vizuální
konvenci pro čitelnost — odsazení (jeho přítomnost, míra, ani konzistence)
nemá žádný vliv na syntaxi ani sémantiku programu. Hranice bloku určují
výhradně samotné řádky `code(label)` a `end code`, stejně jako u
vnořených bloků; odsazení pouze opticky zvýrazňuje vnoření.

**Sémantika běžného průběhu.** Pokud provádění bloku dosáhne řádku
`end code` přirozeně (aniž by nastal `break`, viz níže), příkazy `tělo` se
prostě provedou popořadě jeden po druhém a `code(...)` blok tím jako celek
skončí — `label` sám o sobě lineární běh nijak neovlivňuje, uplatní se jen
v součinnosti s `break`.

**Předčasné ukončení — `break(label)`.** Uvnitř `tělo` libovolného
`code(label)` bloku (i vnořeně, viz níže) lze použít příkaz:

```
break(label)
```

- Jako každý příkaz stojí samostatně na řádku
  ([3.1](#31-oddělování-příkazů)).
- Jeho provedení okamžitě ukončí provádění **toho `code(...)` bloku, jehož
  `label` se s `label` u `break` shoduje** — provádění programu pokračuje
  prvním příkazem za odpovídajícím `end code`; zbytek `tělo` daného bloku
  (vše mezi `break` a jeho `end code`) se nevykoná.
- `label` u `break(label)` musí odpovídat identifikátoru **některého
  z lexikálně obklopujících `code(...)` bloků** v místě, kde se `break`
  nachází — jinak jde o chybu při kompilaci. `break` tedy může směřovat jen
  „ven" z bloku (nebo bloků), ve kterých je sám vnořen, nikdy do souřadného
  („sourozeneckého"), ani do vnitřního bloku.

  *Pozn.: `while` ([4.4](#44-cyklus-s-podmínkou-while)) zavádí druhou
  kategorii pojmenovatelných bloků, takže od zavedení `while` toto pravidlo
  platí obecně pro „některý z lexikálně obklopujících `code(...)` nebo
  `while(...)` bloků" — viz [4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue)
  pro úplné, aktuální znění pravidel `break` (včetně jeho nepojmenované
  varianty, která je specifická pro `while`) a pro nový příkaz `continue`.*

**Vícenásobné (víceúrovňové) ukončení.** Protože `code(...)` bloky lze
libovolně vnořovat, `break(label)` odkazující se na `label` některého
z *vnějších* obklopujících bloků ukončí najednou i všechny bloky mezi
místem `break` a tímto vnějším blokem (včetně) — obdoba tzv. „labeled
break" známého z jiných jazyků (např. Javy). Např.:

```
code(outer)
    code(inner)
        break(outer)
    end code
end code
```

zde `break(outer)` ukončí rovnou oba bloky, `inner` i `outer` — provádění
pokračuje až prvním příkazem za vnějším `end code` (patřícím k `outer`).

**Kolize labelů u vnořených bloků.** Pokud vnitřní `code(...)` blok použije
stejný `label`, jaký už používá některý z jeho (přímo, nebo nepřímo)
obklopujících `code(...)` bloků, jde o chybu při kompilaci — uvnitř takto
vnořeného bloku by byl `break(label)` nejednoznačný (nebylo by jasné, který
ze dvou stejně pojmenovaných bloků se má ukončit). Naopak dva **souřadné**
(vzájemně nevnořené) `code(...)` bloky stejný `label` sdílet mohou, protože
nikdy nejsou aktivní současně.

Příklad:

```
var(int, x, [0])
code(loop_body)
    set(x, [x + 1])
    break(loop_body)
    set(x, [x + 100])
end code
```

Zde se `x` po `var(...)` nastaví na `1` (`set(x, [x + 1])` proběhne), poté
`break(loop_body)` okamžitě ukončí `code(loop_body)` blok — poslední řádek
(`set(x, [x + 100])`) se už neprovede a `x` zůstává `1`.

### 4.4 Cyklus s podmínkou (`while`)

Kromě `code(...)` z [4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break)
zavádí BASIX i druhý druh složeného příkazu — cyklus `while`, s **nepovinným**
labelem:

```
while(label; [výraz])
tělo
end while
```

Pokud label nepotřebujeme, zapisuje se cyklus bez něj a bez středníku:

```
while([výraz])
tělo
end while
```

kde:

- `label`, je-li uveden, je identifikátor dle pravidel
  [3.2](#32-pojmenování-identifikátorů), pojmenovávající tento konkrétní
  cyklus. Platí pro něj stejné pravidlo kolize jako u `code(...)`
  ([4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break)): pokud
  vnořený `while` (nebo `code`) použije `label`, který už používá některý
  z jeho obklopujících `code(...)` nebo `while(...)` bloků, jde o chybu při
  kompilaci; souřadné bloky (`code` i `while` vzájemně) stejný `label`
  sdílet mohou, protože nikdy nejsou aktivní současně. Cyklus bez labelu se
  do této kolizní kontroly nijak nezapojuje (nemá s čím kolidovat). *Pozn.:
  od zavedení `loop` ([4.6](#46-cyklus-s-krokováním-loop)) platí totéž
  pravidlo obecně pro `code(...)`, `while(...)` i `loop(...)` bloky
  dohromady — viz zobecněné znění v
  [4.6](#46-cyklus-s-krokováním-loop).*
- `[výraz]` je podmínka cyklu — hranatými závorkami uzavřený výraz dle
  [3.3](#33-syntaxe-výrazů), případně s explicitní konverzí `[typ; výraz]`
  dle [3.4](#34-explicitní-konverze-typu).
- `tělo` je sekvence libovolného počtu (včetně nuly) příkazů BASIXu —
  `var(...)`, `set(...)`, vnořený `code(...)` nebo `while(...)`,
  `break(...)`, `continue(...)` atd. — každý na vlastním řádku dle
  [3.1](#31-oddělování-příkazů).

Jako každý příkaz stojí řádky `while(...)` a `end while` samostatně na
svém řádku. Odsazení `tělo` je, stejně jako u `code`
([4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break)), čistě
vizuální konvence bez vlivu na syntaxi ani sémantiku.

**Sémantika.** Před **každou** iterací (včetně té úplně první) se vyhodnotí
`[výraz]` a posoudí se jeho pravdivost dle pravidla z
[2.2](#22-pravdivost) (platí jednotně pro `int` i `real`, žádný zvláštní
typ podmínky BASIX nevyžaduje). Je-li podmínka „true", provede se `tělo`
celé, popořadě, od prvního příkazu k poslednímu, a poté se podmínka
vyhodnotí znovu. Jakmile vyjde „false", cyklus jako celek končí a
provádění pokračuje prvním příkazem za odpovídajícím `end while`. Je-li
podmínka nepravdivá hned napoprvé, `tělo` se neprovede ani jednou.

Příklad:

```
var(int, i, [0])
while([i < 3])
    set(i, [i + 1])
end while
```

Zde se podmínka `[i < 3]` vyhodnotí celkem čtyřikrát (pro `i` postupně
`0, 1, 2, 3`) a `tělo` proběhne třikrát; po skončení cyklu má `i` hodnotu
`3`.

### 4.5 Předčasné ukončení a přeskočení iterace (`break`, `continue`)

Zavedením `while` ([4.4](#44-cyklus-s-podmínkou-while)), `loop`
([4.6](#46-cyklus-s-krokováním-loop)), `for`
([4.7](#47-cyklus-přes-pole-for)) a `dowhile`
([4.8](#48-cyklus-s-podmínkou-na-konci-dowhile)) vznikají vedle
`code(...)` bloků
([4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break)) další
**čtyři** druhy pojmenovatelných bloků — všechny **iterační** (na rozdíl
od `code`, který proběhne nejvýše jednou) — a tedy i iterační smysl pro
jejich předčasné ukončení. Zavedením `if`/`case`
([4.9](#49-podmíněný-příkaz-if)) přibývají ještě další dva druhy
pojmenovatelných bloků, tentokrát opět **neiterační** (stejně jako
`code`). Kdekoliv se dále v této sekci píše „cyklus", myslí se tím
jednotně `while`, `loop`, `for` i `dowhile` (všechny čtyři sdílí stejná
pravidla pro `break`/`continue`, jen se liší tím, co se stane po
přeskočení zbytku těla — viz `continue` níže); kdekoliv se píše „blok"
bez upřesnění, myslí se tím kterýkoliv ze **sedmi** druhů — `code`,
`while`, `loop`, `for`, `dowhile`, `if`, `case`. Tato sekce shrnuje
**úplné, aktuální** znění pravidel pro `break` — včetně jeho
nepojmenované varianty, která dává smysl jen u cyklů — a zavádí obdobný
příkaz `continue` pro přeskočení zbytku aktuální iterace.

**`break(label)` — pojmenovaná varianta.** Syntaxe a základní chování jsou
shodné s [4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break):
`label` musí odpovídat identifikátoru některého z lexikálně obklopujících
`code(...)`, `while(...)`, `loop(...)`, `for(...)`, `dowhile(...)`,
`if(...)` **nebo** `case(...)` bloků v místě, kde se `break` nachází —
jinak jde o chybu při kompilaci. Provedení `break(label)` okamžitě
ukončí ten blok, jehož `label` se shoduje, ať už jde o kterýkoliv ze
sedmi druhů — provádění pokračuje prvním příkazem za jeho `end code`/
`end while`/`end loop`/`end for`/`end dowhile`/`end if`/`end case`.
Odkazuje-li `label` na blok, který není tím nejbližším obklopujícím,
ukončí se zároveň i všechny mezilehlé bloky (libovolné kombinace všech
sedmi druhů) mezi místem `break` a cílovým blokem (včetně) — stejné
víceúrovňové chování jako u prostého `code`
([4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break)). U
cyklu (`while`, `loop`, `for`, nebo `dowhile`) cíleného tímto způsobem
`break(label)` ukončuje celý cyklus (ne jen aktuální iteraci) — zbylé
iterace se už neprovedou; u `loop` i `for` se navíc neprovede ani
poslední krokování ([4.6](#46-cyklus-s-krokováním-loop),
[4.7](#47-cyklus-přes-pole-for)). U `if` cíleného tímto způsobem
`break(label)` ukončuje celý `if` (bez ohledu na to, přes který `case`
byl `break` proveden) — provádění pokračuje za jeho `end if`. U `case`
cíleného tímto způsobem `break(label)` ukončuje jen tento `case` blok —
viz [4.9](#49-podmíněný-příkaz-if) pro konkrétní důsledek této
varianty.

**`break()` — nepojmenovaná varianta, jen pro cykly.** Kromě
`break(label)` zavádí `while`, `loop`, `for` i `dowhile` variantu
`break()` bez argumentu: ukončí **nejbližší lexikálně obklopující
cyklus** (`while`, `loop`, `for`, nebo `dowhile`), bez ohledu na to, zda
má, či nemá label, a bez ohledu na to, kolik `code(...)`, `if(...)` a
`case(...)` bloků (pojmenovaných i ne) mezi místem `break()` a tímto
cyklem leží — všechny takové mezilehlé bloky se ukončí spolu s cyklem.
`break()` použitý v místě, kde není žádný obklopující cyklus (byť by byl
obklopen libovolným množstvím `code`, `if`, nebo `case` bloků), je
chyba při kompilaci.

**`continue(label)` a `continue()` — přeskočení iterace.** Syntakticky i
významem analogické k `break`, ale místo ukončení celého cyklu přeskočí
jen zbytek **aktuální** iterace:

- u cíleného `while` pokračuje provádění znovu vyhodnocením jeho podmínky
  `[výraz]` (nikoliv příkazem za jeho `end while`) — je-li podmínka stále
  „true", proběhne další iterace `tělo`, jinak cyklus končí stejně jako
  při běžném konci ([4.4](#44-cyklus-s-podmínkou-while));
- u cíleného `loop` proběhne nejprve krokování (přičtení `krok` k
  `promenna`, viz [4.6](#46-cyklus-s-krokováním-loop)) — stejně, jako by
  `tělo` doběhlo přirozeně až na konec — a teprve poté se znovu vyhodnotí
  podmínka pokračování; `continue` tedy u `loop` nikdy krokování
  neobchází;
- u cíleného `for` proběhne nejprve krokování (`promenna + 1`, viz
  [4.7](#47-cyklus-přes-pole-for)) — stejně, jako by `tělo` doběhlo
  přirozeně až na konec — a teprve poté se znovu vyhodnotí podmínka
  pokračování; `continue` tedy u `for`, stejně jako u `loop`, nikdy
  krokování neobchází;
- u cíleného `dowhile` pokračuje provádění rovnou vyhodnocením jeho
  podmínky `[výraz]` — tedy stejné místo, kde by se podmínka vyhodnotila
  i po přirozeném doběhnutí `tělo` na konec ([4.8](#48-cyklus-s-podmínkou-na-konci-dowhile))
  — je-li podmínka stále „true", proběhne další iterace `tělo`, jinak
  cyklus končí stejně jako při běžném konci.

`label` u `continue(label)` musí odpovídat identifikátoru některého
z lexikálně obklopujících **`while(...)`, `loop(...)`, `for(...)`, nebo
`dowhile(...)`** bloků — na rozdíl od `break(label)` zde `label` patřící
`code(...)`, `if(...)`, ani `case(...)` bloku není platným cílem (jde o
chybu při kompilaci), protože žádný z těchto druhů nemá pojem iterace,
ke které by se dalo vrátit. Odkazuje-li `label` na vzdálenější
obklopující cyklus, ukončí se nejprve všechny mezilehlé bloky (libovolná
kombinace `code`, `if`, `case` i vnořeného `while`/`loop`/`for`/
`dowhile`) mezi místem `continue` a cílovým cyklem (včetně) — stejně
jako u víceúrovňového `break(label)` — a teprve poté se uplatní pravidlo
pro cílový typ bloku (podmínka u `while`, krokování a podmínka u `loop`
i u `for`, podmínka u `dowhile`) popsané výše.

`continue()` bez labelu přeskočí zbytek aktuální iterace **nejbližšího**
lexikálně obklopujícího cyklu (`while`, `loop`, `for`, nebo `dowhile`),
analogicky k `break()` — včetně ukončení libovolných mezilehlých `code`,
`if` i `case` bloků. Stejně jako `break()`, i `continue()` použitý mimo
jakýkoli obklopující cyklus je chyba při kompilaci.

Příklad (kombinace `while`, vnořeného `code`, labelovaného i
nelabelovaného `break`/`continue`):

```
var(int, i, [0])
var(int, soucet, [0])
while(outer; [i < 5])
    set(i, [i + 1])
    code(skip_odd)
        set(soucet, [soucet + i])
        break(skip_odd)
    end code
    while([soucet > 100])
        break(outer)
    end while
    continue()
end while
```

Zde vnitřní nelabelovaný `while([soucet > 100])` demonstruje, že
`break(outer)` uvnitř něj ukončí rovnou oba cykly (vnitřní i vnější
`outer`), zatímco `continue()` na posledním řádku těla `outer` (kdyby k
němu provádění došlo) by přeskočil zbytek těla `outer` a vrátil se rovnou
k vyhodnocení jeho podmínky `[i < 5]` — v tomto konkrétním příkladu jde ale
o poslední příkaz těla, takže `continue()` je zde sémanticky ekvivalentní
přirozenému doběhnutí na `end while`.

### 4.6 Cyklus s krokováním (`loop`)

Kromě `while` ([4.4](#44-cyklus-s-podmínkou-while)) zavádí BASIX i třetí
druh složeného příkazu — cyklus `loop`, který iteruje přes aritmetickou
posloupnost hodnot ukládaných do **již existující** proměnné, s
nepovinným labelem:

```
loop(label; promenna, (od, do, krok))
tělo
end loop
```

Pokud label nepotřebujeme, zapisuje se bez něj a bez středníku:

```
loop(promenna, (od, do, krok))
tělo
end loop
```

kde:

- `label`, je-li uveden, je identifikátor dle
  [3.2](#32-pojmenování-identifikátorů). Platí pro něj úplně stejné
  pravidlo kolize jako u `code(...)` a `while(...)`
  ([4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break)) —
  **Zobecněné (aktuální) znění kolizního pravidla:** pokud vnořený
  `code(...)`, `while(...)`, nebo `loop(...)` blok použije `label`, který
  už používá **kterýkoliv** z jeho (přímo, nebo nepřímo) obklopujících
  bloků — ať už jde o `code`, `while`, nebo `loop`, v libovolné kombinaci
  — jde o chybu při kompilaci; nezáleží na tom, zda jde o stejný, či
  různý druh bloku, kolizní množina labelů je pro všechny tři druhy
  **společná**. Naopak dva **souřadné** (vzájemně nevnořené) bloky
  libovolné kombinace druhů (`code`, `while`, `loop`) stejný `label`
  sdílet mohou, protože nikdy nejsou aktivní současně. `loop` bez labelu
  se do této kolizní kontroly nijak nezapojuje (nemá s čím kolidovat) —
  viz příklad níže. *Pozn.: od zavedení `for`
  ([4.7](#47-cyklus-přes-pole-for)) se tato společná kolizní množina
  rozšiřuje ještě o tento další druh bloku, od zavedení `dowhile`
  ([4.8](#48-cyklus-s-podmínkou-na-konci-dowhile)) o další, a od
  zavedení `if`/`case` ([4.9](#49-podmíněný-příkaz-if)) ještě o dva
  další — viz [4.9](#49-podmíněný-příkaz-if) pro úplně aktuální znění.*
  Viz
  [4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue) pro
  plné znění pravidel `break`/`continue`, která se nyní vztahují na
  všechny tři druhy bloků stejně.
- `promenna` je identifikátor **již dříve deklarované** proměnné (zavedené
  dřívějším `var(...)`, viz
  [4.1](#41-deklarace-a-inicializace-proměnné-var)) — stejný požadavek,
  jaký má `jmeno` u `set(...)` ([4.2](#42-přiřazení-hodnoty-do-proměnné-set)).
  `loop` sám o sobě žádnou novou proměnnou nezavádí ani nemění její
  statický typ — ten zůstává navždy daný jejím původním `var(...)`.
  Použití nedeklarovaného identifikátoru jako `promenna` je chyba při
  kompilaci.
- `od` a `do` jsou hranatými závorkami uzavřené výrazy dle
  [3.3](#33-syntaxe-výrazů), případně s explicitní konverzí
  `[typ; výraz]` dle [3.4](#34-explicitní-konverze-typu) — stejná syntaxe
  výrazu, jaká se používá všude jinde v BASIXu.
- `krok` je výraz stejného tvaru, avšak **nepovinný**; je-li vynechán,
  chová se cyklus, jako by byl zapsán `[1]` (celočíselný literál `1`).
- `tělo` je sekvence libovolného počtu (včetně nuly) příkazů BASIXu,
  stejně jako u `code`/`while`.

Jako každý příkaz stojí `loop(...)` a `end loop` samostatně na svém
řádku; odsazení `tělo` je čistě vizuální konvence bez vlivu na syntaxi
ani sémantiku (stejně jako u `code`/`while`).

**Meze se vyhodnocují jednou, na začátku.** Na rozdíl od podmínky
`while`, která se přehodnocuje před každou iterací, se `od`, `do` i
`krok` vyhodnotí přesně **jednou**, před první iterací, v pořadí `od`,
`do`, `krok` (zleva doprava, jak jsou zapsané) — jejich hodnoty (a u
`krok` i z ní odvozený směr, viz níže) zůstávají pro celý běh cyklu
fixní. Naproti tomu `promenna` je zcela běžná proměnná: cyklus ji čte i
zapisuje stejně jako kterýkoliv jiný příkaz, a pokud ji `tělo` samo přes
`set(...)` změní, projeví se to i na dalším průběhu cyklu — žádné skryté,
tělem needitovatelné počítadlo neexistuje (viz příklad níže).

**Inicializace.** Před první iterací se do `promenna` uloží hodnota
`od`, stejně, jako by se provedlo `set(promenna, od)` — tedy včetně
implicitní konverze dle [2.4](#24-implicitní-konverze-mezi-typy), liší-li
se typ výrazu `od` od (neměnného) typu `promenna`.

**Směr a podmínka pokračování.** Znaménko fixní hodnoty `krok` (viz výše)
určuje směr celého cyklu:

- je-li `krok >= 0` (ascendentní směr — zahrnuje i `krok == 0`, viz
  níže), test před každou iterací zní `promenna <= do`;
- je-li `krok < 0` (descendentní směr), test zní `promenna >= do`.

Obě meze jsou **inkluzivní** — je-li `promenna` rovna přesně `do`, ještě
proběhne další iterace. Porovnání se provádí dle standardní hierarchie
typů z [2.5](#25-hierarchie-typů-u-binárních-operací) (liší-li se typ
`promenna` od typu fixní hodnoty `do`, nižší typ se promuje na `real`
stejně jako u kteréhokoliv jiného porovnání) — `loop` zde nezavádí žádný
nový porovnávací mechanismus.

**Průběh iterace.** Před **každou** iterací (včetně té úplně první) se
vyhodnotí výše popsaná podmínka z aktuální hodnoty `promenna`. Je-li
„true", provede se `tělo` celé, popořadě; jakmile `tělo` doběhne
(přirozeně, nebo přes `continue`, viz
[4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue)),
provede se **krokování**: hodnota `promenna` se přepíše na
`promenna + krok`, stejně, jako by se provedlo
`set(promenna, [promenna + krok])` — tedy včetně hierarchie typů
([2.5](#25-hierarchie-typů-u-binárních-operací)) a saturace
([2.3](#23-saturace-přetečení-a-widening)) při samotném sčítání a
implicitní konverze výsledku zpět do typu `promenna`
([2.4](#24-implicitní-konverze-mezi-typy)). Poté se podmínka vyhodnotí
znovu. Jakmile vyjde „false", cyklus jako celek končí a provádění
pokračuje prvním příkazem za `end loop`; hodnota `promenna` zůstává
taková, jaká byla naposledy nastavena — žádné „zapomenutí" hodnoty po
konci cyklu se nekoná, `promenna` je obyčejná, dále použitelná proměnná.
Je-li podmínka nepravdivá hned napoprvé, `tělo` se neprovede ani jednou a
`promenna` zůstává na hodnotě `od`.

**`krok == 0` není chyba ani zvláštní případ.** Spadá do ascendentní
větve výše (`krok >= 0`), test tedy zůstává `promenna <= do`; protože se
ale `promenna` krokováním nikdy nezmění (`promenna + 0 = promenna`),
cyklus buď neproběhne ani jednou (je-li úvodní `od > do`), nebo poběží
navždy (je-li `od <= do`) — stejně deterministické, nekonečné chování,
jaké může nastat i u `while([1]) ... end while` bez `break`. `loop` zde
nezavádí žádné nové pravidlo, jen se na `krok == 0` uplatní obecná
ascendentní větev jako na kterékoliv jiné nezáporné `krok`.

**Saturace při krokování.** Protože krokovací přičtení používá stejný
saturační mechanismus jako běžné `+`
([2.3](#23-saturace-přetečení-a-widening)), může `promenna` u `int` i
`real` dosáhnout meze `2^53` (resp. `-2^53`) a dál na ní setrvat
(saturace, ne přetečení/UB) — pokud tato saturovaná hodnota stále
splňuje test (`<= do`, resp. `>= do`), stává se cyklus nekonečným, stejně
deterministickým způsobem jako v případě `krok == 0` výše.

**Příklad.**

```
var(int, i, [0])
var(int, konec, [10])
loop(outer; i, ([0], [konec], [1 + 1]))
    set(i, [i + i])
end loop
```

Průběh (test → tělo → krokování):

| iterace | test (`i <= 10`) | `i` po `set(i, [i+i])` | `i` po krokování (`+2`) |
|---|---|---|---|
| 1 | `0 <= 10` → true | `0` | `2` |
| 2 | `2 <= 10` → true | `4` | `6` |
| 3 | `6 <= 10` → true | `12` | `14` |
| 4 | `14 <= 10` → false | — | — |

Cyklus končí po třetí iteraci s `i = 14`. Příklad zároveň ukazuje, že
`krok` (zde fixně `2`, vyhodnocen jen jednou z `[1 + 1]`) je jediná
hodnota přičítaná při krokování — samotné `tělo` může `promenna` změnit
libovolně (zde zdvojnásobením), a další test i krokování vychází z takto
změněné hodnoty, nikoliv z nějakého skrytého počítadla nezávislého na
`tělo`.

**Příklad — kolize labelů napříč `code`, `while` a `loop`.** Následující
(nezkompilovatelný) fragment ilustruje, že kolizní množina labelů je
opravdu společná pro všechny tři druhy bloků bez ohledu na kombinaci
druhů:

```
var(int, i, [0])
var(int, j, [0])
var(int, konec, [10])

loop(A; i, ([0], [konec]))
    while(B; [i < konec])
        code(A)
            break(A)
        end code
    end while
end loop

loop(A; j, ([0], [konec]))
end loop
```

Vnější `loop(A; i, ...)` má label `A`; do něj je vnořený `while(B; ...)`
s labelem `B`; do toho je dále vnořený `code(A)` — a právě ten je
problém: použije label `A`, který už používá jeho obklopující (byť ne
bezprostřední) `loop(A)`. Druh bloku přitom roli nehraje — kolize by
nastala stejně, kdyby vnější blok byl `code(A)` nebo `while(A)` — jde o
chybu při kompilaci (uvnitř `code(A)` by `break(A)` bylo nejednoznačné:
mělo by ukončit vnitřní `code`, nebo vnější `loop`?).

Druhý, na řádcích níže samostatně stojící `loop(A; j, ...)` je naproti
tomu v pořádku: není vnořený do prvního `loop(A; i, ...)` (ten už v
místě druhého `loop` dávno skončil), jde tedy o **souřadné** bloky, a ty
label `A` sdílet smí.

Kdyby se vnitřní `code(A)` přejmenoval např. na `code(inner)`, fragment
by byl validní a `break(A)` uvnitř něj by nadále platně cílil na vzdálený
obklopující `loop(A)` — víceúrovňově by tak ukončil zároveň `code(inner)`
(blok, ve kterém `break` sám stojí), `while(B)` i cílový `loop(A)`,
přesně dle pravidel z
[4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue).

### 4.7 Cyklus přes pole (`for`)

Kromě `while` ([4.4](#44-cyklus-s-podmínkou-while)) a `loop`
([4.6](#46-cyklus-s-krokováním-loop)) zavádí BASIX i čtvrtý druh
složeného příkazu — cyklus `for`, který iteruje přes indexy pole
(jednorozměrné `array`, kap. [5](#5-jednorozměrné-pole-array), nebo
vícerozměrné, kap. [6](#6-vícerozměrné-pole)) a ukládá je do **již
existující** proměnné, s nepovinným labelem:

```
for(label; promenna, pole)
tělo
end for
```

Pokud label nepotřebujeme, zapisuje se bez něj a bez středníku — stejná
konvence jako u `while`/`loop`/`dowhile`:

```
for(promenna, pole)
tělo
end for
```

kde:

- `label`, je-li uveden, je identifikátor dle
  [3.2](#32-pojmenování-identifikátorů). Zapojuje se do **téže společné
  kolizní množiny labelů** jako `code`, `while`, `loop`, `dowhile`, `if`
  a `case` ([4.6](#46-cyklus-s-krokováním-loop),
  [4.9](#49-podmíněný-příkaz-if) pro úplně aktuální znění) — `for` je
  **sedmý** druh bloku v této množině. **Zobecněné (aktuální) znění
  kolizního pravidla:** pokud vnořený blok kteréhokoliv ze sedmi druhů
  (`code`, `while`, `loop`, `for`, `dowhile`, `if`, `case`) použije
  `label`, který už používá kterýkoliv z jeho (přímo, nebo nepřímo)
  obklopujících bloků — libovolného ze sedmi druhů, v libovolné
  kombinaci — jde o chybu při kompilaci; souřadné bloky stejný `label`
  sdílet mohou, protože nikdy nejsou aktivní současně. `for` bez labelu
  se do této kolizní kontroly nijak nezapojuje (nemá s čím kolidovat).
- `promenna` je proměnná, která v průběhu cyklu nabývá hodnot indexů
  pole `pole`, postupně od `1` do velikosti pole (inclusive na obou
  stranách — stejná konvence inclusive mezí jako jinde ve specifikaci).
- `pole` je jméno existujícího jednorozměrného pole (`array`, kap.
  [5](#5-jednorozměrné-pole-array)).

**`promenna` musí být deklarovaná už dříve přes `var(...)`** — stejný
požadavek, jaký má `promenna` u `loop`
([4.6](#46-cyklus-s-krokováním-loop)), a jaký má `jmeno` u `set(...)`
([4.2](#42-přiřazení-hodnoty-do-proměnné-set)). `for` sám o sobě žádnou
novou proměnnou nezavádí ani nemění její statický typ — ten zůstává
navždy daný jejím původním `var(...)`. Použití nedeklarovaného
identifikátoru jako `promenna` je chyba při kompilaci — přesně stejné
znění, jaké má `loop` pro svou `promenna`.

Důsledek: `for` **nezavádí** žádný nový druh scope — proměnná platí i
po skončení cyklu, se svou poslední hodnotou, stejně jako u `loop`.
Jazyk tak dosud nemá koncept proměnné se scope omezeným na blok a `for`
na tom nic nemění.

**Typ `promenna` je libovolný** (`int`, nebo `real`) — stejně jako u
`loop` ([4.6](#46-cyklus-s-krokováním-loop)), `for` sám žádný typ
nevynucuje. Index (celé číslo `1, 2, ..., velikost(pole)`) se do
`promenna` v každé iteraci ukládá stejně, jako by se provedlo
`set(promenna, [index])` — tedy včetně implicitní konverze podle
[2.4](#24-implicitní-konverze-mezi-typy), liší-li se typ `promenna` od
`int`. Je-li `promenna` typu `real`, dostává tak v `i`-té iteraci
hodnotu `i.0` (bezeztrátově, protože `int → real` je vždy přesný
převod v mezích [2.1](#21-základní-typy)) — o nic jiného než o
pohodlnost zápisu tu nejde, index samotný zůstává vždy celé číslo.
Volba je vědomě konzistentní s tím, že jazyk jinak nikde nevynucuje typ
proměnné podle kontextu použití (`loop`, `set`, `var` — všude platí
stejná obecná implicitní konverze).

**Sémantika iterace.** Po vzoru `loop` ([4.6](#46-cyklus-s-krokováním-loop))
se `for(label; promenna, pole)` chová, jako by šlo o `loop` s pevnou
trojicí `(od, do, krok) = ([1], [velikost(pole)], [1])`, kde
`velikost(pole)` je aktuální (pevná, viz [5.1](#51-přehled) bod 1)
velikost pole `pole`.

**Meze se vyhodnocují jednou, na začátku.** Stejně jako u `loop` se
horní mez (`velikost(pole)`) zjišťuje jednou, před první iterací —
prakticky jde ale o formalitu, protože velikost pole je jednou daná při
deklaraci a už se nemění ([5.1](#51-přehled), bod 1), takže by opakované
vyhodnocování dalo vždy stejný výsledek. Spodní mez (`1`) a krok (`1`)
jsou pevné konstanty dané samotnou syntaxí `for` — na rozdíl od `loop`
je zde `krok` vždy kladný, `for` proto na rozdíl od `loop` nemá
descendentní variantu.

**Inicializace.** Před první iterací se do `promenna` uloží hodnota
`1`, stejně jako by se provedlo `set(promenna, [1])` — tedy včetně
implicitní konverze dle [2.4](#24-implicitní-konverze-mezi-typy),
liší-li se typ `promenna` od `int`.

**Podmínka pokračování.** Před **každou** iterací (včetně té úplně
první) se testuje `promenna <= velikost(pole)` — vždy tato jedna,
ascendentní forma testu (na rozdíl od `loop` zde není co rozlišovat
podle znaménka kroku, protože krok je vždy `1`). Porovnání se řídí
standardní hierarchií typů
[2.5](#25-hierarchie-typů-u-binárních-operací) (je-li `promenna` typu
`real`, `velikost(pole)` coby `int` se pro účely porovnání promuje na
`real`) — `for` zde nezavádí žádný nový porovnávací mechanismus, stejně
jako `loop`.

**Průběh iterace (test → tělo → krokování).** Je-li podmínka „true",
provede se `tělo` celé, popořadě; jakmile `tělo` doběhne (přirozeně,
nebo přes `continue`, dle
[4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue)),
provede se **krokování**: hodnota `promenna` se přepíše na
`promenna + 1`, stejně, jako by se provedlo
`set(promenna, [promenna + 1])` — tedy včetně hierarchie typů
([2.5](#25-hierarchie-typů-u-binárních-operací)), saturace
([2.3](#23-saturace-přetečení-a-widening)) a implicitní konverze
výsledku zpět do typu `promenna` ([2.4](#24-implicitní-konverze-mezi-typy)).
Poté se podmínka vyhodnotí znovu. Jakmile vyjde „false", cyklus jako
celek končí a provádění pokračuje prvním příkazem za `end for`; hodnota
`promenna` zůstává taková, jaká byla naposledy nastavena — žádné
„zapomenutí" hodnoty po konci cyklu se nekoná, přesně jako u `loop`.

**`tělo` smí `promenna` měnit ručně (přes `set`) — projeví se to na
dalším průběhu cyklu.** Přesně jako u `loop`
([4.6](#46-cyklus-s-krokováním-loop)): `for` nedrží žádné skryté, tělem
needitovatelné počítadlo indexu. Krokování (`promenna + 1`) i další test
vychází vždy z aktuální hodnoty `promenna`, tedy i z hodnoty, kterou do
ní případně zapsalo samo `tělo`. Pokud `tělo` např. `promenna` zvýší o
`10`, další iterace pokračuje od této zvýšené hodnoty (a poté se k ní
teprve přičte krokovací `+1`) — `for` se v tomto ohledu chová identicky
k `loop`, jen s pevně danými mezemi/krokem odvozenými z `pole` místo
z explicitní `(od, do, krok)` trojice.

**Prázdné pole nemůže nastat — `for` proto vždy provede tělo alespoň
jednou.** Na rozdíl od `while`/`loop`/`dowhile`, kde je běžné, že se
`tělo` neprovede ani jednou, u `for` k tomu z principu nemůže dojít:
pole nikdy nemá velikost `0` — obě deklarační varianty to zaručují
([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly):
výsledek menší než `1` saturuje na `1`;
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu):
seznam `{...}` musí mít alespoň jednu hodnotu). Test první iterace je
tedy vždy `1 <= velikost(pole)` s `velikost(pole) >= 1`, což je vždy
„true".

**Příklad.**

```
var((array, int), a, {10, 20, 30})
var(int, i, [0])
var(int, soucet, [0])

for(i, a)
    set(soucet, [soucet + a[i]])
end for
```

Průběh (test → tělo → krokování), pole `a` má velikost `3`:

| iterace | test (`i <= 3`) | `a[i]` | `soucet` po těle | `i` po krokování |
|---|---|---|---|---|
| 1 | `1 <= 3` → true | `a[1] = 10` | `10` | `2` |
| 2 | `2 <= 3` → true | `a[2] = 20` | `30` | `3` |
| 3 | `3 <= 3` → true | `a[3] = 30` | `60` | `4` |
| 4 | `4 <= 3` → false | — | — | — |

Cyklus končí po třetí iteraci; `soucet` má hodnotu `60`, `i` zůstává na
`4` (poslední krokování proběhlo, i když už podmínku nesplnilo).

**`break`/`continue` u `for`.** `for` se zapojuje do pravidel
`break`/`continue` z
[4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue) zcela
beze změny, jako čtvrtý plnohodnotný druh „cyklu" — kdekoliv se v
[4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue) píše
„cyklus", myslí se od zavedení `for` jednotně `while`, `loop`, `dowhile`
**i** `for` (všechny čtyři sdílí stejná pravidla, liší se jen tím, co se
stane po přeskočení zbytku těla); kdekoliv se píše „blok" bez upřesnění,
myslí se tím kterýkoliv ze **sedmi** druhů — `code`, `while`, `loop`,
`dowhile`, `if`, `case`, `for`.

- **`break(label)`** — `label` smí odpovídat identifikátoru některého
  z lexikálně obklopujících bloků libovolného ze sedmi druhů; u `for`
  cíleného tímto způsobem ukončuje celý cyklus (ne jen aktuální
  iteraci) — zbylé iterace (a jejich krokování) se už neprovedou,
  provádění pokračuje za `end for`.
- **`break()`** — bez argumentu ukončí nejbližší lexikálně obklopující
  cyklus (`while`, `loop`, `dowhile`, nebo `for`), bez ohledu na to, zda
  má, či nemá label — stejně jako u ostatních tří.
- **`continue(label)` / `continue()`** — přeskočí zbytek aktuální
  iterace. U `for` (cíleného přímo, nebo přes `label`) to znamená:
  provede se nejprve krokování (`promenna + 1`, stejně jako by `tělo`
  doběhlo přirozeně na konec) a teprve poté se znovu vyhodnotí podmínka
  pokračování (`promenna <= velikost(pole)`) — `continue` u `for` tedy,
  stejně jako u `loop`, nikdy krokování neobchází. `label` u
  `continue(label)` musí odpovídat identifikátoru některého
  z lexikálně obklopujících `while(...)`, `loop(...)`, `dowhile(...)`,
  nebo `for(...)` bloků — `code`, `if`, ani `case` label zde platným
  cílem není.

Příklad:

```
var((array, int), a, {10, -5, 20, -1, 30})
var(int, i, [0])
var(int, soucet_kladnych, [0])

for(hledej; i, a)
    if([a[i] < 0])
        case(true)
            continue()
        end case
    end if
    set(soucet_kladnych, [soucet_kladnych + a[i]])
end for
```

Pro záporné prvky pole (`a[2] = -5`, `a[4] = -1`) se `continue()`
provede dřív, než se stihne přičíst do `soucet_kladnych` — přeskočí se
zbytek těla dané iterace, provede se krokování `i` a pokračuje se
dalším testem. Po skončení cyklu má `soucet_kladnych` hodnotu
`10 + 20 + 30 = 60`.

**Syntaxe a sémantika — vícerozměrné pole.** Nepovinný
label, stejná konvence zápisu (se středníkem) jako u jednorozměrné
varianty:

```
for(label; (promenna1, promenna2, ..., promennaN), pole)
tělo
end for
```

Bez labelu (bez středníku):

```
for((promenna1, promenna2, ..., promennaN), pole)
tělo
end for
```

kde:

- `label` je nepovinný, se stejnou syntaxí a se stejným zapojením do
  společné kolizní množiny labelů, jaké má u jednorozměrné varianty
  (viz výše) — varianta pro vícerozměrné pole nezavádí žádnou novou
  kategorii bloku, `for` zůstává jediným, sedmým druhem.
- `(promenna1, promenna2, ..., promennaN)` je kulatými závorkami
  uzavřený, čárkami oddělený seznam **alespoň jedné** proměnné — stejná
  syntaktická konstrukce (výčet v `()`), jakou pro *meze* vícerozměrného
  pole zavádí [6.2](#62-deklarace-a-inicializace-výchozí-nuly); tady ale
  namísto výrazů `[vyraz1], ..., [vyrazD]` určujících tvar pole při
  deklaraci stojí výčet **proměnných**, do kterých `for` postupně
  ukládá jednotlivé indexy. `N` (počet uvedených `promennaX`) se musí
  přesně shodovat s počtem rozměrů `D` pole `pole` — jinak jde o chybu
  při kompilaci, analogicky k pravidlu pro počet indexů u čtení/zápisu
  prvku vícerozměrného pole ([6.3](#63-čtení-prvku-jmenovyrazvyraz)/
  [6.4](#64-zápis-do-prvku-setjmenovyrazvyraz-vyraz)).
- Každá `promennaX` musí být **již dříve deklarovaná** proměnná (přes
  `var(...)`) — stejný požadavek jako u jednorozměrné varianty a u
  `loop`; `for` sám žádnou z nich nezavádí ani nemění její typ.
  Jednotlivé `promennaX` jsou vzájemně nezávislé proměnné, klidně i
  různých typů (`int`/`real`) — každá se řídí stejným pravidlem
  implicitní konverze jako jednorozměrná `promenna` výše.
- `pole` je jméno existujícího vícerozměrného pole ([6](#6-vícerozměrné-pole))
  s počtem rozměrů `D = N`. Pro `D = 1` je tento zápis — v souladu s
  identitou z [6.2](#62-deklarace-a-inicializace-výchozí-nuly) (`([vyraz])`
  je pro `D = 1` totéž co holé `[vyraz]`) — plně rovnocenný jednorozměrné
  variantě `for(label; promenna, pole)` výše; `(promenna)` s jedinou
  proměnnou v závorce a holé `promenna` znamenají pro pole o jednom
  rozměru totéž.

**Vnořené krokování v pořadí posledního rozměru jako nejrychlejšího
(„row-major").** `for` s `N` proměnnými se chová, jako by šlo o `N` do
sebe vnořených jednorozměrných `for`-ů, jeden pro každý rozměr, kde
`promenna1` odpovídá **nejvzdálenějšímu** (nejpomaleji se měnícímu)
rozměru a `promennaN` **nejvnitřnějšímu** (nejrychleji se měnícímu) —
stejné pořadí rozměrů a stejná konvence „vnějšího-jako-prvního", jakou
uvádí vícerozměrné pole u indexace ([6.3](#63-čtení-prvku-jmenovyrazvyraz):
pořadí `vyraz1, ..., vyrazD` odpovídá pořadí zadanému při deklaraci
[6.2](#62-deklarace-a-inicializace-výchozí-nuly)). Ekvivalentně
(a prakticky totéž jako přímý zápis vnořených cyklů):

```
for(promenna1, dim1(pole))
    for(promenna2, dim2(pole))
        ...
            for(promennaN, dimN(pole))
                tělo
            end for
        ...
    end for
end for
```

kde `dimX(pole)` značí velikost `X`-tého rozměru pole `pole`. Přesné,
jednotné znění (bez pomocné fikce vnořených `for`):

1. **Inicializace.** Před první iterací se do každé `promennaX`
   (v pořadí `promenna1, ..., promennaN`) uloží `1`, stejně jako by se
   provedlo `set(promennaX, [1])`, včetně implicitní konverze
   [2.4](#24-implicitní-konverze-mezi-typy).
2. **Podmínka pokračování.** Cyklus pokračuje, dokud je aktuální
   `N`-tice `(promenna1, ..., promennaN)` platnou kombinací indexů —
   tedy dokud `promenna1 <= dim1(pole)` (na ostatních `promennaX` už
   v tomto bodě nezáleží, viz krokování níže, které zaručuje, že jsou
   vždy buď platné, nebo že celý cyklus zároveň skončil).
3. **Tělo.** Je-li podmínka „true", provede se `tělo` celé, popořadě —
   se všemi `promennaX` nastavenými na aktuální kombinaci indexů.
4. **Krokování („odometr").** Po doběhnutí `tělo` (přirozeně, nebo přes
   `continue`) se krokuje **poslední** (`promennaN`) proměnná: přepíše
   se na `promennaN + 1`. Přesáhne-li tím `dimN(pole)`, nastaví se
   zpátky na `1` a **místo ní** se o `1` zvýší předchozí, `(N-1)`-tá
   proměnná — a stejné pravidlo (přetečení → reset na `1` a krokování
   o úroveň výš) se uplatní kaskádovitě, dokud buď nějaká `promennaX`
   zvýšení „unese" (zůstane `<= dimX(pole)`), nebo dokud přetečení
   nedosáhne až na `promenna1` — v tom případě cyklus jako celek končí
   (podmínka v kroku 2 vyjde „false"). Každý dílčí krok tohoto
   kaskádového krokování se řídí stejnými pravidly jako krokování
   u jednorozměrné varianty (implicitní konverze
   [2.4](#24-implicitní-konverze-mezi-typy), saturace
   [2.3](#23-saturace-přetečení-a-widening) při `+1`).
5. Po kroku 4 se provádění vrací do kroku 2 (nové vyhodnocení
   podmínky).

**Tělo smí libovolnou `promennaX` měnit ručně** — stejně jako u
jednorozměrné varianty, žádná z nich není žádné skryté, needitovatelné
počítadlo; ruční změna (přes `set`) se projeví na dalším krokování i
testu stejně, jako by šlo o aktuální, „opravdovou" hodnotu dané
proměnné.

**Prázdné pole opět nemůže nastat.** Každý rozměr vícerozměrného pole má
vždy velikost alespoň `1` ([6.2](#62-deklarace-a-inicializace-výchozí-nuly),
saturace „výsledek některého `vyrazX` menší než `1`") — `for` přes
vícerozměrné pole proto, stejně jako jednorozměrná varianta, vždy provede
`tělo` alespoň jednou (pro první, „nejnižší" kombinaci indexů
`(1, 1, ..., 1)`).

**`break`/`continue`.** Beze změny oproti jednorozměrné variantě — `for`
zůstává jediný druh bloku i v podobě pro vícerozměrné pole, se stejným labelem
napříč celým příkazem (žádný z „vnořených" virtuálních dílčích cyklů
z ekvivalentního zápisu výše není samostatně adresovatelný vlastním
labelem). `continue()`/`continue(label)` cílící na tento `for` tedy vždy
provede přesně **jeden krok kaskádového krokování** (bod 4 výše) a poté
znovu otestuje podmínku — ne jen krokování nejvnitřnější proměnné bez
ohledu na přetečení, ale celý kaskádový krok, přesně jako by `tělo`
doběhlo přirozeně. `break()`/`break(label)` cílící na tento `for`
ukončí celou `N`-rozměrnou iteraci najednou, bez ohledu na to, v jak
„hluboko vnořené" virtuální úrovni by se podle ekvivalentního zápisu
právě nacházel.

**Příklad — ekvivalent souhrnného příkladu [6.6](#66-souhrnný-příklad)
zapsaný přes `for`.**

```
var(int, radky, [2])
var(int, sloupce, [3])
var((array, real), matice, ([radky], [sloupce]))

set(matice[1][1], [1.5])
set(matice[1][2], [2.5])
set(matice[1][3], [3.0])
set(matice[2][1], [4.0])
set(matice[2][2], [5.5])
set(matice[2][3], [6.0])

var(real, soucet, [0.0])
var(int, i, [0])
var(int, j, [0])

for((i, j), matice)
    set(soucet, [soucet + matice[i][j]])
end for

var(real, prumer, [soucet / (radky * sloupce)])
```

Kombinace `(i, j)` se vystřídají v pořadí
`(1,1), (1,2), (1,3), (2,1), (2,2), (2,3)` — `j` (poslední, `N`-tá
proměnná) se mění nejrychleji, `i` teprve po jejím přetečení — přesně
odpovídá pořadí, v jakém dvojitý `while` z
[6.6](#66-souhrnný-příklad) procházel prvky. `soucet` skončí na `22.5`,
`prumer` na `3.75`, shodně s [6.6](#66-souhrnný-příklad).

### 4.8 Cyklus s podmínkou na konci (`dowhile`)

Kromě `while` ([4.4](#44-cyklus-s-podmínkou-while)),
`loop` ([4.6](#46-cyklus-s-krokováním-loop))
a `for` ([4.7](#47-cyklus-přes-pole-for))
zavádí BASIX i pátý druh složeného příkazu — cyklus `dowhile`, který
se od `while` liší jen tím, **kdy** se vyhodnocuje jeho podmínka: místo
před každou iterací se u `dowhile` vyhodnocuje až po ní. Stejně jako
`while`/`loop`/`for` má nepovinný label:

```
dowhile(label; [výraz])
tělo
end dowhile
```

Pokud label nepotřebujeme, zapisuje se bez něj a bez středníku —
stejná konvence jako u `while`/`loop`:

```
dowhile([výraz])
tělo
end dowhile
```

kde:

- `label`, je-li uveden, je identifikátor dle
  [3.2](#32-pojmenování-identifikátorů). Zapojuje
  se do **téže společné kolizní množiny labelů** jako `code`, `while`,
  `loop`, `for`, `if` a `case`
  ([4.6](#46-cyklus-s-krokováním-loop),
  [4.7](#47-cyklus-přes-pole-for),
  [4.9](#49-podmíněný-příkaz-if)) — **zobecněné
  (aktuální) znění kolizního pravidla:** pokud vnořený `code(...)`,
  `while(...)`, `loop(...)`, `for(...)`, `dowhile(...)`, `if(...)`, nebo
  `case(...)` blok použije `label`, který už používá kterýkoliv z jeho
  (přímo, nebo nepřímo) obklopujících bloků — v libovolné kombinaci
  těchto sedmi druhů — jde o chybu při kompilaci; souřadné bloky stejný
  `label` sdílet mohou, protože nikdy nejsou aktivní současně. `dowhile`
  bez labelu se do této kolizní kontroly nijak nezapojuje (nemá s čím
  kolidovat).
- `[výraz]` je podmínka cyklu — hranatými závorkami uzavřený výraz dle
  [3.3](#33-syntaxe-výrazů), případně s explicitní
  konverzí `[typ; výraz]` dle
  [3.4](#34-explicitní-konverze-typu) — stejná
  syntaxe podmínky, jakou používá `while`.
- `tělo` je sekvence libovolného počtu (**včetně nuly**) příkazů
  BASIXu — `var(...)`, `set(...)`, vnořený `code(...)`, `while(...)`,
  `loop(...)`, další `dowhile(...)`, `break(...)`, `continue(...)`
  atd. — každý na vlastním řádku dle
  [3.1](#31-oddělování-příkazů).

Jako každý příkaz stojí `dowhile(...)` a `end dowhile` samostatně na
svém řádku. Odsazení `tělo` je, stejně jako u `code`/`while`/`loop`,
čistě vizuální konvence bez vlivu na syntaxi ani sémantiku.

**Sémantika.** Na rozdíl od `while`, kde se `[výraz]` vyhodnocuje
**před** každou iterací, se u `dowhile` vyhodnocuje **po** každé
iteraci:

1. Provede se `tělo` celé, popořadě, od prvního příkazu k poslednímu.
2. Poté se vyhodnotí `[výraz]` a posoudí se jeho pravdivost dle
   pravidla z [2.2](#22-pravdivost) (platí
   jednotně pro `int` i `real`, žádný zvláštní typ podmínky BASIX
   nevyžaduje).
3. Je-li podmínka „true", provede se `tělo` znovu (krok 1), a tak dále.
   Jakmile vyjde „false", cyklus jako celek končí a provádění
   pokračuje prvním příkazem za odpovídajícím `end dowhile`.

**`tělo` se tedy vždy provede alespoň jednou** — bez ohledu na
vyhodnocení `[výraz]` — na rozdíl od `while`
([4.4](#44-cyklus-s-podmínkou-while)), kde se
`tělo` neprovede ani jednou, je-li podmínka nepravdivá hned napoprvé.
To platí i pro prázdné `tělo` (nula příkazů): `dowhile([výraz])`
s prázdným `tělo` opakovaně vyhodnocuje jen `[výraz]` bez jakéhokoliv
dalšího efektu, dokud nevyjde „false" (případně navždy, je-li `[výraz]`
trvale „true") — stejné, deterministické chování jako u `while([1])
end while` bez `break`, jen s podmínkou testovanou na konci místo na
začátku.

Příklad:

```
var(int, i, [0])
dowhile([i < 3])
    set(i, [i + 1])
end dowhile
```

Zde se podmínka `[i < 3]` vyhodnotí celkem třikrát (pro `i` postupně
`1, 2, 3`) a `tělo` proběhne třikrát; po skončení cyklu má `i` hodnotu
`3`. Ve srovnání s obdobným příkladem u `while`
([4.4](#44-cyklus-s-podmínkou-while)), kde se
podmínka testuje čtyřikrát (jednou navíc, na začátku, pro `i = 0`), zde
`dowhile` testuje jen třikrát — pokaždé až po té iteraci, kterou už
umožnila.

Příklad demonstrující rozdíl oproti `while`, kdy je podmínka nepravdivá
hned napoprvé:

```
var(int, x, [0])
dowhile([0])
    set(x, [x + 1])
end dowhile
```

`tělo` přesto proběhne **jednou** — `x` skončí na `1`. Ekvivalentní
`while([0]) ... end while` by tělo neprovedlo ani jednou a `x` by
zůstalo `0`.

**`break`/`continue` u `dowhile`.** `dowhile` se zapojuje do pravidel
`break`/`continue` z
[4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue)
stejně jako `while`, `loop` a `for` — kdekoliv se v té sekci píše
„cyklus", napříště se tím myslí jednotně `while`, `loop`, `for` **i**
`dowhile` (všechny čtyři sdílí stejná pravidla pro `break`/`continue`,
liší se jen tím, co se stane po přeskočení zbytku těla); kdekoliv se
píše „blok" bez upřesnění, myslí se tím kterýkoliv ze **sedmi** druhů —
`code`, `while`, `loop`, `for`, `dowhile`, `if`, `case`.

- **`break(label)`** — `label` smí odpovídat identifikátoru některého
  z lexikálně obklopujících `code(...)`, `while(...)`, `loop(...)`,
  `for(...)`, `dowhile(...)`, `if(...)`, nebo `case(...)` bloků;
  provedení okamžitě ukončí ten blok (a všechny mezilehlé bloky mezi
  místem `break` a ním), jehož `label` se shoduje — u `dowhile`
  cíleného tímto způsobem ukončuje celý cyklus (ne jen aktuální
  iteraci), provádění pokračuje za `end dowhile`.
- **`break()`** — bez argumentu ukončí nejbližší lexikálně obklopující
  cyklus (`while`, `loop`, `for`, nebo `dowhile`), bez ohledu na to, zda
  má, či nemá label — stejně jako u `while`/`loop`/`for`.
- **`continue(label)` / `continue()`** — přeskočí zbytek **aktuální**
  iterace. U `dowhile` (cíleného přímo, nebo přes `label`) to znamená:
  pokračování rovnou vyhodnocením jeho podmínky `[výraz]` — tedy stejné
  místo, kde by se podmínka vyhodnotila i po přirozeném doběhnutí
  `tělo` na konec. Je-li podmínka „true", proběhne další iterace
  `tělo`, jinak cyklus končí stejně jako při běžném konci. `label` u
  `continue(label)` musí, stejně jako u `while`/`loop`/`for`, odpovídat
  identifikátoru některého z lexikálně obklopujících `while(...)`,
  `loop(...)`, `for(...)`, nebo `dowhile(...)` bloků — `code`, `if`, ani
  `case` label zde platným cílem není.

Příklad:

```
var(int, i, [0])
var(int, pokusy, [0])
dowhile([i < 5])
    set(pokusy, [pokusy + 1])
    set(i, [i + 1])
    code(over_tri)
        if([i > 3])
            case(true)
                break(over_tri)
            end case
            case(false)
            end case
        end if
        continue()
    end code
    set(pokusy, [pokusy + 100])
end dowhile
```

Dokud `i <= 3`, `break(over_tri)` se neprovede, ale `continue()` na
konci `code(over_tri)` přeskočí zbylý řádek `set(pokusy, [pokusy +
100])` a rovnou vyhodnotí podmínku `[i < 5]` cyklu `dowhile`. Jakmile
`i` vzroste nad `3` (tedy na `4`), `break(over_tri)` ukončí `code`
blok, čímž se `continue()` už neprovede — provádění pokračuje řádkem
`set(pokusy, [pokusy + 100])` a teprve poté (přirozeným doběhnutím
`tělo` na konec) se vyhodnotí podmínka `dowhile`. Výsledné hodnoty:
`i` skončí na `4`, `pokusy` na `4 + 100 = 104` (čtyři iterace
inkrementovaly `pokusy` o `1`, poslední iterace navíc o `100`, protože
v ní `continue()` neproběhl).

---

### 4.9 Podmíněný příkaz (`if`)

Kromě `code`, `while`, `loop`, `for` a `dowhile` zavádí BASIX ještě
dvojici posledních druhů složeného příkazu — `if` a jemu podřízený
`case` — pro větvení programu podle pravdivosti výrazu (viz
[2.2](#22-pravdivost)):

```
if(label; [výraz])
    case(label; true)
    příkazy větve true
    end case
    case(label; false)
    příkazy větve false
    end case
end if
```

kde:

- `label` u `if`, je-li uveden, je identifikátor dle
  [3.2](#32-pojmenování-identifikátorů), pojmenovávající celý `if`
  příkaz. Zapojuje se do **téže společné kolizní množiny labelů** jako
  `code`, `while`, `loop`, `for` a `dowhile` — viz zobecněné pravidlo
  níže.
- `[výraz]` je hranatými závorkami uzavřený výraz dle
  [3.3](#33-syntaxe-výrazů), případně s explicitní konverzí
  `[typ; výraz]` dle [3.4](#34-explicitní-konverze-typu).
- `tělo` příkazu `if` je na rozdíl od `code`/`while`/`loop` **omezené**:
  smí obsahovat výhradně sekvenci jednoho nebo více `case(...)  ...
  end case` bloků, nic jiného přímo na úrovni `if` psát nelze (běžné
  příkazy typu `var`/`set` je nutné umístit až dovnitř některého
  `case`).
- `case(label; hodnota)` — každý blok uvnitř `if` požaduje jednu ze dvou
  pevně daných hodnot, zapsanou jako holé klíčové slovo (bez `[]`, stejně
  jako `typ` u `var`/explicitní konverze): `true`, nebo `false`. Žádná
  jiná hodnota zde není platná — např. `case(5)` je chyba při kompilaci.
  `label` u `case`, je-li uveden, je opět identifikátor dle
  [3.2](#32-pojmenování-identifikátorů) a zapojuje se do stejné společné
  kolizní množiny jako `label` u `if` (viz níže).
- Pokud label (u `if`, nebo u `case`) nepotřebujeme, zapisuje se bez něj
  a bez středníku — stejná konvence jako u `while`/`loop`:
  `if([výraz])`, `case(true)`.
- `příkazy` uvnitř každého `case` jsou sekvencí libovolného počtu
  (včetně nuly) příkazů BASIXu, stejně jako `tělo` u `code`/`while`/
  `loop`.

Jako každý příkaz stojí `if(...)`, `case(...)`, `end case` a `end if`
samostatně na svém řádku.

**Odsazení.** `case(...) ... end case` bloky se zapisují odsazené
doprava vůči řádkům `if(...)` a `end if`, jejichž jsou přímou součástí —
stejná konvence jako odsazení `tělo` vůči `code(label)`/`end code` v
[4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break) (a
obdobně u `while`/`loop`). Podobně se `příkazy` uvnitř každého `case`
zapisují odsazené doprava vůči jeho vlastním `case(...)`/`end case`.
Jde ale, stejně jako u ostatních složených příkazů, čistě o vizuální
konvenci pro čitelnost — odsazení (jeho přítomnost, míra, ani
konzistence) nemá žádný vliv na syntaxi ani sémantiku programu. Hranice
jednotlivých bloků určují výhradně samotné řádky
`if(...)`/`case(...)`/`end case`/`end if`, stejně jako u vnořených
bloků; odsazení pouze opticky zvýrazňuje vnoření.

**Minimálně jeden `case`, maximálně dva.** `if` musí obsahovat **alespoň
jeden** `case` blok (prázdný `if` bez jediného `case` je chyba při
kompilaci) — ale protože existují jen dvě platné hodnoty (`true`,
`false`) a v rámci jednoho `if` nesmí mít dva jeho přímé `case` bloky
**stejnou hodnotu** (viz níže), plyne z toho, že `if` smí mít **nejvýše
dva** `case` bloky: jeden s hodnotou `true`, jeden s hodnotou `false`.
`if` se dvěma `case` bloky (`true` i `false`) odpovídá klasickému
if/else; `if` s jediným `case` (jen `true`, nebo jen `false`) odpovídá
if bez else, případně if s obráceným smyslem podmínky.

**Kolize hodnot `case` uvnitř jednoho `if` je chyba při kompilaci.** Dva
přímé `case` bloky téhož `if` se stejnou hodnotou (`true`+`true`, nebo
`false`+`false`) jsou chyba při kompilaci — na rozdíl od kolize *labelů*
(viz níže) zde nejde o žádoucí flexibilitu, ale o zamezení nejasnosti,
protože **na pořadí zápisu `case` bloků nezáleží** (viz sémantika níže) a
při duplicitní hodnotě by nebylo definované, který ze dvou stejně
„vhodných" bloků se má provést.

**Sémantika.** `if` se provede nejvýše jednou (na rozdíl od `while`/
`loop`/`dowhile` není iterační, chová se v tomto ohledu jako `code`):

1. `[výraz]` se vyhodnotí přesně jednou a posoudí se jeho pravdivost dle
   [2.2](#22-pravdivost) (jednotně pro `int` i `real`).
2. Mezi přímými `case` bloky `if` se najde ten, jehož hodnota (`true`,
   nebo `false`) odpovídá vyhodnocené pravdivosti — díky pravidlu o
   zákazu kolize hodnot je takový blok nejvýše jeden. Protože na pořadí
   zápisu `case` bloků nezáleží, jde koncepčně o vyhledání podle hodnoty,
   nikoliv o postupné zkoušení jednoho bloku po druhém.
3. Je-li odpovídající `case` nalezen, provedou se jeho `příkazy`
   popořadě — přesně jako `tělo` libovolného jiného složeného příkazu
   (`code`, `while`, `loop`, `dowhile`). Poté (přirozeným doběhnutím na
   `end case`, nebo přes `break`, viz níže) `if` jako celek končí a
   provádění pokračuje prvním příkazem za `end if`. Ostatní
   (nematchující) `case` blok se vůbec neprovede a jeho
   přítomnost/nepřítomnost pravdivost nijak neovlivňuje.
4. Není-li odpovídající `case` nalezen (např. pravdivost je `true`, ale
   `if` obsahuje jen `case(false)`), neprovede se nic a provádění rovnou
   pokračuje prvním příkazem za `end if` — stejně deterministický no-op,
   jako když se `tělo` u `while` neprovede ani jednou.

**Kolize labelů — zobecněné (aktuální) znění.** Od zavedení `if`/`case`
platí kolizní pravidlo z [4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break)/
[4.6](#46-cyklus-s-krokováním-loop)/[4.7](#47-cyklus-přes-pole-for)/
[4.8](#48-cyklus-s-podmínkou-na-konci-dowhile)
obecně pro **všech sedm** druhů pojmenovatelných bloků dohromady
(`code`, `while`, `loop`, `for`, `dowhile`, `if`, `case`): pokud vnořený
blok kteréhokoliv z těchto sedmi druhů použije `label`, který už
používá kterýkoliv z jeho (přímo, nebo nepřímo) obklopujících bloků —
libovolného ze sedmi druhů, v libovolné kombinaci — jde o chybu při
kompilaci. Naopak
**souřadné** (vzájemně nevnořené) bloky, libovolné kombinace druhů,
stejný `label` sdílet mohou, protože nikdy nejsou aktivní současně — to
platí i pro dva `case` bloky téhož `if`: ač smí mít nejvýše jeden z nich
stejnou *hodnotu* (viz výše), stejný *label* mít smí, protože se nikdy
neprovedou oba zároveň.

**Interakce s `break`/`continue`.** `if` ani `case` nejsou iterační
(stejně jako `code`), takže se na ně vztahují jen ty části pravidel z
[4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue), které
se týkají `code`:

- `break(label)` cílící na `label` obklopujícího `if` ukončí celý `if`
  (provádění pokračuje za `end if`) — bez ohledu na to, ze kterého
  `case` byl proveden.
- `break(label)` cílící na `label` obklopujícího `case` ukončí jen tento
  `case` blok (provádění pokračuje za jeho `end case`).
- `continue(label)` ani nepojmenované `break()`/`continue()` nemohou cílit
  na `if`, ani na `case` — stejné omezení jako u `code`
  ([4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue)),
  protože ani jeden z nich nemá pojem iterace.

**Důsledek plynoucí z omezeného těla `if`.** Protože tělo `if` smí
obsahovat výhradně `case` bloky (žádný jiný příkaz přímo na úrovni
`if`), a protože se provede nejvýše jeden `case`, po jehož doběhnutí
(přirozeném i přes `break`) `if` sám okamžitě končí, platí pro *aktuálně
prováděný* `case` zvláštní důsledek: `break(case_label)` cílící na
vlastní label prováděného `case` skončí na **přesně stejném místě**
programu, jako `break(if_label)` cílící na obklopující `if` (obojí vede
rovnou za `end if`, protože za `case` už v těle `if` nic nenásleduje).
Label `case` bloku tedy v aktuální podobě jazyka neslouží k vytvoření
odlišného cíle `break` oproti labelu obklopujícího `if` — jeho smysl je
čistě v tom, umožnit **předčasné** opuštění zbytku `case` těla (např. z
hluboko vnořeného `code`/`while`/`loop`/`if` uvnitř), aniž by bylo nutné
znát/opakovat label `if`.

**Příklad.**

```
var(int, x, [5])
var(int, y, [0])

if(cond; [x > 3])
    case(true)
        set(y, [1])
    end case
    case(false)
        set(y, [-1])
    end case
end if
```

`x` je `5`, tedy `[x > 3]` je pravdivé (`1`); provede se `case(true)` —
`y` dostane `1`. `case(false)` se vůbec neprovede. Po `end if` pokračuje
program s `y = 1`.

**Příklad — vnořený `if` uvnitř `loop`, s `break` do vnějšího cyklu.**

```
var(int, i, [0])
var(int, prvni_sude, [-1])

loop(hledej; i, ([0], [9]))
    if(je_sude; [i % 2])
        case(false)
            set(prvni_sude, [i])
            break(hledej)
        end case
    end if
end loop
```

Zde `if` má jediný `case(false)` (žádný `case(true)`) — `[i % 2]` je
pravdivé (nenulové) pro liché `i`, takže větev se provede právě tehdy,
je-li `i` sudé (`i % 2 == 0`, tedy „false"). Jakmile k tomu poprvé dojde
(`i = 0`), uloží se `prvni_sude = 0` a `break(hledej)` rovnou ukončí
**celý vnější `loop`** (nikoliv jen `if`) — víceúrovňové ukončení přesně
dle [4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue),
kdy mezilehlý `if` (respektive jeho `case(false)`) skončí spolu s
cílovým `loop`.

---

### 4.10 Řetězený podmíněný příkaz (`if(...; first)`)

Kromě dvouhodnotové varianty `if`/`case` z
[4.9](#49-podmíněný-příkaz-if) (kde se větev vybírá podle pravdivostní
*hodnoty* `true`/`false` a pořadí zápisu `case` bloků nehraje roli)
zavádí BASIX i druhou variantu **téhož** páru příkazů `if`/`case` —
řetězené větvení, kde se vykoná **první** `case`, jehož vlastní
podmínka vyjde pravdivá (obdoba `if`/`else if`/`.../else` z jiných
jazyků). Nejde o nový, osmý druh bloku — pouze o druhou variantu
`if`/`case`, odlišenou tím, co následuje za středníkem u `if`:

```
if(label; first)
    case(label; [výraz])
    příkazy
    end case
    case(label; [výraz])
    příkazy
    end case
    case(label)
    příkazy
    end case
end if
```

Pokud label (u `if`, nebo u některého `case`) nepotřebujeme, zapisuje se
bez něj a bez středníku — stejná konvence jako u varianty z
[4.9](#49-podmíněný-příkaz-if):

```
if(first)
    case([výraz])
    příkazy
    end case
    case()
    příkazy
    end case
end if
```

kde:

- `label` u `if`, je-li uveden, je identifikátor dle
  [3.2](#32-pojmenování-identifikátorů). Zapojuje se do stejné, společné
  kolizní množiny labelů jako `code`, `while`, `loop`, `dowhile` a obě
  varianty `if`/`case` dohromady — viz
  [4.9](#49-podmíněný-příkaz-if)/[4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue);
  tato varianta žádnou novou kategorii bloků nezavádí, takže žádné nové
  pravidlo kolize labelů netřeba.
- `first` je holé klíčové slovo (bez `[]`), zapsané na místě, kam
  dvouhodnotová varianta z [4.9](#49-podmíněný-příkaz-if) umísťuje
  `[výraz]` — stejná konvence holého klíčového slova jako `true`/`false`
  u `case`, nebo `typ` u `var`/explicitní konverze. Přítomnost `first`
  (místo `[výraz]`) je jediné a definitivní vodítko, podle kterého
  kompilátor pozná, o kterou ze dvou variant `if` jde — obě varianty
  sdílí klíčové slovo `if`, ale jsou vzájemně nezaměnitelné a nelze je
  kombinovat v rámci jednoho `if(...)`.
- `case` má v této variantě dvě odlišné podoby:
  - **podmíněný `case(label; [výraz])`** — `label` nepovinný, `[výraz]`
    povinný, dle [3.3](#33-syntaxe-výrazů) (případně s explicitní
    konverzí `[typ; výraz]` dle
    [3.4](#34-explicitní-konverze-typu)); takových case bloků smí být
    v rámci jednoho `if` libovolný počet, včetně nuly,
  - **koncový (catch-all) `case(label)`** — `label` nepovinný, žádný
    výraz; nejvýše **jeden** na `if`, sám o sobě nepovinný, ale je-li
    přítomen, musí být syntakticky **posledním** `case` blokem daného
    `if` (viz níže).
- `příkazy` uvnitř každého `case` jsou opět sekvencí libovolného počtu
  (včetně nuly) příkazů BASIXu, stejně jako u varianty z
  [4.9](#49-podmíněný-příkaz-if).

Stejně jako u varianty z [4.9](#49-podmíněný-příkaz-if) je tělo `if`
**omezené**: smí obsahovat výhradně sekvenci `case(...) ... end case`
bloků, žádný jiný příkaz přímo na úrovni `if` psát nelze. Jako každý
příkaz stojí `if(...)`, `case(...)`, `end case` a `end if` samostatně na
svém řádku. Platí i stejné pravidlo odsazení jako u varianty z
[4.9](#49-podmíněný-příkaz-if): `case(...) ... end case` bloky se
zapisují odsazené doprava vůči `if(...)`/`end if` a `příkazy` uvnitř
každého `case` odsazené doprava vůči jeho vlastním
`case(...)`/`end case` — čistě vizuální konvence pro čitelnost, bez
jakéhokoliv vlivu na syntaxi ani sémantiku.

**Minimálně jeden `case`, žádná horní mez.** `if(...; first)` musí
obsahovat **alespoň jeden** `case` blok (prázdný `if` bez jediného
`case` je chyba při kompilaci, stejně jako u [4.9](#49-podmíněný-příkaz-if)).
Na rozdíl od dvouhodnotové varianty ale **neexistuje horní mez** počtu
case bloků — libovolný počet podmíněných `case([výraz])` bloků, plus
nejvýše jeden nepovinný koncový `case()`.

**Koncový `case` musí být poslední — jinak chyba při kompilaci.** Je-li
koncový (bez výrazu) `case` přítomen, musí být zapsán jako syntakticky
**poslední** `case` blok daného `if`. Pokud by byl zapsán jinde (např.
před nějakým podmíněným `case([výraz])`), šlo by o chybu při kompilaci:
jakýkoliv `case` zapsaný za koncovým by byl nedosažitelný mrtvý kód (viz
sémantika níže — koncový `case` se provede vždy, dojde-li na něj řada),
a stejně jako spec u kolize hodnot v [4.9](#49-podmíněný-příkaz-if)
záměrně odmítá takovou nejasnost už při kompilaci, nikoliv jejím
tichým strpěním za běhu. Ze stejného důvodu smí mít jeden `if` **nejvýše
jeden** koncový `case` — druhý koncový `case` by byl rovněž vždy
nedosažitelný, tedy opět chyba při kompilaci.

**Sémantika — na rozdíl od [4.9](#49-podmíněný-příkaz-if) zde na pořadí
zápisu `case` bloků záleží zásadně:**

1. Podmíněné `case` bloky se procházejí v pořadí, v jakém jsou zapsány
   v kódu, shora dolů.
2. Pro aktuálně zkoumaný podmíněný `case` se vyhodnotí jeho `[výraz]` a
   posoudí se jeho pravdivost dle [2.2](#22-pravdivost) (jednotně pro
   `int` i `real`). Vyjde-li „true", provedou se jeho `příkazy`
   popořadě; žádný další `case` (ať podmíněný, nebo koncový) se už
   nezkoumá ani neprovádí — jeho případný výraz se dokonce ani
   nevyhodnotí. Po doběhnutí provedeného `case` (přirozeně, nebo přes
   `break`, viz níže) `if` jako celek ihned končí a provádění pokračuje
   prvním příkazem za `end if`.
3. Vyjde-li „false", pokračuje se dalším `case` blokem v pořadí zápisu
   (opakuje se bod 2).
4. Pokud žádný z podmíněných `case` bloků neodpovídal a je přítomen
   koncový `case`, provedou se vždy jeho `příkazy` (bez jakékoliv další
   podmínky) a `if` končí stejně jako v bodě 2.
5. Pokud žádný podmíněný `case` neodpovídal a koncový `case` chybí,
   neprovede se nic a provádění pokračuje rovnou prvním příkazem za
   `end if` — stejně deterministický no-op jako v odpovídajícím případě
   [4.9](#49-podmíněný-příkaz-if) (bod 4 sémantiky tamní varianty).

**Krátké vyhodnocení (short-circuit).** Jakmile jeden `case` „vyhraje",
žádný z dalších (v pořadí za ním ležících) `case` výrazů se už
nevyhodnocuje — obdoba short-circuit vyhodnocení `and`/`or` z
[2.5](#25-hierarchie-typů-u-binárních-operací). Případné vedlejší
účinky výrazů v nevykonaných `case` blocích (BASIX sám o sobě žádné
vedlejší efekty ve výrazech nedefinuje, ale budoucí rozšíření by na tuto
vlastnost mohla spoléhat) se tedy neprojeví.

**Explicitní srovnání s [4.9](#49-podmíněný-příkaz-if).**

| | dvouhodnotová varianta ([4.9](#49-podmíněný-příkaz-if)) | řetězená varianta (`first`, tato sekce) |
|---|---|---|
| druhý argument `if` | `[výraz]` | holé `first` |
| hodnota `case` | pevné `true`/`false` | libovolný `[výraz]` (podmíněný `case`), nebo žádný (koncový `case`) |
| max. počet `case` | 2 | neomezeno (+ nejvýše 1 koncový) |
| pořadí `case` | nezáleží (match podle hodnoty) | záleží zásadně (first-match-wins) |
| duplicitní/kolidující `case` | chyba (stejná hodnota dvakrát) | chyba (koncový `case` jinde než poslední, nebo dvakrát) |

**Interakce s `break`/`continue`.** Beze změny oproti
[4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue)/
[4.9](#49-podmíněný-příkaz-if) — `if` i `case` zůstávají neiterační bloky
stejné (šesté, resp. sedmé) kategorie ve společné kolizní množině
labelů, tato varianta na tom nic nemění:

- `break(label)` cílící na `label` obklopujícího `if` ukončí celý `if`
  (provádění pokračuje za `end if`) — bez ohledu na to, přes který
  `case` byl proveden.
- `break(label)` cílící na `label` prováděného `case` ukončí jen tento
  `case` blok. Stejně jako u [4.9](#49-podmíněný-příkaz-if) jde funkčně
  o **totéž místo** programu jako `break(if_label)`, protože za `case`
  už v těle `if` nic nenásleduje — label `case` slouží jen k
  předčasnému opuštění zbytku jeho vlastního těla, ne k odlišnému cíli.
- `continue(label)` ani nepojmenované `break()`/`continue()` nemohou
  cílit na `if`, ani na `case` — stejné omezení jako u [4.9](#49-podmíněný-příkaz-if),
  protože ani jeden z nich nemá pojem iterace.

**Příklad.**

```
var(int, skore, [72])
var(int, znamka, [0])

if(hodnoceni; first)
    case([skore >= 90])
        set(znamka, [1])
    end case
    case([skore >= 75])
        set(znamka, [2])
    end case
    case([skore >= 60])
        set(znamka, [3])
    end case
    case()
        set(znamka, [4])
    end case
end if
```

`skore` je `72`. První `case([skore >= 90])` vyjde nepravdivě, druhý
`case([skore >= 75])` také; třetí `case([skore >= 60])` vyjde pravdivě
(`72 >= 60`) — provede se `set(znamka, [3])` a `if` ihned končí. Koncový
`case()` se vůbec nezkoumá ani neprovádí, přestože by (bez ohledu na
`skore`) také „sedl" — na pořadí zde záleží a vítězí první shoda. Po
`end if` má `znamka` hodnotu `3`.

---

### 4.11 Vícenásobný podmíněný příkaz (`if(...; every)`)

BASIX má nyní **tři** varianty téhož páru příkazů `if`/`case`, vzájemně
odlišené tím, co následuje za středníkem u `if`:

| varianta | druhý argument `if` | kolik case bloků se provede |
|---|---|---|
| dvouhodnotová ([4.9](#49-podmíněný-příkaz-if)) | `[výraz]` | nejvýše jeden — vybraný podle hodnoty (`true`/`false`) |
| řetězená ([4.10](#410-řetězený-podmíněný-příkaz-ifthis-first)) | holé `first` | nejvýše jeden — první, jehož vlastní podmínka vyjde pravdivá |
| vícenásobná (tato sekce) | holé `every` | **libovolný počet** — všechny, jejichž vlastní podmínka vyjde pravdivá |

Syntaxe:

```
if(label; every)
    case(label; [výraz])
    příkazy
    end case
    case(label; [výraz])
    příkazy
    end case
    case(label)
    příkazy
    end case
end if
```

Bez labelu:

```
if(every)
    case([výraz])
    příkazy
    end case
    case()
    příkazy
    end case
end if
```

kde:

- `label` u `if`, je-li uveden, je identifikátor dle
  [3.2](#32-pojmenování-identifikátorů), zapojený do stejné, společné
  kolizní množiny labelů jako `code`, `while`, `loop`, `dowhile` a
  všechny tři varianty `if`/`case` dohromady — tato varianta, stejně
  jako `first` v [4.10](#410-řetězený-podmíněný-příkaz-ifthis-first),
  žádnou novou kategorii bloků nezavádí.
- `every` je holé klíčové slovo (bez `[]`), zapsané na místě, kam
  dvouhodnotová varianta umísťuje `[výraz]` a řetězená varianta `first`
  — stejná konvence jako `true`/`false`, `first`, nebo `typ` u
  `var`/explicitní konverze. Všechny tři varianty `if` sdílí klíčové
  slovo `if`, ale jsou vzájemně nezaměnitelné a nelze je kombinovat
  v rámci jednoho `if(...)`.
- `case` má stejné dvě podoby jako u varianty `first`
  ([4.10](#410-řetězený-podmíněný-příkaz-ifthis-first)):
  - **podmíněný `case(label; [výraz])`** — `label` nepovinný, `[výraz]`
    povinný, syntaxe dle [3.3](#33-syntaxe-výrazů)/[3.4](#34-explicitní-konverze-typu);
    libovolný počet, včetně nuly,
  - **koncový (catch-all) `case(label)`** — `label` nepovinný, žádný
    výraz; nejvýše **jeden** na `if`, sám o sobě nepovinný, ale
    je-li přítomen, musí být syntakticky **posledním** `case` blokem
    daného `if` (viz zdůvodnění níže — pozice zde nese význam „vždy
    naposledy", ne otázku nedosažitelnosti jako u [4.10](#410-řetězený-podmíněný-příkaz-ifthis-first)).
- `příkazy` uvnitř každého `case` jsou opět sekvencí libovolného počtu
  (včetně nuly) příkazů BASIXu.

Tělo `if` je stejně **omezené** jako u obou předchozích variant: smí
obsahovat výhradně sekvenci `case(...) ... end case` bloků. Jako každý
příkaz stojí `if(...)`, `case(...)`, `end case` a `end if` samostatně na
svém řádku a platí stejné pravidlo odsazení jako u
[4.9](#49-podmíněný-příkaz-if)/[4.10](#410-řetězený-podmíněný-příkaz-ifthis-first):
`case` bloky odsazené vůči `if`/`end if`, `příkazy` odsazené vůči
vlastnímu `case`/`end case` — čistě vizuální konvence bez vlivu na
syntaxi ani sémantiku.

**Minimálně jeden `case`, žádná horní mez.** Stejně jako u varianty
`first`: `if(...; every)` musí obsahovat alespoň jeden `case` blok
(prázdný `if` je chyba při kompilaci), a neexistuje horní mez počtu
podmíněných case bloků.

**Koncový `case` musí být poslední — jinak chyba při kompilaci.** Důvod
je tu jiný než u varianty `first`: protože `every` provádí *nezávisle*
každý case, jehož podmínka platí, nejde o mrtvý/nedosažitelný kód, kdyby
byl koncový `case` zapsán jinde — ostatní case bloky by se stále mohly
provést. Přesto spec vyžaduje, aby byl zapsán jako poslední, protože
teprve tato pozice dává jednoznačný smysl slovnímu spojení „vykoná se
vždy" — totiž vždy **jako poslední** ze všech case bloků daného `if`,
po vyhodnocení (a případném provedení) všech ostatních. Zápis koncového
case jinam by tuto jednoznačnost porušil (nebylo by jasné, má-li se
provést před, mezi, nebo po ostatních), a je tedy chyba při kompilaci —
stejně jako druhý koncový `case` v jednom `if` (na pozici „poslední"
může být nejvýše jeden blok).

**Sémantika.** Na rozdíl od obou předchozích variant zde `if` neprovede
nejvýše jeden case, ale **libovolný počet** (podle toho, kolik
podmínek vyjde pravdivě), a pořadí case bloků nemá vliv na to, *které*
case bloky se provedou (jen na pořadí, ve kterém se provedou, pokud je
pravdivých víc najednou):

1. Case bloky se procházejí v pořadí, v jakém jsou zapsány v kódu, shora
   dolů.
2. Pro každý **podmíněný** case v tomto pořadí se vyhodnotí jeho
   `[výraz]` a posoudí se jeho pravdivost dle
   [2.2](#22-pravdivost). Na rozdíl od varianty `first` se toto
   vyhodnocení provádí **bez short-circuitu** — ani nalezení pravdivého
   case dříve v pořadí nezabrání vyhodnocení podmínek case bloků, které
   po něm následují.
3. Je-li podmínka „true", provedou se `příkazy` tohoto case bloku celé,
   popořadě — a `if` **nekončí**, pokračuje se (na rozdíl od
   [4.9](#49-podmíněný-příkaz-if)/[4.10](#410-řetězený-podmíněný-příkaz-ifthis-first))
   dalším case blokem v pořadí zápisu (krok 2). Je-li podmínka „false",
   `příkazy` tohoto case bloku se neprovedou a rovnou se pokračuje dalším
   case blokem.
4. Jakmile jsou takto vyčerpány všechny podmíněné case bloky, provedou
   se — je-li přítomen koncový `case` — vždy jeho `příkazy`, bez ohledu
   na to, kolik (i žádný) předchozích case bloků bylo provedeno.
5. Po doběhnutí posledního case bloku (přirozeně, nebo přes `break`, viz
   níže) `if` jako celek končí a provádění pokračuje prvním příkazem za
   `end if`.
6. Pokud žádná z podmínek nevyjde pravdivě a koncový case chybí,
   neprovede se nic — stejně deterministický no-op jako v obou
   předchozích variantách.

**Permutace pořadí podmíněných case bloků nemění, které z nich se
provedou** — každý podmíněný case je vyhodnocen a proveden zcela
nezávisle na ostatních (na rozdíl od `true`/`false` z
[4.9](#49-podmíněný-příkaz-if), kde match vylučuje ostatní hodnoty, nebo
`first` z [4.10](#410-řetězený-podmíněný-příkaz-ifthis-first), kde dřívější
shoda vylučuje pozdější case bloky). Přehození pořadí dvou podmíněných
case bloků tedy může nanejvýš změnit, **v jakém vzájemném pořadí** se
jejich těla provedou (jsou-li oba pravdivé současně) — nikdy ne to, zda
se provedou. Jediná výjimka je koncový case, jehož pozice (nutně
poslední) význam nese, jak vysvětleno výše.

**Interakce s `break`/`continue` — zásadní rozdíl oproti
[4.9](#49-podmíněný-příkaz-if)/[4.10](#410-řetězený-podmíněný-příkaz-ifthis-first).**
V obou předchozích variantách platilo, že `break(case_label)` cílící na
právě prováděný case skončí funkčně na **stejném místě** jako
`break(if_label)`, protože za case v těle if už nic nenásledovalo. U
varianty `every` to **neplatí** — protože za jedním case blokem typicky
následují další (a `if` mezi jednotlivými case bloky nekončí), mají tyto
dva cíle `break` obecně různé důsledky:

- `break(label)` cílící na `label` **case** bloku, ve kterém se právě
  nachází, ukončí jen **tento jeden** case blok (přeskočí zbytek jeho
  `příkazy`) — provádění ale **pokračuje dalším case blokem** v pořadí
  (jeho podmínka se vyhodnotí normálně, případně, jde-li o koncový case,
  provede se bez podmínky), přesně jako by tento case doběhl přirozeně
  na `end case`. `if` jako celek tím **nekončí**.
- `break(label)` cílící na `label` **if** bloku ukončí **celý** `if` —
  přeskočí se i všechny dosud nezpracované case bloky (podmíněné
  i případný koncový, jejichž podmínky se už vůbec nevyhodnotí) a
  provádění pokračuje za `end if`.
- Tyto dva cíle si tedy odpovídají jen ve **zvláštním případě**, kdy je
  aktuálně prováděný case zároveň syntakticky posledním case blokem
  daného `if` (typicky koncový `case`, nebo poslední podmíněný case, není-li
  koncový case přítomen) — tam už žádný další case blok nenásleduje, a
  `break(case_label)` i `break(if_label)` tedy vedou na stejné místo,
  stejně jako tomu bylo vždy u [4.9](#49-podmíněný-příkaz-if)/[4.10](#410-řetězený-podmíněný-příkaz-ifthis-first).
- `continue(label)` ani nepojmenované `break()`/`continue()` nemohou
  cílit na `if`, ani na `case` — stejné omezení jako u obou předchozích
  variant, protože ani jeden z nich nemá pojem iterace.

**Příklad — více současně pravdivých case bloků a vždy prováděný
koncový case.**

```
var(int, n, [15])
var(int, pocet_shod, [0])

if(kontrola; every)
    case([n % 3 == 0])
        set(pocet_shod, [pocet_shod + 1])
    end case
    case([n % 5 == 0])
        set(pocet_shod, [pocet_shod + 1])
    end case
    case()
        set(pocet_shod, [pocet_shod + 10])
    end case
end if
```

`n` je `15` — dělitelné jak `3`, tak `5`. Na rozdíl od varianty `first`
se tu **neděje** žádné „vítězství" prvního case: vyhodnotí se
`[n % 3 == 0]` (true) → `pocet_shod` se zvýší na `1`; vyhodnotí se
`[n % 5 == 0]` (rovněž true, nezávisle na předchozím) → `pocet_shod` se
zvýší na `2`; nakonec se vždy provede koncový case → `pocet_shod` se
zvýší na `12`. Po `end if` má `pocet_shod` hodnotu `12`.

**Příklad — rozdíl mezi `break(case_label)` a `break(if_label)`.**

```
var(int, x, [5])
var(int, y, [0])

if(vyhodnoceni; every)
    case(a; [x > 0])
        set(y, [y + 1])
        break(a)
        set(y, [y + 100])
    end case
    case(b; [x > 3])
        set(y, [y + 1])
    end case
    case()
        set(y, [y + 1])
    end case
end if
```

`x` je `5`. `case(a; [x > 0])` je pravdivý: `set(y, [y + 1])` nastaví
`y = 1`, poté `break(a)` ukončí **jen** case `a` (řádek
`set(y, [y + 100])` se neprovede) — `if` ale nekončí, pokračuje se
case `b`. `case(b; [x > 3])` je rovněž pravdivý: `y` se zvýší na `2`.
Nakonec se vždy provede koncový case: `y` se zvýší na `3`. Po `end if`
má `y` hodnotu `3` — kdyby `break(a)` fungoval jako `break(vyhodnoceni)`
(tedy jako u [4.9](#49-podmíněný-příkaz-if)/[4.10](#410-řetězený-podmíněný-příkaz-ifthis-first)),
`if` by skončil hned po case `a` a `y` by zůstalo na `1`; přesně tento
rozdíl je u varianty `every` nutné mít na paměti.

---

### 4.12 Postupný podmíněný příkaz (`if(...; dive)`)

BASIX má nyní **čtyři** varianty téhož páru příkazů `if`/`case`, vzájemně
odlišené tím, co následuje za středníkem u `if`:

| varianta | druhý argument `if` | kolik case bloků se provede |
|---|---|---|
| dvouhodnotová ([4.9](#49-podmíněný-příkaz-if)) | `[výraz]` | nejvýše jeden — vybraný podle hodnoty (`true`/`false`) |
| řetězená ([4.10](#410-řetězený-podmíněný-příkaz-ifthis-first)) | holé `first` | nejvýše jeden — první, jehož vlastní podmínka vyjde pravdivá |
| vícenásobná ([4.11](#411-vícenásobný-podmíněný-příkaz-ifthis-every)) | holé `every` | libovolný počet — všechny, jejichž vlastní podmínka vyjde pravdivá |
| postupná (tato sekce) | holé `dive` | libovolný počet **od začátku, dokud podmínky vychází pravdivě** — první nepravdivá podmínka celý `if` ukončí |

Syntaxe:

```
if(label; dive)
    case(label; [výraz])
    příkazy
    end case
    case(label; [výraz])
    příkazy
    end case
    case(label)
    příkazy
    end case
end if
```

Bez labelu:

```
if(dive)
    case([výraz])
    příkazy
    end case
    case()
    příkazy
    end case
end if
```

kde:

- `label` u `if`, je-li uveden, je identifikátor dle
  [3.2](#32-pojmenování-identifikátorů), zapojený do stejné, společné
  kolizní množiny labelů jako `code`, `while`, `loop`, `dowhile` a
  všechny čtyři varianty `if`/`case` dohromady — tato varianta, stejně
  jako `first` ([4.10](#410-řetězený-podmíněný-příkaz-ifthis-first)) a
  `every` ([4.11](#411-vícenásobný-podmíněný-příkaz-ifthis-every)),
  žádnou novou kategorii bloků nezavádí.
- `dive` je holé klíčové slovo (bez `[]`), zapsané na místě, kam ostatní
  varianty umísťují `[výraz]`, `first`, nebo `every` — stejná konvence
  jako `true`/`false`, `first`, `every`, nebo `typ` u `var`/explicitní
  konverze. Všechny čtyři varianty `if` sdílí klíčové slovo `if`, ale
  jsou vzájemně nezaměnitelné a nelze je kombinovat v rámci jednoho
  `if(...)`.
- `case` má stejné dvě podoby jako u variant `first` a `every`
  ([4.10](#410-řetězený-podmíněný-příkaz-ifthis-first)/
  [4.11](#411-vícenásobný-podmíněný-příkaz-ifthis-every)):
  - **podmíněný `case(label; [výraz])`** — `label` nepovinný, `[výraz]`
    povinný, syntaxe dle [3.3](#33-syntaxe-výrazů)/[3.4](#34-explicitní-konverze-typu);
    libovolný počet, včetně nuly,
  - **koncový (catch-all) `case(label)`** — `label` nepovinný, žádný
    výraz; nejvýše **jeden** na `if`, sám o sobě nepovinný, ale
    je-li přítomen, musí být syntakticky **posledním** `case` blokem
    daného `if` (viz zdůvodnění níže).
- `příkazy` uvnitř každého `case` jsou opět sekvencí libovolného počtu
  (včetně nuly) příkazů BASIXu, stejně jako u předchozích variant.

Stejně jako u všech předchozích variant je tělo `if` **omezené**: smí
obsahovat výhradně sekvenci `case(...) ... end case` bloků, žádný jiný
příkaz přímo na úrovni `if` psát nelze. Jako každý příkaz stojí
`if(...)`, `case(...)`, `end case` a `end if` samostatně na svém řádku.
Platí i stejné pravidlo odsazení jako u variant `first`/`every`: `case`
bloky odsazené vůči `if`/`end if`, `příkazy` odsazené vůči vlastnímu
`case`/`end case` — čistě vizuální konvence bez vlivu na syntaxi ani
sémantiku.

**Minimálně jeden `case`, žádná horní mez.** `if(...; dive)` musí
obsahovat **alespoň jeden** `case` blok (prázdný `if` bez jediného
`case` je chyba při kompilaci, stejně jako u ostatních variant).
Podmíněných `case([výraz])` bloků smí být libovolný počet, plus nejvýše
jeden nepovinný koncový `case()`.

**Koncový `case` musí být poslední — jinak chyba při kompilaci.**
Koncový `case` nemá žádný výraz, který by mohl řetěz (viz sémantika
níže) ukončit „nepravdivostí" — je tedy jediným blokem v celém `if`,
který se, pokud na něj dojde řada, provede bezpodmínečně. Kdyby byl
zapsán jinam než na konec, byly by case bloky za ním nerozlišitelné od
běžného pokračování řetězu (nic by jim nebránilo v provedení, protože
koncový case žádnou podmínku nemá) — ztratil by se tak jednoznačný
smysl „bezpodmínečně poslední krok". Spec proto, ve shodě s konvencí
zavedenou u [4.10](#410-řetězený-podmíněný-příkaz-ifthis-first) a
[4.11](#411-vícenásobný-podmíněný-příkaz-ifthis-every), takové umístění
zakazuje jako chybu při kompilaci — stejně jako druhý koncový `case`
v jednom `if` (na pozici „poslední" smí být nejvýše jeden blok).

**Sémantika — řetěz podmínek, kde na pořadí zápisu `case` bloků záleží
zásadně a kde (na rozdíl od všech tří předchozích variant) i *pravdivá*
podmínka pouze umožňuje pokračovat, nikoliv provedení ukončuje:**

1. Case bloky (podmíněné i případný koncový) se procházejí v pořadí, v
   jakém jsou zapsány v kódu, shora dolů, počínaje prvním.
2. Pro aktuálně zkoumaný **podmíněný** case se vyhodnotí jeho `[výraz]`
   a posoudí se jeho pravdivost dle [2.2](#22-pravdivost) (jednotně pro
   `int` i `real`).
   - Je-li „true", provedou se jeho `příkazy` popořadě celé — a `if`
     tím **nekončí**: pokračuje se dalším case blokem v pořadí zápisu
     (opět bodem 2, případně bodem 3, jde-li o koncový case).
   - Je-li „false", `příkazy` tohoto case se **neprovedou** a **celý
     `if` ihned končí** — žádný další case (ať podmíněný, nebo koncový)
     se už nezkoumá ani neprovádí, provádění pokračuje prvním příkazem
     za `end if`.
3. Jakmile je (po řadě samých pravdivých podmíněných case blocích)
   dosažen koncový `case` (je-li přítomen), provedou se vždy jeho
   `příkazy` bez jakékoliv podmínky. Po jeho doběhnutí (přirozeně, nebo
   přes `break`, viz níže) `if` jako celek končí a provádění pokračuje
   prvním příkazem za `end if`.
4. Pokud koncový `case` chybí a poslední podmíněný case v pořadí vyšel
   „true" (a byl proveden), `if` končí přirozeně po jeho doběhnutí,
   stejně jako v bodě 3.
5. Pokud je nepravdivý už úplně první case v pořadí, neprovede se nic a
   provádění pokračuje rovnou prvním příkazem za `end if` — stejně
   deterministický no-op jako u ostatních variant.

Jinými slovy: řetěz „se noří" (odtud `dive`) case blokem za case blokem
tak dlouho, dokud každý další podmíněný case vychází pravdivě — obdoba
řetězení `and` z [2.5](#25-hierarchie-typů-u-binárních-operací), jen s
vedlejšími účinky (`příkazy`) prováděnými po cestě u každého úspěšného
článku řetězu, a s bezpodmínečným koncovým krokem, je-li přítomen a je-li
na něj dosaženo.

**Krátké vyhodnocení (short-circuit).** Jakmile jeden podmíněný case
vyjde nepravdivě, žádný z dalších (v pořadí za ním ležících) case výrazů
se už nevyhodnocuje — stejná vlastnost jako u varianty `first`
([4.10](#410-řetězený-podmíněný-příkaz-ifthis-first)), zde ovšem ukončuje
i celý `if`, nikoliv jen hledání „vítěze".

**Explicitní srovnání se zbylými třemi variantami.**

| | dvouhodnotová ([4.9](#49-podmíněný-příkaz-if)) | řetězená (`first`, [4.10](#410-řetězený-podmíněný-příkaz-ifthis-first)) | vícenásobná (`every`, [4.11](#411-vícenásobný-podmíněný-příkaz-ifthis-every)) | postupná (`dive`, tato sekce) |
|---|---|---|---|---|
| druhý argument `if` | `[výraz]` | holé `first` | holé `every` | holé `dive` |
| hodnota `case` | pevné `true`/`false` | libovolný `[výraz]`, nebo žádný (koncový) | libovolný `[výraz]`, nebo žádný (koncový) | libovolný `[výraz]`, nebo žádný (koncový) |
| max. počet case | 2 | neomezeno (+ nejvýše 1 koncový) | neomezeno (+ nejvýše 1 koncový) | neomezeno (+ nejvýše 1 koncový) |
| pořadí case | nezáleží | záleží (first-match-wins) | jen pořadí *provedení*, ne *které* se provedou | záleží zásadně (řetěz, nepravdivost ukončuje) |
| co dělá „true" | vybírá svůj case | ukončí hledání, provede a končí `if` | provede a pokračuje dalším case | provede a pokračuje dalším case |
| co dělá „false" | (pro opačnou hodnotu) vybírá `case(false)` | pokračuje dalším case | přeskočí tento case, pokračuje dalším | **ukončí celý `if`** |

**Interakce s `break`/`continue`.** `if` i `case` zůstávají neiterační
bloky stejné (šesté, resp. sedmé) kategorie ve společné kolizní množině
labelů, stejně jako u předchozích tří variant — s jedním podstatným
rozdílem oproti dvouhodnotové variantě a variantě `first`, a shodou s
variantou `every`:

- `break(label)` cílící na `label` obklopujícího `if` ukončí **celý**
  `if` — provádění pokračuje za `end if`, bez ohledu na to, který case
  byl zrovna prováděn a bez ohledu na to, kolik dalších case bloků by
  jinak v řetězu ještě následovalo.
- `break(label)` cílící na `label` **case** bloku, ve kterém se právě
  nachází, ukončí jen **tento jeden** case blok (přeskočí zbytek jeho
  `příkazy`) — `if` ale tím **nekončí**: přesně jako by tento case
  doběhl přirozeně na `end case`, pokračuje se dalším case blokem v
  řetězu (jeho podmínka se vyhodnotí normálně, případně, jde-li o
  koncový case, provede se bez podmínky). Je to tedy stejné chování,
  jaké má `break(case_label)` u varianty `every`
  ([4.11](#411-vícenásobný-podmíněný-příkaz-ifthis-every)) — **ne**
  chování dvouhodnotové varianty/`first`, kde `break(case_label)` vede
  na stejné místo jako `break(if_label)`, protože tam už za case nic
  nenásledovalo. U `dive` naopak typicky ano (další case v řetězu) — s
  jedinou výjimkou, kdy prováděný case je zároveň syntakticky posledním
  case blokem daného `if` (typicky koncový `case`, nebo poslední
  podmíněný case, není-li koncový case přítomen); tam žádný další case
  blok nenásleduje, a `break(case_label)` i `break(if_label)` tedy vedou
  na stejné místo.
- `continue(label)` ani nepojmenované `break()`/`continue()` nemohou
  cílit na `if`, ani na `case` — stejné omezení jako u ostatních variant,
  protože ani jeden z nich nemá pojem iterace.

**Příklad — řetěz přerušený první nepravdivou podmínkou.**

```
var(int, x, [7])
var(int, y, [0])

if(dive)
    case([x > 0])
        set(y, [y + 1])
    end case
    case([x > 5])
        set(y, [y + 10])
    end case
    case([x > 100])
        set(y, [y + 100])
    end case
    case()
        set(y, [y + 1000])
    end case
end if
```

`x` je `7`. `case([x > 0])` je pravdivý (`y` → `1`), řetěz pokračuje;
`case([x > 5])` je rovněž pravdivý (`y` → `11`), řetěz pokračuje;
`case([x > 100])` je **nepravdivý** — jeho `příkazy` se neprovedou a
**celý `if` tím ihned končí**, včetně koncového `case()`, který se vůbec
nezkoumá. Po `end if` má `y` hodnotu `11`.

**Příklad — rozdíl mezi `break(case_label)` a `break(if_label)` u
`dive`.**

```
var(int, x, [5])
var(int, y, [0])

if(retez; dive)
    case(a; [x > 0])
        set(y, [y + 1])
        break(a)
        set(y, [y + 100])
    end case
    case(b; [x > 3])
        set(y, [y + 1])
    end case
    case()
        set(y, [y + 1])
    end case
end if
```

`x` je `5`. `case(a; [x > 0])` je pravdivý: `set(y, [y + 1])` nastaví
`y = 1`, poté `break(a)` ukončí **jen** case `a` (řádek
`set(y, [y + 100])` se neprovede) — řetěz ale pokračuje case `b`.
`case(b; [x > 3])` je rovněž pravdivý: `y` se zvýší na `2`. Nakonec se
dojde na koncový case, který se provede vždy: `y` se zvýší na `3`. Po
`end if` má `y` hodnotu `3` — kdyby `break(a)` fungoval jako
`break(retez)`, `if` by skončil hned po case `a` a `y` by zůstalo na
`1`; přesně tento rozdíl je, stejně jako u varianty `every`, nutné mít
u `dive` na paměti.

---

## 5. Jednorozměrné pole (`array`)

Toto rozšíření zavádí do BASIXu **jednorozměrné pole** (`array`) jako
nový, souhrnný datový typ vedle skalárních `int` a `real` z [2](#2-datové-typy).
Nemění nic na pravidlech popsaných v předchozích kapitolách — pouze k
nim přidává nový datový typ a s ním související syntaxi.

### 5.1 Přehled

Základní pravidla:

1. **Velikost pole je pevná** — jednou určená při deklaraci, po zbytek
   života proměnné se nemění. Jak přesně se velikost určuje, se ale liší
   podle toho, kterou ze dvou deklaračních variant
   ([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly)
   vs. [5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu))
   použijeme — u varianty A je to hodnota **výrazu** (může tedy záviset i
   na proměnných, ne nutně jen na literálu), u varianty B prostý počet
   hodnot v `{}`.
2. **Všechny prvky jednoho pole mají stejný typ** — `int`, nebo `real`,
   zvolený při deklaraci.
3. **Přístup na index mimo platné meze pole nikdy nevede k UB.** Namísto
   toho se index saturuje na nejbližší platný — viz
   [5.6](#56-index-mimo-meze--saturace).
4. **Indexace od jedné** — platné indexy pole o velikosti `velikost` jsou
   `1, 2, ..., velikost`. Jde o záměrnou odchylku od cílového C++, kde
   jsou pole indexovaná od nuly — kompilátor musí při generování C++
   kódu každý BASIX index před použitím na podkladovém poli snížit o
   `1` (BASIX index `1` odpovídá C++ indexu `0`). Tato konverze je čistě
   implementační detail generovaného kódu, nemění nic na sémantice
   popsané v tomto dokumentu.

### 5.2 Deklarace a inicializace — varianta A (`(array, typ)`, výchozí nuly)

```
var((array, typ), jmeno, [vyraz])
```

kde:

- `(array, typ)` je nový, dvouprvkový **popis typu** v kulatých
  závorkách — `array` je doslovné klíčové slovo označující, že jde o
  pole (nikoliv o skalár), `typ` je `int`, nebo `real`: typ **každého**
  prvku pole.
- `jmeno` je identifikátor pole dle
  [3.2](#32-pojmenování-identifikátorů).
- `[vyraz]` je hranatými závorkami uzavřený výraz dle
  [3.3](#33-syntaxe-výrazů) — na rozdíl od dřívějšího návrhu **nemusí
  jít o literál**: smí obsahovat proměnné i operace, stejně jako
  kterýkoliv jiný `[vyraz]` v jazyce. Jeho výsledná hodnota (po
  implicitní konverzi `real → int` dle
  [2.4](#24-implicitní-konverze-mezi-typy), je-li výraz typu `real`)
  určuje **poslední platný index pole (inclusive)** — protože indexace
  pole začíná od `1` ([5.1](#51-přehled), bod 4), je velikost pole
  rovnou stejné číslo jako tento poslední index, tedy velikost pole je
  `vyraz`.

**Sémantika.** Příkaz zavede nové pole `jmeno` s prvky typu `typ` a
velikostí `vyraz`, a rovnou inicializuje **všechny** prvky výchozí
nulovou hodnotou daného typu — `0` pro `int`, `0.0` pro `real`.

**Výsledek `[vyraz]` menší než `1`.** Pokud by `vyraz` vyšel menší než
`1` (např. `[0]`, nebo záporně), znamenalo by to poslední index menší,
než je vůbec první platný index pole (`1`, [5.1](#51-přehled), bod 4),
tedy pole bez jediného prvku — v duchu zásady „žádný speciální případ,
jednotné pravidlo" ([5.1](#51-přehled), bod 3) se i zde uplatní
saturace: výsledek menší než `1` se saturuje na `1`, takže pole vznikne
vždy s **alespoň jedním** prvkem (poslední index `1`, velikost `1`).

Příklady:

- `var((array, int), a, [4])` → pole `a`, poslední index `4`, tedy
  velikost `4`, prvky typu `int`, všechny `0`.
- `var(int, n, [3])` `var((array, real), b, [n])` → velikost `b` je
  `n = 3`, prvky typu `real`, všechny `0.0`.

### 5.3 Deklarace a inicializace — varianta B (`{hodnoty}`, velikost dle počtu)

```
var((array, typ), jmeno, {hodnota1, hodnota2, ..., hodnotaN})
```

Stejně jako u varianty A
([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly))
jde o běžný, **třech-argumentový** tvar `var(...)` z [4.1](#41-deklarace-a-inicializace-proměnné-var)
— `(array, typ)`, `jmeno` a `{hodnota1, ..., hodnotaN}` jsou tři
oddělené argumenty, žádná další vnější `()` skupina navíc. Jediný
rozdíl oproti variantě A je ve třetím argumentu: místo hranatými
závorkami uzavřeného `[vyraz]` (určujícího poslední index) zde stojí
složenými závorkami uzavřený seznam hodnot `{...}` (určující přímo
obsah pole).

kde:

- `(array, typ)` je stejný, dvouprvkový **popis typu** jako u varianty
  A ([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly))
  — `array` je doslovné klíčové slovo označující pole, `typ` je `int`,
  nebo `real`: typ **každého** prvku pole.
- `jmeno` je identifikátor pole dle
  [3.2](#32-pojmenování-identifikátorů).
- `{hodnota1, ..., hodnotaN}` je čárkami oddělený seznam **alespoň
  jedné** položky ve složených závorkách `{}`. Každá položka je jeden
  ze čtyř tvarů:
  1. přímý **číselný literál** (dle [2.1](#21-základní-typy)) — beze
     změny oproti dosavadnímu pravidlu, bez obalujících `[]`;
  2. **řetězcový literál** v uvozovkách `"..."` (viz níže);
  3. obecný **výraz** dle [3.3](#33-syntaxe-výrazů), obalený vlastní
     dvojicí hranatých závorek `[vyraz]`;
  4. holé **jméno existující proměnné jednorozměrného pole**, obalené
     vlastní dvojicí hranatých závorek `[jmeno_pole]` — bez indexu a
     bez kombinace s čímkoliv dalším uvnitř týchž `[]` (kombinace jako
     `[a + b]` nebo `[a + 1]` zůstávají nedefinované).

**Sémantika — velikost a pořadí.** Velikost výsledného pole je dána
**celkovým počtem hodnot**, které položky seznamu dohromady přispějí,
v pořadí zleva doprava:

- číselný literál a `[vyraz]` (tvary 1 a 3) přispívají vždy přesně
  **jednou** hodnotou;
- řetězcový literál (tvar 2) přispívá **jednou hodnotou na znak** —
  posloupností UTF-32 kódových bodů svých znaků, v pořadí, v jakém se
  vyskytují v literálu;
- `[jmeno_pole]` (tvar 4) přispívá **všemi prvky** odkazovaného pole,
  v jejich indexovém pořadí — funguje tedy jako zkratka za zřetězení.
  Odkazuje-li `jmeno_pole` na **vícerozměrné** pole,
  položka se **zcela vynechá** (nepřispěje žádnou hodnotou; není to
  chyba kompilace).

Počet položek v `{}` (a tedy i to, kolik z nich je řetězcových
literálů či odkazů na pole) je vždy staticky daný ze zdrojového textu
— velikost výsledného pole je tudíž i nadále čistě syntaktická
vlastnost, zjistitelná při kompilaci, stejně jako v dosavadním pravidle
„velikost = počet hodnot v `{}`".

`i`-tá hodnota v takto sestaveném pořadí (počítáno od `1`) inicializuje
prvek na indexu `i` (indexace od jedné, [5.1](#51-přehled), bod 4).

**Typ hodnoty a implicitní konverze.** Každá jednotlivá přispěná
hodnota je v okamžiku svého vzniku typu `int`, nebo `real`:

- číselný literál má typ daný svým zápisem (celočíselný/desetinný);
- znak řetězcového literálu má vždy typ `int` (jeho UTF-32 kódový bod);
- `[vyraz]` má typ daný vyhodnocením výrazu;
- prvek odkazovaného pole `[jmeno_pole]` má typ, jaký byl deklarován
  pro prvky daného pole.

Je-li typ přispěné hodnoty odlišný od deklarovaného `typ` cílového
pole, uplatní se před uložením implicitní konverze na `typ` pole podle
[2.4](#24-implicitní-konverze-mezi-typy) — nezávisle pro každou
jednotlivou hodnotu. Nezávisle na tom se u číselných literálů (tvar 1)
i nadále uplatní případná statická saturace mimo rozsah
`[-2^53, 2^53]` dle [2.3](#23-saturace-přetečení-a-widening), stejně
jako u kteréhokoliv jiného literálu v jazyce; u hodnot vzešlých z
výrazu, řetězce nebo odkazovaného pole (tvary 2–4) je vstup vždy již
v mezích `[-2^53, 2^53]` (viz [2.3](#23-saturace-přetečení-a-widening)
pro výrazy, resp. dále v tomto odstavci pro znaky řetězce), takže
zvláštní saturace zde není potřeba.

**Řetězcový literál.** Uzavřen v uvozovkách `"..."`, podporuje uzavřený
výčet šesti escape sekvencí: `\"`, `\\`, `\n`, `\t`, `\r` a `\uXXXX`
(kódový bod v rozsahu BMP, `U+0000`–`U+FFFF`, zapsaný přesně čtyřmi
hexadecimálními číslicemi, mimo rozsah surrogate polovin
`U+D800`–`U+DFFF`); `\` následované čímkoliv mimo tento výčet je chyba
kompilace. Zdrojový soubor BASIXu je UTF-8 a kompilátor bajty
odpovídající literálu korektně dekóduje na jednotlivé Unicode znaky
(kódové body) bez ohledu na jejich délku v UTF-8 — znaky mimo BMP
(např. emoji) se zapisují přímo jako doslovný znak v literálu, ne
escape sekvencí. Literál smí být zapsán jen na jednom řádku zdrojového
textu — doslovný konec řádku uvnitř `"..."` je chyba, nový řádek v
hodnotě se zapisuje výhradně jako `\n`. Prázdný řetězec `""` je platný
a jako položka seznamu sám o sobě přispívá **nulou** znakových hodnot
— stejně jako `[jmeno_pole]` odkazující na (hypoteticky) prázdné pole.

**Minimální velikost výsledného pole.** Vyjde-li **celkový** počet
hodnot přispěných všemi položkami seznamu `{}` dohromady (viz výše)
roven `0` — což nastává, jen obsahuje-li seznam výhradně prázdné
řetězcové literály a/nebo odkazy na (hypoteticky) prázdná pole — platí
stejná saturace jako u varianty A
([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly)):
výsledné pole vznikne s **alespoň jedním** prvkem, nastaveným na
výchozí nulovou hodnotu deklarovaného `typ` pole (`0` pro `int`, `0.0`
pro `real`). Tím se generalizuje původní pravidlo pro samostatné `""`
(pole velikosti `1` s výchozím prvkem) i na složené případy jako
`{"", ""}` nebo `{[prazdne_pole]}`.

Příklady:

- `var((array, int), c, {10, 20, 30})` → pole `c` o velikosti `3`,
  `c[1] = 10`, `c[2] = 20`, `c[3] = 30`.
- `var((array, int), d, {10, 2.9, 30})` → pole `d` o velikosti `3`,
  prvky typu `int`; prostřední hodnota `2.9` je desetinný literál, tedy
  se implicitně zkonvertuje na `int` (ořezáním desetinné části, dle
  [2.4](#24-implicitní-konverze-mezi-typy)), takže `d[1] = 10`,
  `d[2] = 2`, `d[3] = 30`.
- `var((array, int), jmeno, {"ab"})` → pole velikosti `2`,
  `jmeno[1] = 97` (`'a'`), `jmeno[2] = 98` (`'b'`).
- `var((array, real), x, {"a"})` → pole velikosti `1`, `x[1] = 97.0`
  (implicitní konverze `int → real`).
- `var((array, int), e, {"ab", 10})` → pole velikosti `3`:
  `e[1] = 97`, `e[2] = 98`, `e[3] = 10`.
- `var((array, int), f, {"ab", "cd"})` → pole velikosti `4`:
  `f[1] = 97`, `f[2] = 98`, `f[3] = 99`, `f[4] = 100`.
- `var(int, x, [5])` `var((array, int), a, {[x + 1], 5})` → pole
  velikosti `2`, `a[1] = 6` (hodnota výrazu `x + 1`), `a[2] = 5`.
- `var((array, int), a, {1, 2, 3})` `var((array, int), b, {4, 5})`
  `var((array, int), c, {[a], [b]})` → pole `c` velikosti `5`:
  `c[1..3] = 1, 2, 3` (z `a`), `c[4..5] = 4, 5` (z `b`).

**Návazná rozhodnutí (mimo rozsah tohoto rozšíření, řešená samostatně).**
Tato sekce mění jen to, jak se pole naplní řetězcovým literálem/`{}`
zápisem — ne co s hotovým polem lze dál dělat. Otázky, co s hotovým
polem (typicky řetězcem) dál dělat, byly postupně rozhodnuty takto:

- **Porovnání polí.** Rozšíření operátorů `==`/`!=`
  ([2.5](#25-hierarchie-typů-u-binárních-operací)) o porovnání dvou
  polí jako celku — **vyřešeno**: porovnává se výhradně velikost
  posledního rozměru obou polí, viz
  [6.7](#67-porovnání-polí-operátory-rovnosti).
- **Výstup/tisk.** Jak se pole (řetězec i jiné) dostane ven z
  programu — **vyřešeno** příkazem `print`, viz
  [7](#7-příkaz-pro-výstup-print).
- **Konverze číslo ↔ text.** Funkce nad hotovými hodnotami `int`/`real`
  a hotovým polem, nezávislá na tvaru literálu — **vyřešeno**
  rozšířením `set`, viz
  [5.8](#58-zápis-celého-pole-jako-čísla-textu-nebo-kopie-jiného-pole-set).
- **Zjištění délky.** Obecná funkce/operátor pro zjištění velikosti
  pole za běhu, platná pro všechna pole (číselná i řetězcová) —
  **vyřešeno**: žádná samostatná funkce (`length` apod.) nevzniká,
  místo toho vestavěná funkce `max(jmeno)` (holé jméno pole, bez
  indexu) vrací nejvyšší platný index pole, což je prakticky jeho
  délka (pole je indexováno od jedné, [5.1](#51-přehled), bod 4) —
  viz [9](#9-vestavěné-funkce-maxmin), zejména
  [9.4](#94-sémantika--podoba-nad-polem-poslední-rozměr-holé-jméno).
  Totéž funguje jednotně i pro vícerozměrné pole (mez posledního rozměru,
  s možností zvolit i jiný rozměr), viz
  [9.5](#95-sémantika--podoba-nad-vícerozměrným-polem-konkrétní-rozměr).

### 5.4 Čtení prvku (`jmeno[index]`)

Hodnota prvku pole se čte zápisem:

```
jmeno[index]
```

kde `jmeno` je identifikátor dříve deklarovaného pole a `index` je
výraz dle [3.3](#33-syntaxe-výrazů) (literál, proměnná, nebo operace)
— hranaté závorky bezprostředně za `jmeno` zde slouží zároveň jako
oddělovač indexu.

`jmeno[index]` se do gramatiky výrazu ([3.3](#33-syntaxe-výrazů))
zapojuje jako nový druh **operandu**, rovnocenný s literálem, nebo
proměnnou — lze ho tedy použít kdekoliv, kde je operand očekáván,
včetně vnořeně jako součást složitějšího výrazu. Použije-li se jako
**celý** obsah nějakého `[vyraz]` místa (např. třetí argument `var`,
nebo `set`), platí i nadále obecné pravidlo [3.3](#33-syntaxe-výrazů) —
výraz jako celek musí být obalen vnějšími `[]`, takže výsledný zápis má
dvoje hranaté závorky vedle sebe: vnější (povinný obal hodnoty výrazu)
a vnitřní (index pole), např. `var(int, x, [jmeno[i]])`. Je-li
`jmeno[index]` součástí většího výrazu, obaluje se (spolu s celým
výrazem) jen jednou vnější dvojicí, např. `[jmeno[i] + 1]`.

**Typ indexu.** Je-li `index` typu `real`, uplatní se implicitní
konverze na `int` podle [2.4](#24-implicitní-konverze-mezi-typy)
(ořezání desetinné části) dříve, než se index použije.

**Výsledný typ.** `jmeno[index]` má stejný typ, jaký byl deklarován pro
prvky pole `jmeno` — dále se s ním zachází jako s kterýmkoliv jiným
operandem daného typu (hierarchie
[2.5](#25-hierarchie-typů-u-binárních-operací) atd.).

**Index mimo meze** se saturuje dle [5.6](#56-index-mimo-meze--saturace).

Příklady (pole `c` z
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu),
`c = [10, 20, 30]`):

- `var(int, x, [c[1]])` → `x` dostane `10`.
- `var(int, y, [c[2] + c[3]])` → `y` dostane `50`.

### 5.5 Zápis do prvku (`set(jmeno[index], [výraz])`)

Zápis do konkrétního prvku pole:

```
set(jmeno[index], [vyraz])
```

tedy prakticky `set(jmeno[vyraz_indexu], [vyraz_hodnoty])`, kde:

- `jmeno[index]` je **cíl** zápisu — stejná syntaxe jako u čtení
  ([5.4](#54-čtení-prvku-jmenoindex)), zde ale bez vlastního
  obalujícího `[]` navíc, přesně jako bylo dosud bez obalu bere
  `set(jmeno, [vyraz])` jméno skalární proměnné
  ([4.2](#42-přiřazení-hodnoty-do-proměnné-set)): hranaté závorky
  bezprostředně u `jmeno` jsou index, ne obal hodnoty.
- `[vyraz]` je hranatými závorkami uzavřený výraz dle
  [3.3](#33-syntaxe-výrazů), jehož hodnota se (po implicitní konverzi
  na deklarovaný typ prvků pole, [2.4](#24-implicitní-konverze-mezi-typy))
  zapíše na daný index.

**Sémantika.** Mění se výhradně hodnota jednoho prvku na pozici `index`
— velikost ani typ prvků pole `jmeno` se tímto nikdy nemění.

Příklady (navazují na `c` z
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)):

- `set(c[1], [99])` → `c` = `[99, 20, 30]`.
- `set(c[2], [c[1] + c[3]])` → pravá strana se vyhodnotí **před**
  zápisem (`99 + 30 = 129`), teprve poté se uloží: `c` = `[99, 129, 30]`.

### 5.6 Index mimo meze — saturace

Přístup (čtení i zápis) na index mimo platný rozsah `[1, velikost]`
pole nikdy nevede k UB ([5.1](#51-přehled), bod 3) — index se před
použitím **saturuje** na nejbližší platnou mez, analogicky k saturaci
hodnot u skalárních typů ([2.3](#23-saturace-přetečení-a-widening)):

- `index < 1` → použije se `1` (první prvek).
- `index > velikost` → použije se `velikost` (poslední prvek).
- `index` uvnitř `[1, velikost]` → použije se beze změny.

Pravidlo je jednotné pro čtení (`jmeno[index]`, [5.4](#54-čtení-prvku-jmenoindex))
i zápis (`set(jmeno[index], ...)`, [5.5](#55-zápis-do-prvku-setjmenoindex-výraz)),
bez výjimky.

Příklad (pole `c` o velikosti `3`, platné indexy `1, 2, 3`):

```
set(c[-5], [77])
var(int, x, [c[100]])
```

`set(c[-5], [77])` → index `-5` saturuje na `1`, tedy `c` = `[77, 20, 30]`.
`c[100]` → index `100` saturuje na `velikost = 3`, tedy `x` dostane `30`.

### 5.7 Souhrnný příklad

```
var((array, real), teploty, [4])
set(teploty[1], [21.5])
set(teploty[2], [19.0])
set(teploty[3], [23.25])
set(teploty[4], [teploty[1] + teploty[3]])

var(real, prumer, [(teploty[1] + teploty[2] + teploty[3] + teploty[4]) / 4])
```

`teploty` vznikne variantou A
([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly))
s posledním indexem `4`, tedy velikostí `4` (platné indexy `1`–`4`),
prvky typu `real`, všechny zpočátku `0.0`. Po čtyřech `set` příkazech je
`teploty` = `[21.5, 19.0, 23.25, 44.75]` (poslední prvek je součet
prvního a třetího). `prumer` pak sečte všechny čtyři prvky a vydělí `4`.

### 5.8 Zápis celého pole jako čísla, textu nebo kopie jiného pole (`set`)

Nad rámec zápisu do jednoho prvku
([5.5](#55-zápis-do-prvku-setjmenoindex-výraz)) rozšiřuje `set` i o zápis
do **celého** jednorozměrného pole najednou — cíl bez indexu za jménem,
stejně jako u skalárního `set(jmeno, [vyraz])`
([4.2](#42-přiřazení-hodnoty-do-proměnné-set)). Řeší otázku „konverze
číslo ↔ text" ze
[souhrnu otevřených rozhodnutí v 5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu):
místo samostatných funkcí (`text(...)`, `number(...)`) se přidávají tři
nové kombinace cíl/zdroj `set`, rozlišené — stejně jako dnes u `input`
([8](#8-příkaz-pro-vstup-input)) — podle **deklarovaného typu** jména
prvního argumentu:

**A) `set(pole, [vyraz])` — cíl pole (bez indexu), zdroj skalární výraz.**

```
set(pole, [vyraz])
```

`vyraz` se vyhodnotí běžně dle [3.3](#33-syntaxe-výrazů) na skalární
`int`/`real`. Výsledek se zformátuje **stejnými pravidly jako `print`**
([7.3](#73-sémantika)) — `int` jako desítkový zápis, `real` jako
nejkratší round-trip zápis, vždy s `.0` u celočíselné hodnoty — a
takto zformátovaný text se uloží do `pole` **stejnou konvencí jako
`input(pole)`** ([8.3](#83-sémantika)): velikost `pole` je pevná a
nemění se; je-li text kratší, zbylé prvky pole se nastaví na výchozí
nulovou hodnotu deklarovaného typu pole; je-li text delší, uloží se jen
prvních `velikost` znaků a zbytek se zahodí.

Příklad: `var((array, int), buf, [5])` `set(buf, [42])` → text `"42"`
(dva znaky) se uloží do pole velikosti `5`: `buf[1] = 52` (`'4'`),
`buf[2] = 50` (`'2'`), `buf[3..5] = 0` (doplnění nulou).

Je-li `pole` vícerozměrné, platí totéž, jen se prvky
pole berou v **linearizovaném pořadí** místo prostého `1..velikost` —
viz [6.8](#68-implicitní-konverze-mezi-poli-a-mezi-polem-a-skalárem).

**B) `set(promenna, [pole])` — cíl skalár, zdroj holé jméno pole.**

```
set(promenna, [pole])
```

`pole` (bez indexu) se čte jako text — UTF-32 znaky, stejná konvence
jako u řetězcového literálu ([5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu))
— a parsuje se **stejnými pravidly jako `input` do skaláru**
([8.3](#83-sémantika)): přeskočí se úvodní bílé znaky a rozpozná se
nejdelší úvodní část tvořící platnou hodnotu deklarovaného typu
`promenna` (`int`, nebo `real`, dle [3.3](#33-syntaxe-výrazů)); zbytek
obsahu pole se pro tento zápis ignoruje. Na rozdíl od `input` ale
nejde o spotřebování vstupního streamu — pole samotné zůstává touto
operací **beze změny**. Neplatný, nebo prázdný rozpoznatelný obsah
vede na výchozí nulovou hodnotu (`0`/`0.0`) `promenna`, stejně jako u
neplatného vstupu u `input`; rozpoznaná hodnota mimo rozsah
`[-2^53, 2^53]` saturuje na příslušnou mez, stejně jako všude jinde v
jazyce ([2.3](#23-saturace-přetečení-a-widening)).

Příklad: `var((array, int), text, {"123"})` `var(int, n, [0])`
`set(n, [text])` → `n = 123`.

Je-li `pole` vícerozměrné, platí totéž, jen se prvky
pole čtou v **linearizovaném pořadí** — viz
[6.8](#68-implicitní-konverze-mezi-poli-a-mezi-polem-a-skalárem).
Částečná indexace (např. jen `pole[i]` u vícerozměrného pole) zůstává
zakázaná dle [6.3](#63-čtení-prvku-jmenovyrazvyraz) beze změny — tady
se vždy bere pole jako **celek**.

**C) `set(pole1, [pole2])` — cíl i zdroj pole, kopírování hodnot.**

```
set(pole1, [pole2])
```

Doplňkové rozšíření nad rámec původní otázky „číslo ↔ text": kopírují
se **hodnoty prvků přímo**, ne jejich textová interpretace — s
implicitní konverzí `int ↔ real` dle
[2.4](#24-implicitní-konverze-mezi-typy) prvek po prvku, liší-li se
deklarovaný typ prvků `pole1` a `pole2`. Velikost `pole1` je pevná a
nemění se; platí stejná konvence jako v bodech A a B výše — je-li
`pole2` kratší než `pole1`, zbylé prvky `pole1` se nastaví na výchozí
nulovou hodnotu jeho typu; je-li `pole2` delší, přebytek se zahodí.

Tento tvar platí pro **libovolnou kombinaci** jednorozměrného a
vícerozměrného pole u `pole1` a `pole2` (obě jednorozměrná, jedno
jednorozměrné a druhé vícerozměrné, nebo obě vícerozměrná) — je-li
alespoň jedna strana vícerozměrná,
„velikost"/„kratší"/„delší" výše se rozumí ve smyslu **linearizovaného**
počtu a pořadí prvků, ne tvaru/počtu rozměrů; tvar obou stran se
nemusí shodovat vůbec. Podrobně viz
[6.8](#68-implicitní-konverze-mezi-poli-a-mezi-polem-a-skalárem).

Příklad: `var((array, int), a, {1, 2, 3})` `var((array, int), b, [5])`
`set(b, [a])` → `b = [1, 2, 3, 0, 0]`.

**Zdůvodnění.** Řešení znovu používá už zavedené, otestované mechanismy
(`print`ovo formátování, `input`ovo parsování a jeho ořez/doplnění
nulou u polí) místo zavádění nových, samostatných funkcí — `set` se tak
stává jednotným místem pro veškeré přiřazení, jehož konkrétní chování
se řídí deklarovaným typem cíle a zdroje, stejně jako je to dnes
zavedené u `input`.

---

## 6. Vícerozměrné pole

Toto rozšíření zavádí do BASIXu **vícerozměrné pole** jako zobecnění
jednorozměrného pole
([5](#5-jednorozměrné-pole-array)) na libovolný počet rozměrů. Oproti
jednorozměrnému poli má vícerozměrné pole jedinou deklarační formu — bez
varianty s výčtem počátečních hodnot analogické k
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)
— jinak z něj beze změny přejímá všechny základní principy (žádné UB,
saturace indexu mimo meze, indexace od jedné).

### 6.1 Přehled

Základní pravidla vícerozměrného pole zobecňují pravidla jednorozměrného pole
([5.1](#51-přehled)) na libovolný počet rozměrů `D`:

1. **Tvar pole je pevný** — jednou určený při deklaraci
   ([6.2](#62-deklarace-a-inicializace-výchozí-nuly)), po zbytek
   života proměnné se nemění. Tvarem se rozumí uspořádaná `D`-tice
   velikostí jednotlivých rozměrů.
2. **Všechny prvky jednoho pole mají stejný typ** — `int`, nebo `real`,
   zvolený při deklaraci (stejně jako u [5.1](#51-přehled), bod 2),
   nezávisle na počtu rozměrů.
3. **Přístup na index mimo platné meze nikdy nevede k UB** — namísto
   toho se index v příslušném rozměru saturuje na nejbližší platný
   (viz [6.5](#65-index-mimo-meze--saturace)), stejně jako u
   [5.1](#51-přehled), bod 3.
4. **Indexace je stejná jako u jednorozměrného pole** — v každém
   rozměru zvlášť platí indexace od jedné
   ([5.1](#51-přehled), bod 4): pro rozměr o velikosti `velikost` jsou
   platné indexy `1, 2, ..., velikost`. Žádný rozměr nemá vlastní,
   odlišnou konvenci — pravidlo je napříč všemi rozměry jednotné a
   shoduje se s pravidlem pro 1D pole.

### 6.2 Deklarace a inicializace (výchozí nuly)

```
var((array, typ), jmeno, ([vyraz1], [vyraz2], ..., [vyrazD]))
```

kde:

- `(array, typ)` je **stejný**, dvouprvkový popis typu jako u
  jednorozměrného pole
  ([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly))
  — `array` je doslovné klíčové slovo označující, že jde o pole, `typ`
  je `int`, nebo `real`: typ **každého** prvku pole. Popis typu sám o
  sobě **neurčuje počet rozměrů** — ten je (viz níže) dán až třetím
  argumentem `var(...)`, nikoliv typem.
- `jmeno` je identifikátor pole dle pravidel
  [3.2](#32-pojmenování-identifikátorů).
- třetí argument je nová syntaktická forma: kulatými závorkami `()`
  uzavřený, čárkami oddělený seznam **alespoň jednoho** hranatými
  závorkami uzavřeného výrazu — `([vyraz1], [vyraz2], ..., [vyrazD])`.
  Každý `vyrazX` je výraz dle [3.3](#33-syntaxe-výrazů) (smí obsahovat
  proměnné i operace, nemusí jít o literál), jehož výsledná hodnota (po
  implicitní konverzi `real → int` dle
  [2.4](#24-implicitní-konverze-mezi-typy), je-li výraz typu `real`)
  určuje **poslední platný index v X-tém rozměru pole (inclusive)** —
  analogicky k jedinému `[vyraz]` u jednorozměrného pole
  ([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly)),
  jen zde platí zvlášť pro každý rozměr.

  Vnější `()` zde **nejsou** obyčejné seskupovací závorky operátorů
  ([2.6](#26-priorita-a-asociativita-operátorů)) — jde o samostatnou
  syntaktickou konstrukci třetího argumentu `var(...)`, po vzoru
  `{hodnota1, ..., hodnotaN}` u varianty B jednorozměrného pole
  ([5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)):
  místo výčtu literálů oddělených čárkou zde stojí výčet `[vyraz]`
  bloků oddělených čárkou.

**Počet rozměrů.** Počet rozměrů pole `jmeno` je dán **počtem**
`[vyraz]` bloků v třetím argumentu — značme jej `D`. Zápis
`([vyraz])` s jediným blokem je **stejný, 1D případ** jako
`var((array, typ), jmeno, [vyraz])` z
[5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly)
— obě syntaxe jsou pro `D = 1` plně rovnocenné, nejde jen o formální
podobnost, ale o identický zápis stejné věci (jednoprvková n-tice
`([vyraz])` a holé `[vyraz]` znamenají totéž). `([vyraz1], [vyraz2])`
je 2D pole, `([vyraz1], [vyraz2], [vyraz3])` je 3D pole atd.

**Horní mez počtu rozměrů `D`.** `D` je omezeno nejvyšší hodnotou typu
`int`, tedy `2^53` (viz [2.1](#21-základní-typy)) — stejná magnituda,
kterou tato specifikace používá jako mez pro hodnoty samotné, se tak
uplatňuje i na počet rozměrů pole. Jde o čistě formální (v praxi
nedosažitelnou) horní mez, spíš než o reálné praktické omezení.

**Tvar pole.** Uspořádaná `D`-tice posledních indexů
`(vyraz1, vyraz2, ..., vyrazD)` — po implicitní konverzi na `int` —
určuje **tvar** pole: velikost v `i`-tém rozměru je rovna `vyrazI`
(stejný vztah jako u 1D pole v
[5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly),
jen zde nezávisle pro každý rozměr). Pořadí rozměrů v tomto seznamu je
zároveň pořadí, v jakém se rozměry budou uvádět při indexaci (viz
[6.3](#63-čtení-prvku-jmenovyrazvyraz) — indexace je stejná jako u
jednorozměrného pole, viz [6.1](#61-přehled), bod 4).

**Sémantika.** Příkaz zavede nové pole `jmeno` s prvky typu `typ`,
počtem rozměrů `D` a tvarem daným výše zmíněnou `D`-ticí, a rovnou
inicializuje **všechny** prvky (ve všech rozměrech) výchozí nulovou
hodnotou daného typu — `0` pro `int`, `0.0` pro `real` — stejně jako
varianta A jednorozměrného pole
([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly)).

**Výsledek některého `vyrazX` menší než `1`.** Stejně jako u
jednorozměrného pole
([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly))
platí zásada „žádný speciální případ, jednotné pravidlo": je-li
výsledek některého `vyrazX` menší než `1`, saturuje se **nezávisle na
ostatních rozměrech** na `1` — velikost pole v tomto rozměru je tedy
vždy alespoň `1`, bez ohledu na to, jak velké jsou ostatní rozměry.
Jde o pravidlo aplikované na každý rozměr samostatně, nikoliv na pole
jako celek.

Příklady:

- `var((array, int), a, ([3], [4]))` → dvourozměrné pole `a`, tvar
  `3×4` (poslední indexy `3` a `4` ve svých rozměrech), prvky typu
  `int`, všechny `0`.
- `var(int, n, [3])` `var((array, real), b, ([n], [5], [2]))` →
  trojrozměrné pole `b`, tvar `3×5×2` (první rozměr určen proměnnou
  `n`), prvky typu `real`, všechny `0.0`.
- `var((array, int), c, ([0], [5]))` → první rozměr saturuje na `1`
  (výsledek `0` je menší než `1`), druhý zůstává `5` beze změny —
  tvar `c` je tedy `1×5`, nikoliv pole bez prvků.

### 6.3 Čtení prvku (`jmeno[vyraz][vyraz]...`)

Hodnota prvku `D`-rozměrného pole se čte zápisem:

```
jmeno[vyraz1][vyraz2]...[vyrazD]
```

kde `jmeno` je identifikátor dříve deklarovaného vícerozměrného pole
([6.2](#62-deklarace-a-inicializace-výchozí-nuly)) s počtem rozměrů
`D`, a každé `vyrazX` je výraz dle [3.3](#33-syntaxe-výrazů) (literál,
proměnná, nebo operace) — hranaté závorky bezprostředně za `jmeno`, a
každá další skupina hranatých závorek bezprostředně za předchozí, zde
slouží jako oddělovač indexu v příslušném rozměru, v pořadí, v jakém
byly rozměry určeny při deklaraci
([6.2](#62-deklarace-a-inicializace-výchozí-nuly)).

**Počet indexů musí odpovídat `D`.** Počet takto zřetězených
`[vyrazX]` bloků musí přesně odpovídat počtu rozměrů `D` pole `jmeno`
— jinak jde o chybu při kompilaci. Na rozdíl od jednorozměrného pole
([5.4](#54-čtení-prvku-jmenoindex)), kde jediný blok `[index]`
jednoznačně odpovídá jedinému rozměru, je zde nutné uvést index pro
**každý** rozměr zvlášť; žádné částečné indexování (např. jen
`jmeno[i]` u dvourozměrného pole) není povoleno.

`jmeno[vyraz1]...[vyrazD]` se do gramatiky výrazu
([3.3](#33-syntaxe-výrazů)) zapojuje jako nový druh **operandu**,
rovnocenný s literálem, proměnnou, nebo `jmeno[index]` u
jednorozměrného pole ([5.4](#54-čtení-prvku-jmenoindex)) — lze ho tedy
použít kdekoliv, kde je operand očekáván, včetně vnořeně jako součást
složitějšího výrazu. Použije-li se jako **celý** obsah nějakého
`[vyraz]` místa (např. třetí argument `var`, nebo `set`), platí i
nadále obecné pravidlo [3.3](#33-syntaxe-výrazů) — výraz jako celek
musí být obalen vnějšími `[]`, takže výsledný zápis má vedle sebe
vnější (povinný obal hodnoty výrazu) a `D` vnitřních (indexy
jednotlivých rozměrů) hranatých závorek, např.
`var(int, x, [jmeno[i][j]])`. Je-li `jmeno[vyraz1]...[vyrazD]`
součástí většího výrazu, obaluje se (spolu s celým výrazem) jen jednou
vnější dvojicí, např. `[jmeno[i][j] + 1]`.

**Typ indexu.** Je-li některé `vyrazX` typu `real`, uplatní se před
jeho použitím implicitní konverze na `int` dle
[2.4](#24-implicitní-konverze-mezi-typy) (ořezání desetinné části) —
nezávisle pro každý index zvlášť, stejně jako u jednorozměrného pole
([5.4](#54-čtení-prvku-jmenoindex)).

**Výsledný typ.** `jmeno[vyraz1]...[vyrazD]` má stejný typ, jaký byl
deklarován pro prvky pole `jmeno` — dále se s ním zachází jako
s kterýmkoliv jiným operandem daného typu (hierarchie
[2.5](#25-hierarchie-typů-u-binárních-operací) atd.).

**Index mimo meze** se v každém rozměru saturuje nezávisle dle
[6.5](#65-index-mimo-meze--saturace).

Příklady (pole `m` z
[6.2](#62-deklarace-a-inicializace-výchozí-nuly), tvar `3×4`, typ
`int`, všechny prvky zatím `0`):

- `var(int, x, [m[1][1]])` → `x` dostane `0`.
- `var(int, i, [2])` `var(int, j, [3])` `var(int, y, [m[i][j]])` → `y`
  dostane `0` — pole `m` je zatím celé nulové, zápis do prvku
  zavedeme až v [6.4](#64-zápis-do-prvku-setjmenovyrazvyraz-vyraz).

### 6.4 Zápis do prvku (`set(jmeno[vyraz][vyraz], [vyraz])`)

Zápis do konkrétního prvku `D`-rozměrného pole:

```
set(jmeno[vyraz1][vyraz2]...[vyrazD], [vyraz])
```

tedy prakticky
`set(jmeno[vyraz_indexu1]...[vyraz_indexuD], [vyraz_hodnoty])`, kde:

- `jmeno[vyraz1]...[vyrazD]` je **cíl** zápisu — stejná syntaxe (a
  stejná pravidla — počet indexů musí odpovídat `D`, typ indexu, atd.)
  jako u čtení ([6.3](#63-čtení-prvku-jmenovyrazvyraz)), zde ale bez
  vlastního obalujícího `[]` navíc, přesně jako je bez obalu i cíl
  zápisu do skalární proměnné
  ([4.2](#42-přiřazení-hodnoty-do-proměnné-set)), i cíl zápisu do
  prvku jednorozměrného pole
  ([5.5](#55-zápis-do-prvku-setjmenoindex-výraz)): hranaté závorky
  bezprostředně u `jmeno` jsou indexy, ne obal hodnoty.
- `[vyraz]` je hranatými závorkami uzavřený výraz dle
  [3.3](#33-syntaxe-výrazů), jehož hodnota se (po implicitní konverzi
  na deklarovaný typ prvků pole, [2.4](#24-implicitní-konverze-mezi-typy))
  zapíše na daný index ve všech `D` rozměrech.

**Sémantika.** Mění se výhradně hodnota jednoho prvku na pozici
`(vyraz1, ..., vyrazD)` — tvar (velikost v žádném rozměru), ani typ
prvků pole `jmeno` se tímto nikdy nemění, stejně jako u
jednorozměrného pole ([5.5](#55-zápis-do-prvku-setjmenoindex-výraz)).

Příklady (pole `m` z
[6.2](#62-deklarace-a-inicializace-výchozí-nuly), tvar `3×4`, typ
`int`, zatím celé `0`):

- `set(m[1][1], [99])` → prvek na pozici `(1, 1)` dostane `99`,
  ostatní prvky zůstávají `0`.
- `set(m[2][3], [m[1][1] + 1])` → pravá strana se vyhodnotí **před**
  zápisem (`99 + 1 = 100`, díky předchozímu příkladu), teprve poté se
  uloží na pozici `(2, 3)`.

### 6.5 Index mimo meze — saturace

Saturace indexu mimo platný rozsah u vícerozměrného pole funguje **stejně
jako u jednorozměrného pole** ([5.6](#56-index-mimo-meze--saturace))
— pravidlo se jen uplatňuje **nezávisle v každém rozměru zvlášť**,
podle velikosti daného rozměru z tvaru pole
([6.2](#62-deklarace-a-inicializace-výchozí-nuly)):

- `vyrazX < 1` → použije se `1` (první prvek daného rozměru).
- `vyrazX > velikostX` → použije se `velikostX` (poslední prvek
  daného rozměru), kde `velikostX` je velikost `X`-tého rozměru dle
  [6.2](#62-deklarace-a-inicializace-výchozí-nuly).
- `vyrazX` uvnitř `[1, velikostX]` → použije se beze změny.

Pravidlo je jednotné pro čtení
(`jmeno[vyraz1]...[vyrazD]`, [6.3](#63-čtení-prvku-jmenovyrazvyraz)) i
zápis (`set(jmeno[vyraz1]...[vyrazD], ...)`,
[6.4](#64-zápis-do-prvku-setjmenovyrazvyraz-vyraz)), bez výjimky — a
každý index v `D`-tici se posuzuje vůči mezím **svého vlastního**
rozměru, zcela nezávisle na tom, jak vyšly (nebo saturovaly) indexy
ostatních rozměrů.

Příklad (pole `m` z
[6.2](#62-deklarace-a-inicializace-výchozí-nuly), tvar `3×4`, platné
indexy `1..3` v prvním a `1..4` ve druhém rozměru):

```
set(m[-5][2], [77])
var(int, x, [m[100][2]])
```

`set(m[-5][2], [77])` → index prvního rozměru `-5` saturuje na `1`,
index druhého rozměru `2` zůstává beze změny, tedy se zapíše na
pozici `(1, 2)`. `m[100][2]` → index prvního rozměru `100` saturuje na
`velikost1 = 3`, druhý zůstává `2`, tedy `x` dostane hodnotu prvku na
pozici `(3, 2)`.

### 6.6 Souhrnný příklad

```
var(int, radky, [2])
var(int, sloupce, [3])
var((array, real), matice, ([radky], [sloupce]))

set(matice[1][1], [1.5])
set(matice[1][2], [2.5])
set(matice[1][3], [3.0])
set(matice[2][1], [4.0])
set(matice[2][2], [5.5])
set(matice[2][3], [6.0])

var(real, soucet, [0.0])
var(int, i, [1])
var(int, j, [1])
while([i <= radky])
    set(j, [1])
    while([j <= sloupce])
        set(soucet, [soucet + matice[i][j]])
        set(j, [j + 1])
    end while
    set(i, [i + 1])
end while

var(real, prumer, [soucet / (radky * sloupce)])
```

`matice` vzniká deklarací z
[6.2](#62-deklarace-a-inicializace-výchozí-nuly) s tvarem daným
proměnnými `radky = 2` a `sloupce = 3`, tedy `2×3` prvků typu `real`,
všechny zpočátku `0.0`. Šest příkazů `set(matice[i][j], [...])` naplní
všechny prvky pole
([6.4](#64-zápis-do-prvku-setjmenovyrazvyraz-vyraz)), takže `matice`
je:

```
[1.5  2.5  3.0]
[4.0  5.5  6.0]
```

Vnořený pár `while` cyklů ([4.4](#44-cyklus-s-podmínkou-while))
postupně projde všechny dvojice `(i, j)` v platném rozsahu obou
rozměrů a pomocí čtení `matice[i][j]`
([6.3](#63-čtení-prvku-jmenovyrazvyraz), s proměnnými jako indexy)
sečte všech `6` prvků do `soucet`; žádný z indexů `i`, `j` se v tomto
příkladu nedostane mimo meze, takže se saturace z
[6.5](#65-index-mimo-meze--saturace) vůbec neuplatní. Po skončení
obou cyklů má `soucet` hodnotu `22.5`. Výraz `radky * sloupce` (oba
`int`) dá `6`; dělení `real` hodnoty `soucet` tímto `int` výsledkem
promuje `6` na `real` podle hierarchie
[2.5](#25-hierarchie-typů-u-binárních-operací), takže `prumer`
nakonec dostane `3.75`.

### 6.7 Porovnání polí operátory rovnosti

Operátory `==` a `!=` ([2.5](#25-hierarchie-typů-u-binárních-operací),
[2.6](#26-priorita-a-asociativita-operátorů)) lze nově použít i nad
dvěma **holými jmény polí** — jednorozměrných (`array`,
[5](#5-jednorozměrné-pole-array)), vícerozměrných
([6](#6-vícerozměrné-pole)), i v libovolné vzájemné
kombinaci obou. Dosud šlo o chybu kompilace (jméno pole samo o sobě
nebylo platným operandem); řeší otázku „porovnání polí" ze
[souhrnu otevřených rozhodnutí v 5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu).

**Pravidlo.** `a == b` (resp. `a != b`), kde `a` i `b` jsou holá jména
existujících polí, porovnává **výhradně velikost jejich posledního
rozměru** — nikoliv obsah/hodnoty jednotlivých prvků:

- U jednorozměrného `array` je „poslední rozměr" totéž co jediný
  rozměr pole, tedy jeho celková velikost — pravidlo se tak na `array`
  chová jako prosté porovnání celkové velikosti.
- U vícerozměrného pole se bere v úvahu **jen** velikost posledního rozměru;
  všechny předchozí rozměry (a případný nesoulad v počtu rozměrů `D`
  mezi oběma poli, [6.1](#61-přehled)) se ignorují.
- Jde o jedno jednotné pravidlo napříč oběma druhy pole — `array` je
  z tohoto pohledu jen speciální případ vícerozměrného pole s `D = 1`.
- Deklarovaný typ prvků (`int`, nebo `real`) roli nehraje — porovnává
  se jen velikost, nikoliv obsah, takže žádná konverze prvek po prvku
  není potřeba. `(array, int)` lze tedy bez omezení porovnat s
  `(array, real)`, bez ohledu na počet rozměrů obou stran.
- Pole různé délky posledního rozměru jsou automaticky **nerovná**
  (`!=` pravda) — nejde o chybu za běhu ani o chybu kompilace.
- Smíšené porovnání jednorozměrného a vícerozměrného pole je výslovně povoleno:
  jednorozměrné `array` o velikosti `5` je rovno libovolnému
  vícerozměrnému poli (nezávisle na počtu rozměrů `D`), jehož poslední
  rozměr má velikost `5`.

Výsledkem je, stejně jako u skalárního porovnání
([2.5](#25-hierarchie-typů-u-binárních-operací)), vždy `int` hodnota
`0`/`1` — žádná saturace se neuplatňuje.

Příklady:

- `var((array, int), a, {1, 2, 3})` `var((array, real), b, {9.0, 9.0, 9.0})`
  `[a == b]` → `1` (obě velikosti `3`, obsah se neporovnává).
- `var((array, int), c, {1, 2})` `[a == c]` (`a` z předchozího příkladu,
  velikost `3`) → `0`; `[a != c]` → `1`.
- `var((array, int), m, ([2], [3]))` (tvar `2×3`, poslední rozměr
  velikost `3`) `[a == m]` (`a` velikost `3`) → `1`, bez ohledu na to,
  že `a` je jednorozměrné a `m` dvourozměrné.

**Zdůvodnění.** Porovnávat pole podle velikosti posledního rozměru je
jednoduché, jednoznačné a levné pravidlo — nevyžaduje procházet ani
konvertovat obsah prvků, funguje jednotně napříč jednorozměrným i vícerozměrným polem
bez ohledu na počet rozměrů `D`, a zachovává stejnou sémantiku bez
ohledu na deklarovaný typ prvků pole. Na rozdíl od implicitní konverze
z [6.8](#68-implicitní-konverze-mezi-poli-a-mezi-polem-a-skalárem) se
zde obsah prvků vůbec neprochází, takže žádná konverze prvek po prvku
není potřeba.

### 6.8 Implicitní konverze mezi poli a mezi polem a skalárem

Tato sekce shrnuje **jeden obecný mechanismus**, kterým BASIX
implicitně konvertuje mezi libovolnými dvěma poli (jednorozměrnými i vícerozměrnými,
v jakékoliv vzájemné kombinaci a s libovolným, i vzájemně odlišným
tvarem) a mezi polem a skalárem (`int`/`real`). Mechanismus platí
**všude, kde k takové konverzi může dojít** — konkrétně v `set`
([5.8](#58-zápis-celého-pole-jako-čísla-textu-nebo-kopie-jiného-pole-set),
body A, B, C) a v `{[jmeno_pole], ...}`
([5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu),
tvar 4) — a není vlastností žádné z těchto konstrukcí samotné, ty jsou
jen konkrétní místa, kde se pravidlo uplatní.

**1) Linearizace vícerozměrného pole — row-major.** Aby šlo s `D`-rozměrným
polem zacházet jako s lineární posloupností prvků (nutné pro obě
následující pravidla), narovnává se vždy **row-major** pořadím —
poslední rozměr se mění nejrychleji, první nejpomaleji:

```
pole[1]  = pole[1][1][1]
pole[2]  = pole[1][1][2]
...
pole[10] = pole[1][1][10]
pole[11] = pole[1][2][1]
atd.
```

(pro pole tvaru např. `N×10×10`). Toto pořadí odpovídá tomu, jak se
rozměry zapisují při indexaci `jmeno[v1][v2]...[vD]`
([6.3](#63-čtení-prvku-jmenovyrazvyraz)) i jak se uvádí tvar pole při
deklaraci ([6.2](#62-deklarace-a-inicializace-výchozí-nuly)): poslední
zapsaný rozměr je ten „nejrychlejší". Pro `array` (`D = 1`) je
linearizované pořadí triviálně shodné s běžnou indexací `1..velikost`.
Tato linearizace se používá **výhradně** pro účely konverzí popsaných
níže — na běžnou indexaci `jmeno[v1]...[vD]`
([6.3](#63-čtení-prvku-jmenovyrazvyraz)) nemá vliv a **nezavádí**
žádnou částečnou indexaci (ta zůstává zakázaná dle 6.3 beze změny).

**2) Jednorozměrné/vícerozměrné pole ↔ jednorozměrné/vícerozměrné pole (hodnoty prvků).**
Realizováno `set(pole1, [pole2])` ([5.8](#58-zápis-celého-pole-jako-čísla-textu-nebo-kopie-jiného-pole-set),
bod C) a `{[jmeno_pole], ...}` ([5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu),
tvar 4):

1. Obě strany (zdroj i cíl) se linearizují podle bodu 1 výše —
   nezávisle na vlastním tvaru/počtu rozměrů `D` každé strany; tvary
   obou stran se mezi sebou nemusí shodovat vůbec.
2. Prvek po prvku se aplikuje implicitní `int ↔ real` konverze dle
   [2.4](#24-implicitní-konverze-mezi-typy), liší-li se deklarovaný typ
   prvků obou stran.
3. Nesoulad **celkového** (lineárního) počtu prvků: je-li zdroj kratší
   než cíl, zbylé prvky cíle (za koncem zdrojové lineární sekvence) se
   nastaví na výchozí nulovou hodnotu dle typu cíle (`0`/`0.0`); je-li
   zdroj delší, přebytek se zahodí. Velikost/tvar cíle je vždy pevná a
   touto konverzí se nemění.

Příklad: `array[999]` (zdroj) → vícerozměrné pole tvaru `10×10×10` (cíl,
1000 prvků): prvních `999` prvků cíle v row-major pořadí (`[1][1][1]`
až `[10][10][9]`) se naplní ze zdroje, poslední prvek `[10][10][10]`
se nastaví na výchozí nulu.

**3) `int`/`real` ↔ jednorozměrné/vícerozměrné pole (číslo ↔ text ↔ znaky).**
Realizováno `set(pole, [vyraz])` a `set(promenna, [pole])`
([5.8](#58-zápis-celého-pole-jako-čísla-textu-nebo-kopie-jiného-pole-set),
body A a B). Mechanismus je stejný jako v původním 5.8A/B — hodnota se
formátuje/parsuje stejnými pravidly jako `print`/`input`
([7.3](#73-sémantika), [8.3](#83-sémantika)) — jen se **pole** (je-li
vícerozměrné) bere jako **celek** v linearizovaném (row-major) pořadí
z bodu 1, ne po jednotlivých rozměrech a bez jakékoliv role
konkrétního rozměru (poslední rozměr zde nemá žádné zvláštní
postavení — jde čistě o linearizaci, stejně jako v bodě 2 výše).

**Vztah k `set` a `{}`.** `set` (5.8) a `{[jmeno_pole], ...}` (5.3) tedy
samy o sobě žádnou konverzi **nedefinují** — jsou to jen dvě konkrétní
syntaktické konstrukce, ve kterých se uplatní obecné pravidlo popsané
zde v 6.8, analogicky k tomu, jak se skalární `int ↔ real` konverze
(2.4) uplatňuje při jakémkoliv přiřazení bez ohledu na konkrétní
příkaz.

**Vztah k `obj`.** Tento mechanismus se týká výhradně polí (jednorozměrných
i vícerozměrných) a skalárů — na složený typ `obj`
([10](#10-složený-datový-typ-obj)) se nijak nerozšiřuje. Konverze mezi
polem a `obj` (v libovolném směru) se místo toho řídí pravidlem
tichého vynechání dle
[10.8](#108-konverze-mezi-obj-a-jinými-typy--tiché-vynechání).

---

## 7. Příkaz pro výstup (`print`)

### 7.1 Přehled

`print` je příkaz pro textový výstup hodnot. BASIX rozlišuje tři
syntaktické varianty podle toho, co (a zda vůbec něco) se vypisuje —
jedna hodnota (skalár, nebo celé pole/řetězec najednou), série více
položek, anebo zcela žádný argument. Varianta se sérií položek sdílí
tvar jednotlivých položek se zápisem jednorozměrného pole
([5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)),
byť s vlastní sémantikou výstupu (viz [7.3](#73-sémantika)).

### 7.2 Syntaxe

**Varianta A — jedna hodnota, nebo jedno pole (řetězec):**

```
print([vyraz])
```

`[vyraz]` je buď běžný výraz dle
[3.3](#33-syntaxe-výrazů) (vyhodnotí se na skalární `int`, nebo `real`),
**nebo** — analogicky k tvaru 4 z
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)
— holé jméno existující proměnné jednorozměrného pole, `[jmeno_pole]`,
odkazující na pole jako celek (typicky řetězec), bez indexu a bez
kombinace s čímkoliv dalším uvnitř týchž `[]`.

**Varianta B — série hodnot:**

```
print({polozka1, polozka2, ..., polozkaN})
```

`{...}` je čárkami oddělený seznam položek (viz níže o povoleném
prázdném seznamu), každá jednoho ze čtyř tvarů zavedených v
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu):

1. přímý **číselný literál** (např. `34`), bez obalujících `[]`;
2. **řetězcový literál** v uvozovkách (např. `"abcdef"`);
3. obecný **výraz**, obalený `[vyraz]`;
4. holé **jméno existující proměnné jednorozměrného pole**, obalené
   `[jmeno_pole]`.

**Varianta C — bez argumentu:**

```
print()
```

Kromě argumentu ve tvaru `[vyraz]` (varianta A) nebo `{...}` (varianta
B) přijímá `print` i zápis zcela **bez argumentu** — prázdné kulaté
závorky.

**Poznámka k variantě B a prázdnému seznamu.** Na rozdíl od `{}` u
`var(...)` ([5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)),
kde seznam musí obsahovat **alespoň jednu** položku, `print({})` je u
`print` platný zápis i s **prázdným** seznamem (žádná položka) — viz
sémantika v [7.3](#73-sémantika).

Příklady zápisu:

- `print([x])` — vypíše hodnotu skalární proměnné `x`.
- `print([retezec])` — vypíše celé pole `retezec` (např. řetězec).
- `print({[a], [b], "abcdef", 34})` — vypíše sérii položek: hodnotu/pole
  `a`, hodnotu/pole `b`, řetězcový literál `"abcdef"` a číselný literál
  `34`, v tomto pořadí.
- `print()`, `print({})` — vypíší jeden konec řádku (viz [7.3](#73-sémantika)).

### 7.3 Sémantika

**Výstup pole (`[jmeno_pole]`) — vždy jako text.** Je-li vypisovanou
položkou (ať už jediný argument varianty A, nebo položka tvaru 4 uvnitř
`{}` varianty B) holé jméno jednorozměrného pole, vypíše se **vždy jako
text**: každý prvek pole se interpretuje jako jeden Unicode kódový bod
(UTF-32) a vypíše se jako odpovídající znak, v indexovém pořadí prvků
pole ([5.1](#51-přehled)) — stejně, jako by pole vzniklo z řetězcového
literálu ([5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)).

Toto pravidlo je **jednotné pro oba deklarované typy prvků pole**, bez
výjimky:

- **`(array, int)`** — hodnota prvku se použije přímo jako kódový bod.
- **`(array, real)`** — než se prvek interpretuje jako kódový bod,
  uplatní se implicitní konverze `real → int`
  ([2.4](#24-implicitní-konverze-mezi-typy)), tedy ořezání desetinné
  části; teprve tato již ořezaná celočíselná hodnota se použije jako
  kódový bod. Např. prvek `65.9` se před výstupem ořízne na `65` a
  vypíše se jako znak `'A'`.

Pole tedy při výstupu nikdy nevypisuje své prvky jako čísla — bez
ohledu na svůj deklarovaný typ prvků se vždy chová jako text.

**Výstup pole odkazujícího na vícerozměrné pole — tiché vynechání.**
Odkazuje-li `[jmeno_pole]` (ať už jako jediný argument varianty A, nebo
jako položka tvaru 4 uvnitř `{}` varianty B) na **vícerozměrné** pole
([6](#6-vícerozměrné-pole)), položka se **zcela vynechá** —
nevypíše se vůbec nic, není to chyba kompilace. Stejné pravidlo (a
stejné zdůvodnění) jako u sestavování pole v
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu).

**Výstup skalární hodnoty.** Vyhodnotí-li se `[vyraz]` na skalární
hodnotu (`int`, nebo `real`) — ať už jako jediný argument varianty A,
nebo jako položka tvaru 3 uvnitř `{}` varianty B — vypíše se **tak, jak
je**, tedy jako textová reprezentace své hodnoty. Např. `[34]` (výraz s
hodnotou `int` `34`) se vypíše jako text `34`.

**Výstup řetězcového literálu a číselného literálu (tvary 1–2 u
varianty B).** Číselný literál (tvar 1, např. `34`) se chová shodně s
pravidlem pro skalární hodnotu výše — vypíše se jako textová
reprezentace svého čísla. Řetězcový literál (tvar 2, např. `"abcdef"`)
se chová shodně s pravidlem pro pole výše — vypíše se přímo jako text
svých znaků (žádná mezikonverze na kódové body jako čísla, na rozdíl od
jeho role v [5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu),
kde přispíval hodnotami do pole).

Všechny čtyři tvary položky (číslo, řetězec, `[vyraz]`, `[jmeno_pole]`)
tedy u `print` sdílí **jedno jednotné pravidlo**: každá položka se
vypíše jako text — číslo jako své desítkové vyjádření, řetězec a pole
jako sled znaků, `[vyraz]` jako desítkové vyjádření své vyhodnocené
skalární hodnoty (nebo jako sled znaků, odkazuje-li bare jméno pole —
viz výše). Syntaxe položek je sdílená s
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu),
sémantika výstupu je ale `print` vlastní.

**Formát desítkového zápisu `real`.** Skalární hodnota typu `real` (ať
už jako výsledek `[vyraz]`, nebo prvek pole při jeho výstupu — pozor,
ten se ale dle pravidla výše vypisuje jako **znak**, ne jako číslo) se
vypisuje **nejkratším desítkovým zápisem, který se zpětným parsováním
vrátí na bitově identickou hodnotu `double`** (tzv. *shortest
round-trip* zápis — stejný princip jako C++17 `std::to_chars` v
round-trip režimu, nebo Python `repr(float)`), **vždy s desetinnou
tečkou**. Důvod je shodný se zásadou č. 1 z [1](#1-přehled): jde o
jediný zápis čísla, který je **deterministický a nezávislý na
platformě** — na rozdíl od zápisu s pevným počtem míst (arbitrární,
ošklivý u celočíselných hodnot) nebo výchozího C++ `std::cout` chování
(implementation-defined přesnost a přepínání mezi pevnou/exponenciální
notací).

Hodnota, jejíž matematická hodnota je celé číslo (např. `3.0`), se tedy
vypíše **s koncovou `.0`** (`"3.0"`, nikoliv `"3"`) — udržuje to na
výstupu stejné vizuální odlišení `real` od `int`, jaké typy mají všude
jinde ve specifikaci. Příklady: `3.0 → "3.0"`, `3.14 → "3.14"`,
`0.1 → "0.1"` (ne dlouhý zápis skutečné binární aproximace).

**Žádné implicitní oddělovače ani odřádkování (u neprázdného obsahu).**
Obsahuje-li `print` alespoň jednu vypisovanou hodnotu — tedy varianta A,
nebo varianta B s neprázdným seznamem — příkaz mezi jednotlivé položky
(ani na konci celého výstupu) **nepřidává nic navíc**: žádnou mezeru,
čárku ani konec řádku. Chce-li program oddělovač nebo nový řádek ve
výstupu, musí ho vypsat explicitně jako součást obsahu (např.
řetězcovým literálem obsahujícím mezeru, nebo `"\n"`, viz escape
sekvence v
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)).
Zřetězení více `print` příkazů, ani více položek v jednom
`print({...})`, tedy samo o sobě nikdy nevloží do výstupu nic mezi ně.

**Prázdné volání (`print()`, `print({})`) — odřádkuje.** Právě
**prázdné** volání je z tohoto obecného pravidla výjimkou — ať už zcela
bez argumentu (varianta C, `print()`), nebo s prázdným seznamem varianty
B (`print({})`), je definováno jako vypsání **právě jednoho znaku konce
řádku** a ničeho jiného. Obě varianty (`print()` i `print({})`) jsou v
tomto ohledu **rovnocenné a zaměnitelné**. Toto je jediný způsob, jak
`print` sám o sobě vloží do výstupu nový řádek, aniž by ho program musel
zapsat explicitně escape sekvencí `"\n"` uvnitř řetězcového literálu.

**Rozhoduje syntaktická, nikoliv efektivní prázdnota.** Toto pravidlo o
odřádkování se řídí výhradně tím, zda je argument `print` **syntakticky**
prázdný (doslova nic mezi `()`, resp. mezi `{}`) — nikoliv tím, zda
výsledný vypsaný text nakonec vyjde prázdný. Argument, který sice
obsahuje nějakou položku, ale ta při výstupu sama o sobě nic
nevypíše — např. `print([prazdne_pole])` (prázdné pole, viz
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)),
nebo `print({""})` (prázdný řetězcový literál jako jediná položka) —
**nevypíše se vůbec nic, ani konec řádku**: takové volání se řídí
obecným pravidlem výše (žádné implicitní oddělovače ani odřádkování),
protože argument sám o sobě **syntakticky prázdný není** — jen se
shodou okolností jeho vyhodnocením nic nevytiskne. Konec řádku tedy
vypíše výhradně `print()` a `print({})` doslova, žádný jiný zápis, byť
efektivně prázdný.

### 7.4 Souhrnný příklad

```
var(int, x, [42])
var(real, y, [3.5])
var((array, int), jmeno, {"Ahoj"})

print([jmeno])
print()
print({[x], " + ", [y], " = ", [x + y]})
print()
```

`print([jmeno])` vypíše pole `jmeno` (vzniklé z řetězcového literálu
`"Ahoj"`, [5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu))
jako text — tedy `Ahoj` — bez dalšího odřádkování. Následující `print()`
(syntakticky prázdné volání) vypíše samostatný konec řádku, takže další
výstup začne na novém řádku.

`print({[x], " + ", [y], " = ", [x + y]})` vypíše sérii pěti položek za
sebou, bez jakéhokoliv oddělovače mezi nimi: skalární `int` hodnotu `x`
jako text `42`, řetězcový literál `" + "` jako text ` + `, skalární
`real` hodnotu `y` jako text `3.5` (formát dle výše), řetězcový literál
`" = "` jako text ` = `, a nakonec výraz `x + y` — dle hierarchie typů
([2.5](#25-hierarchie-typů-u-binárních-operací)) se `x` (`int`)
promuje na `real`, součet `42 + 3.5` dá `real` hodnotu `45.5`, vypsanou
jako text `45.5`. Výsledný řádek výstupu je tedy `42 + 3.5 = 45.5`, bez
koncového odřádkování — to zajišťuje až následující `print()`.

Celkový výstup programu:

```
Ahoj
42 + 3.5 = 45.5
```

---

## 8. Příkaz pro vstup (`input`)

### 8.1 Přehled

`input` je příkaz pro čtení hodnoty ze vstupu do již existující
proměnné. Na rozdíl od `print` ([7](#7-příkaz-pro-výstup-print)),
který má tři syntaktické varianty (jedna hodnota, série hodnot, žádný
argument), má `input` prozatím jedinou syntaxi — čtení jedné hodnoty do
jedné skalární proměnné.

### 8.2 Syntaxe

```
input(promenna)
```

kde:

- `promenna` je identifikátor **již existující** proměnné (zavedené
  dříve příkazem `var(...)`,
  [4.1](#41-deklarace-a-inicializace-proměnné-var))
  — analogicky k cíli přiřazení u `set(...)`
  ([4.2](#42-přiřazení-hodnoty-do-proměnné-set)):
  holé jméno, bez obalujících `[]` (hranaté závorky u `promenna` by zde
  značily jméno pole s indexem, ne cíl zápisu skalární hodnoty — stejná
  konvence jako u `set`).
- `input` sám o sobě **nezavádí** novou proměnnou — na rozdíl od
  `var(...)`, mění pouze hodnotu proměnné, která již existuje, stejně
  jako `set(...)`.
- `promenna` může být **buď** skalární proměnná (`int`, nebo `real`),
  **nebo** proměnná jednorozměrného pole ([5](#5-jednorozměrné-pole-array))
  — v obou případech stejná syntaxe `input(promenna)`, bez rozlišujícího
  zápisu navíc; který z obou případů nastal, plyne ze statického typu
  `promenna` (skalár vs. pole), stejně jako u `set(...)`. Sémantika se
  přitom liší (viz [8.3](#83-sémantika)).

**Typ vstupu (skalár).** `input` neurčuje typ čtené hodnoty žádným
vlastním zápisem (např. žádné `input(int, promenna)`) — namísto toho se
očekávaná hodnota ze vstupu čte **podle statického typu `promenna`**
(`int`, nebo `real`, dle jejího deklarovaného typu z `var(...)`).

Příklad:

```
var(int, x, [0])
input(x)
```

Zde `input(x)` očekává, že se ze vstupu přečte hodnota typu `int`
(protože `x` byla deklarována jako `int`), a tuto hodnotu uloží do `x`.

**Vstup do pole.**

```
var((array, int), retezec, [10])
input(retezec)
```

(přesná syntaxe deklarace pole viz
[5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly)/[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)) —
je-li `promenna` jméno existujícího jednorozměrného pole, `input` z něj
načte řetězec (viz [8.3](#83-sémantika)).

### 8.3 Sémantika

**Sdílený mechanismus — `input` vždy čte a spotřebuje jeden celý
řádek.** Bez ohledu na to, jde-li o skalární proměnnou, nebo o pole,
každé jednotlivé volání `input(promenna)` přečte ze vstupu **právě
jeden řádek** — text až po nejbližší znak konce řádku (výlučně; tento
znak sám součástí přečteného textu není), nebo po EOF, není-li žádný
další znak konce řádku k dispozici. Přečtený řádek (i jeho ukončovací
znak konce řádku, je-li přítomen) se přitom vždy **celý spotřebuje** —
zbytek téhož řádku není k dispozici pro žádné další, následné čtení, a
to i v případech, kdy z něj `promenna` samotná nakonec převezme jen
menší část (viz obě podsekce níže). Následující volání `input` tedy
vždy začíná čtení znovu od **dalšího** řádku vstupu, nikdy uprostřed
řádku předchozího. Tento mechanismus je pro skalár i pole stejný —
liší se až to, co se s takto přečteným řádkem dál dělá.

**Vstup do pole — celý řádek jako řetězec, omezený velikostí pole.**
Je-li cílem `input(promenna)` proměnná **jednorozměrného pole**,
přečtený řádek (viz výše) se uloží do pole znak po znaku (stejnou
konvencí jako řetězcový literál — UTF-32 kódový bod na prvek,
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)),
**až do velikosti pole** — tedy nejvýše tolik znaků, kolik má pole
prvků. Velikost pole je přitom **pevně daná už jeho deklarací**
([5.1](#51-přehled), bod o pevné velikosti) —
`input` do pole tuto velikost nijak nemění, jen naplní (nejvýše)
existující prvky.

**Kratší vstupní text — doplnění nulovou hodnotou.** Je-li přečtený
vstupní text **kratší** než velikost pole, zbylé prvky pole (za
posledním znakem textu) se nastaví na **výchozí nulovou hodnotu
deklarovaného typu pole** — `0` pro `(array, int)`, `0.0` pro
`(array, real)` — stejné výchozí hodnoty, jako dostávají prvky pole při
běžné deklaraci ([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly)).
Text kratší, než je velikost pole, tedy pole zcela **přepíše** (žádné
předchozí hodnoty prvků za koncem textu nezůstávají zachovány) —
zbytek se jen nastaví na nulu místo na znak.

**Delší vstupní text — zahození přebytku.** Je-li přečtený vstupní text
**delší** než velikost pole, pole se naplní prvními (dle velikosti
pole) znaky textu a **zbytek vstupního textu se zahodí** — nezůstává k
dispozici pro žádné další, následné čtení (`input`, ani jiné).

**Vstup do skaláru — jen první hodnota z řádku, zbytek se zahazuje.**
Je-li cílem `input(promenna)` **skalární** proměnná, `input` z
přečteného řádku (viz výše) nejprve přeskočí případné úvodní bílé znaky
(mezery, tabulátory), a poté z něj rozpozná **nejvýše jednu** hodnotu —
nejdelší úvodní část řádku, která tvoří platný zápis hodnoty typu
`promenna` (`int`, nebo `real`, syntakticky dle
[3.3](#33-syntaxe-výrazů)), ukončenou buď bílým
znakem, nebo koncem řádku. Tuto jednu hodnotu `promenna` dostane (po
případné saturaci, viz níže). **Vše ostatní na řádku** — ať už další
bílé znaky, nebo třeba další čísla za první hodnotou — se **zahodí**
spolu se zbytkem řádku (viz sdílený mechanismus výše) a pro žádné další
volání `input` už není k dispozici. Toto pravidlo je pro skalár přímou
obdobou pravidla „delší vstupní text — zahození přebytku" u pole výše —
jen aplikovanou na jednu hodnotu místo na
posloupnost znaků: `input` se nikdy nesnaží přečíst z jednoho řádku
**víc než jednu** hodnotu, ani u skaláru, ani u pole.

Např. `input(a)` následované `input(b)` (obě `int`) nad vstupem

```
5 10
20
```

dá `a` hodnotu `5` (zbytek prvního řádku, ` 10`, se zahodí) a `b`
hodnotu `20` (z druhého řádku) — hodnota `10` z prvního řádku se do
`b` **nedostane**, protože `input(b)` už čte nový, druhý řádek, ne
zbytek prvního.

**Neplatný/nečíselný vstup u skalární proměnné — nulová hodnota.**
Nelze-li přečtený vstup rozpoznat jako platnou hodnotu typu `promenna`
(`int`, nebo `real`), `promenna` dostane **výchozí nulovou hodnotu
svého typu** — `0` pro `int`, `0.0` pro `real` — a nejde o chybu
kompilace ani chybu za běhu. Toto pravidlo přímo navazuje na již
zavedený vzor v jazyce, kde neúplný/neplatný vstup vede na definovanou
nulovou hodnotu místo na UB nebo běhovou chybu — stejně jako dělení
nulou ([2.3](#23-saturace-přetečení-a-widening))
nebo doplnění zbylých prvků pole při kratším vstupním textu (viz výše).
BASIX zatím nemá žádný koncept chyb za běhu ani stavový příznak úspěchu
čtení (na rozdíl od C++ `std::cin`) — program se tedy o neplatnosti
vstupu jinak nedozví, což je v souladu s tím, že jazyk podobný
mechanismus jinde nemá.

**Vstup mimo rozsah `[-2^53, 2^53]` — saturace.** Je-li přečtený vstup
platné číslo daného typu, ale jeho hodnota leží mimo mez
`[-2^53, 2^53]` ([2.1](#21-základní-typy)),
uplatní se **stejná saturace jako u literálu** mimo rozsah
([2.3](#23-saturace-přetečení-a-widening)) —
hodnota se saturuje na příslušnou mez (`-2^53`, nebo `2^53`), není to
chyba za běhu. Toto pravidlo je konzistentní s tím, že saturace na
`[-2^53, 2^53]` je v BASIXu **jednotný mechanismus uplatňovaný všude**,
kde se do proměnné daného typu dostává hodnota mimo tuto mez — bez
ohledu na to, zda pochází z literálu, z výpočtu, nebo (nově) ze vstupu.

**Vstup na konci vstupu (EOF) — nulová hodnota, žádná chyba za běhu.**
Narazí-li `input(promenna)` u **skalární** proměnné na konec vstupu
(EOF) dřív, než se podaří přečíst jakoukoliv hodnotu, `promenna`
dostane stejně jako u neplatného/nečíselného vstupu (viz výše)
**výchozí nulovou hodnotu svého typu** — `0` pro `int`, `0.0` pro
`real`. Nejde o chybu kompilace ani chybu za běhu. Toto pravidlo je jen
přímočarým rozšířením pravidla o neplatném vstupu: EOF na místě, kde se
čeká hodnota, je z pohledu `input` jen zvláštní případ „nepodařilo se
přečíst platnou hodnotu" — BASIX mezi „vstup byl přítomen, ale byl
neplatný" a „vstup vůbec nebyl přítomen" nijak nerozlišuje, ve shodě se
zásadou č. 1 z [1](#1-přehled) (žádné UB, vždy
deterministické chování) a s tím, že jazyk nemá žádný stavový příznak
úspěchu čtení, kterým by šlo tyto dva případy odlišit.

Pro **pole** žádné samostatné pravidlo netřeba: je-li vstup na EOF už
od začátku (přečtený text má délku `0`), jde jen o krajní případ
pravidla „kratší vstupní text" výše — prázdný text je nejkratší možný
text, takže se celé pole nastaví na výchozí nulovou hodnotu svého typu,
stejně jako by to udělal jakýkoliv jiný text kratší než velikost pole.

### 8.4 Souhrnný příklad

```
var(int, a, [0])
var(int, b, [0])
var((array, int), jmeno, [5])

input(a)
input(b)
input(jmeno)
```

Nad vstupem (tři řádky):

```
5 10
20
Ahoj svete
```

`input(a)` přečte první řádek `5 10` celý (a spotřebuje ho); z něj
rozpozná jedinou úvodní hodnotu `5` (ukončenou mezerou), tu uloží do
`a`, zbytek `" 10"` se zahodí. `input(b)` proto už čte **druhý** řádek
`20` (ne zbytek prvního) — z něj rozpozná hodnotu `20` a uloží ji do
`b`; hodnota `10` z prvního řádku se do `b` nikdy nedostane. Nakonec
`input(jmeno)` přečte třetí řádek `Ahoj svete` (10 znaků) do pole
`jmeno` o velikosti `5` — uloží se jen prvních pět znaků, `A`, `h`,
`o`, `j`, ` ` (mezera), zbytek `svete` se zahodí.

Po doběhnutí všech tří příkazů tedy platí: `a` = `5`, `b` = `20`,
`jmeno` odpovídá řetězci `"Ahoj "` (s koncovou mezerou, bez `svete`).

---

## 9. Vestavěné funkce `max`/`min`

### 9.1 Přehled

`max` a `min` jsou dvě vestavěné funkce BASIXu — žádné samostatné
klíčové slovo ani konstanta (jako by byly např. `maxint`/`minint`)
nevznikají. Obě funkce mají **čtyři syntaktické podoby**, rozlišené
podle **tvaru jediného argumentu** — přesně stejným způsobem, jakým už
dnes `print` rozlišuje holé jméno pole od hranatými závorkami
uzavřeného výrazu ([7.3](#73-sémantika)):

- **skalární podoba**, `max([vyraz])`/`min([vyraz])` — vrací horní,
  resp. dolní mez `[-2^53, 2^53]` ([2.1](#21-základní-typy))
  **výtěžného typu** daného výrazu;
- **podoba nad polem, holé jméno**, `max(jmeno)`/`min(jmeno)` — vrací
  nejvyšší, resp. nejnižší platný **index posledního rozměru** pole
  `jmeno` — jednotně pro jednorozměrné `array`
  ([5](#5-jednorozměrné-pole-array)), kde je poslední rozměr zároveň
  jediný, i pro vícerozměrné pole
  ([6](#6-vícerozměrné-pole)), stejnou konvencí „poslední
  rozměr", jakou už používá porovnání polí
  ([6.7](#67-porovnání-polí-operátory-rovnosti));
- **podoba nad vícerozměrným polem, konkrétní rozměr**,
  `max((jmeno, [vyraz]))`/`min((jmeno, [vyraz]))` — vrací nejvyšší,
  resp. nejnižší platný index **rozměru zvoleného výrazem `vyraz`**
  vícerozměrného pole `jmeno`, nezávisle na tom, zda jde o poslední
  rozměr, nebo ne;
- **podoba nad `obj`, holé jméno instance**, `max(jmeno)`/`min(jmeno)`
  — kde `jmeno` je tentokrát holé jméno proměnné typu `obj`
  ([10.2](#102-deklarace-proměnné-instance-typu-obj)) — vrací počet
  členů, resp. dolní mez `1`, viz
  [9.6](#96-sémantika--podoba-nad-obj-holé-jméno-instance). Tato
  podoba sdílí stejný syntaktický tvar `max(jmeno)`/`min(jmeno)` jako
  podoba nad polem výše — obě jsou navzájem bezpečně rozlišitelné
  podle **deklarovaného typu proměnné**, na kterou `jmeno` odkazuje
  (pole vs. `obj`), stejně jako je typ proměnné vždy staticky známý
  už z její deklarace.

Podoba nad polem přitom zároveň řeší dříve otevřenou otázku „zjištění
délky pole za běhu" (viz [souhrn otevřených rozhodnutí v 5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)):
`max(jmeno)` **je** touto funkcí, protože nejvyšší platný index
posledního rozměru pole je zároveň jeho délkou (pole je indexováno od
jedné, [5.1](#51-přehled), bod 4) — žádná samostatná funkce `length`
se tedy nezavádí.

**Dvouargumentová podoba se nezavádí.** BASIX záměrně nezavádí žádnou
obecnou funkci/operátor pro výběr většího, resp. menšího ze dvou
konkrétních skalárních výrazů (analogicky k C++ `std::max`/`std::min`),
nezávislou na tom, zda hodnoty pocházejí z pole. `max`/`min` tak v
BASIXu zůstávají výhradně ve čtyřech podobách výše — žádná další,
dvouargumentová podoba nepřibývá, takže mezi žádnými dvěma podobami
nemůže dojít ke kolizi podle počtu argumentů.

### 9.2 Syntaxe

```
max([vyraz])
min([vyraz])
max(jmeno)
min(jmeno)
max((jmeno, [vyraz]))
min((jmeno, [vyraz]))
```

kde:

- `vyraz` je hranatými závorkami uzavřený výraz dle
  [3.3](#33-syntaxe-výrazů) — stejná konvence jako u `set`/`var`
  ([4.1](#41-deklarace-a-inicializace-proměnné-var),
  [4.2](#42-přiřazení-hodnoty-do-proměnné-set)). U třetí podoby udává
  `vyraz` po vyhodnocení číslo rozměru, pro který se má vrátit mez.
- `jmeno` u podoby nad polem je **holé jméno** existující proměnné
  pole — jednorozměrného `array` ([5](#5-jednorozměrné-pole-array)),
  nebo vícerozměrného ([6](#6-vícerozměrné-pole))
  — bez `[]`, bez indexu.
- `jmeno` u podoby nad `obj` je stejným způsobem **holé jméno**
  existující proměnné typu `obj`
  ([10.2](#102-deklarace-proměnné-instance-typu-obj)) — viz
  [9.6](#96-sémantika--podoba-nad-obj-holé-jméno-instance). Tvar
  `max(jmeno)`/`min(jmeno)` je pro pole i pro `obj` stejný — kompilátor
  obě podoby rozliší podle **deklarovaného typu** proměnné `jmeno`
  (pole vs. `obj`), ne podle syntaxe samotné.
- `(jmeno, [vyraz])` u třetí podoby je — stejně jako `(array, typ)` u
  `var` ([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly))
  — kulatými závorkami uzavřená **dvojice** sloužící jako jediný
  argument, ne dva argumenty oddělené čárkou na stejné úrovni.

Všechny čtyři podoby jsou vzájemně bezpečně rozlišitelné podle tvaru
argumentu a — v případě holého jména — podle deklarovaného typu
proměnné: hranaté závorky (skalární podoba), holé jméno proměnné pole
(podoba nad polem), holé jméno proměnné `obj` (podoba nad `obj`), nebo
kulatými závorkami uzavřená dvojice (podoba nad vícerozměrným polem s výběrem
rozměru) — stejným principem, jakým už `print([jmeno_pole])` je
odlišitelný od `print([vyraz])` ([7.3](#73-sémantika)).

### 9.3 Sémantika — skalární podoba (mez typu)

`vyraz` se vyhodnotí dle obvyklých pravidel — je-li smíšený, uplatní
se hierarchie typů u binárních operací
([2.5](#25-hierarchie-typů-u-binárních-operací)) — čímž se určí jeho
**výtěžný typ**, `int` nebo `real`. Samotná **hodnota**, na kterou se
`vyraz` vyhodnotí, se nijak nepoužije ani nevrací — `vyraz` slouží
výhradně k určení typu výsledku:

- `max([vyraz])` → **horní** mez (`2^53`) výtěžného typu `vyraz`,
  vrácená jako hodnota téhož typu (`int`, nebo `real`).
- `min([vyraz])` → **dolní** mez (`-2^53`) výtěžného typu `vyraz`,
  vrácená jako hodnota téhož typu.

Protože obě meze `[-2^53, 2^53]` sdílejí stejnou magnitudu napříč
`int`/`real` ([1](#1-přehled), zásada 2), rozdíl mezi `max`/`min`
volaným s `int`, resp. `real` výrazem je čistě ve **výsledném typu**
vrácené hodnoty, ne v její magnitudě. Hodnota je v principu staticky
známá konstanta, vyhodnotitelná už při kompilaci.

Příklady:

- `var(int, a, [max([5])])` → `[5]` je typu `int`, `a` dostane `int`
  mez `2^53` (`9007199254740992`).
- `var(real, b, [min([3.14])])` → `[3.14]` je typu `real`, `b`
  dostane `real` mez `-2^53` (`-9007199254740992.0`).
- `var(int, x, [5])` `var(real, y, [1.0])`
  `var(real, c, [max([x + y])])` → výraz `x + y` promuje `x` na
  `real` dle [2.5](#25-hierarchie-typů-u-binárních-operací), tedy
  `max` vrací `real` mez `2^53`, i když `x` samo je `int`.
- `var(int, d, [max([2.5])])` → `[2.5]` je typu `real`, `max` vrátí
  `real` mez `2^53`; při uložení do `int` proměnné `d` se uplatní
  implicitní konverze `real → int` ([2.4](#24-implicitní-konverze-mezi-typy)) —
  bezeztrátově, protože obě meze sdílejí stejnou magnitudu.

### 9.4 Sémantika — podoba nad polem (poslední rozměr, holé jméno)

`jmeno` je holé jméno existující proměnné pole — buď jednorozměrného
`array` ([5](#5-jednorozměrné-pole-array)), nebo vícerozměrného
([6](#6-vícerozměrné-pole)):

- Je-li `jmeno` jednorozměrné `array`:
  - `max(jmeno)` → **nejvyšší platný index** pole — prakticky jeho
    délka (počet prvků), protože pole je indexováno od jedné
    ([5.1](#51-přehled), bod 4).
  - `min(jmeno)` → **nejnižší platný index** pole — protože BASIX
    indexuje všechna jednorozměrná pole jednotně od `1`, jde vždy o
    **konstantu `1`**, nezávisle na velikosti či obsahu konkrétního
    pole.
- Je-li `jmeno` vícerozměrné pole s `D` rozměry, `max(jmeno)`/`min(jmeno)`
  vrací nejvyšší, resp. nejnižší platný index **posledního** rozměru
  pole `jmeno` — stejná konvence „poslední rozměr", jaká už platí u
  porovnání polí ([6.7](#67-porovnání-polí-operátory-rovnosti)).
  `array` je tak i zde jen speciální případ vícerozměrného pole s `D = 1`,
  kde „poslední rozměr" je zároveň jediný rozměr, a sémantika pro
  `array` výše je speciálním případem stejného pravidla.

Obě funkce vrací hodnotu typu **`int`** (indexy jsou vždy celočíselné)
— bez ohledu na deklarovaný typ **prvků** pole (`int`, nebo `real`).
Protože pole má vždy alespoň jeden prvek v každém rozměru
([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly),
[5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu),
[6.1](#61-přehled), [6.2](#62-deklarace-a-inicializace-výchozí-nuly)),
jsou `max(jmeno)` i `min(jmeno)` vždy dobře definované — nehrozí
případ prázdného pole. Tvar pole (počet a velikost rozměrů) je vždy
staticky daný už jeho deklarací ([5.1](#51-přehled), bod 2) —
`max(jmeno)` i `min(jmeno)` jsou tedy v principu vyhodnotitelné jako
konstanty už při kompilaci (`min(jmeno)` je dokonce staticky `1` u
libovolného pole, bez ohledu na jeho konkrétní velikost).

**Vztah k 9.5.** U vícerozměrného pole je `max(jmeno)`/`min(jmeno)` **zkratka**
pro poslední rozměr — pro výběr jiného, konkrétního rozměru zůstává k
dispozici dvojicová podoba `max((jmeno, [vyraz]))`/`min((jmeno, [vyraz]))`
z [9.5](#95-sémantika--podoba-nad-vícerozměrným-polem-konkrétní-rozměr). Obě
syntaxe u vícerozměrného pole koexistují: `max((jmeno, [D]))` (kde `D` je
počet rozměrů pole `jmeno`) dává stejný výsledek jako `max(jmeno)`, jen
zapsaný explicitně.

### 9.5 Sémantika — podoba nad vícerozměrným polem (konkrétní rozměr)

`jmeno` je holé jméno existující proměnné typu vícerozměrné pole
([6](#6-vícerozměrné-pole)) s `D` rozměry; `vyraz` je
hranatými závorkami uzavřený výraz dle [3.3](#33-syntaxe-výrazů),
který se vyhodnotí a udává **číslo rozměru**, pro který se má vrátit
mez — číslováno od `1` (stejná konvence jako indexace prvků,
[6.1](#61-přehled)), ne od `0`:

- `max((jmeno, [vyraz]))` → **nejvyšší platný index** rozměru
  s pořadovým číslem `vyraz` pole `jmeno` — prakticky velikost tohoto
  rozměru.
- `min((jmeno, [vyraz]))` → **nejnižší platný index** téhož rozměru —
  vždy konstanta `1`, protože vícerozměrné pole indexuje jednotně od jedné
  ve všech rozměrech, stejně jako `array` ([6.1](#61-přehled)).

Obě funkce vrací `int`, bez ohledu na deklarovaný typ prvků pole.

**Typ a mimo-rozsahové chování `vyraz`.** V souladu s tím, jak se
zachází s indexy jinde v jazyce — je-li `vyraz` typu `real`, uplatní
se implicitní konverze na `int` ořezáním desetinné části, stejně jako
u indexu prvku ([6.3](#63-čtení-prvku-jmenovyrazvyraz)). Vyjde-li
`vyraz` (po konverzi) mimo platný rozsah čísel rozměrů `[1, D]`,
**saturuje se** na nejbližší platné číslo rozměru (`1`, resp. `D`) —
analogicky k saturaci indexu prvku mimo meze
([6.5](#65-index-mimo-meze--saturace)) — takže ani zde nevzniká žádný
nový případ chyby za běhu ani UB ([1](#1-přehled), zásada 1).

Protože vícerozměrné pole má vždy alespoň jeden prvek v každém rozměru
([6.1](#61-přehled), [6.2](#62-deklarace-a-inicializace-výchozí-nuly)),
jsou `max((jmeno, [vyraz]))` i `min((jmeno, [vyraz]))` vždy dobře
definované — nehrozí případ prázdného rozměru. Tvar (počet a velikost
všech rozměrů) vícerozměrného pole je vždy staticky daný už jeho deklarací —
je-li navíc `vyraz` staticky vyhodnotitelný výraz, jsou v principu
staticky vyhodnotitelné (jako konstanty) i `max`/`min` samotné.

### 9.6 Sémantika — podoba nad `obj` (holé jméno instance)

`jmeno` je holé jméno existující proměnné typu `obj`
([10.2](#102-deklarace-proměnné-instance-typu-obj)) — analogicky k
podobě nad polem ([9.4](#94-sémantika--podoba-nad-polem-poslední-rozměr-holé-jméno)),
jen namísto počtu prvků pole se pracuje s počtem členů `obj` typu, na
který je `jmeno` navázáno ([10.1](#101-definice-typu-objjmeno--end-obj)):

- `min(jmeno)` → vždy **konstanta `1`**, nezávisle na konkrétním `obj`
  typu — stejná konvence jako `min(jmeno)` u pole
  ([9.4](#94-sémantika--podoba-nad-polem-poslední-rozměr-holé-jméno)).
- `max(jmeno)` → **počet členů** (počet `var(...)` řádků,
  [10.1](#101-definice-typu-objjmeno--end-obj)) v definici `obj` typu,
  na který je `jmeno` navázáno.

Obě funkce vrací hodnotu typu **`int`**. Protože `obj` musí mít vždy
alespoň jeden člen ([10.1](#101-definice-typu-objjmeno--end-obj)),
jsou `min(jmeno)` i `max(jmeno)` u `obj` vždy dobře definované —
nehrozí žádný prázdný případ, stejně jako u pole. Počet členů je
vlastností `obj` **typu**, ne konkrétní instance, je tedy staticky
známý už při kompilaci.

**Pouze počet, ne pozicový přístup.** Tato podoba vrací výhradně
počet/dolní mez jako číslo — nezavádí žádný nový způsob přístupu ke
členům `obj` podle pořadového čísla (tj. nevzniká žádná obdoba
`jmeno_instance[2]`). Přístup ke členům zůstává výhradně přes jméno
([10.3](#103-čtení-hodnoty-člena-jmeno_instancejmeno_clenu),
[10.4](#104-zápis-do-člena-setjmeno_instancejmeno_clenu-výraz)).

Příklad:

```
obj(bod)
var(int, x)
var(int, y)
var(int, z)
end obj

var((obj, bod), p)

var(int, pocet, [max(p)])
var(int, prvni, [min(p)])
```

`pocet` dostane `3` (`bod` má tři členy: `x`, `y`, `z`), `prvni`
dostane `1`.

### 9.7 Souhrnný příklad

```
var((array, int), c, {10, 20, 30})

var(int, n, [max(c)])
var(int, i, [min(c)])

while([i <= max(c)])
    print([c[i]])
    set(i, [i + 1])
end while
```

`c` má velikost `3`. `n` dostane `3` (`max(c)`, nejvyšší platný
index/délka), `i` dostane `1` (`min(c)`, vždy `1`). Cyklus `while`
následně projde celé pole `c` bez znalosti jeho velikosti napevno —
`min(jmeno)`/`max(jmeno)` slouží jako obecné meze cyklu i bez znalosti
toho, že BASIX indexuje pole od jedné.

Totéž pro vícerozměrné pole se dvěma rozměry:

```
var((array, int), m, ([2], [3]))

var(int, posledni, [max(m)])
var(int, prvni, [max((m, [1]))])
```

`m` má tvar `2×3` (rozměr `1` velikosti `2`, rozměr `2` velikosti
`3`). `max(m)` je zkratka pro poslední rozměr, tedy vrátí `3`
(velikost rozměru `2`) — stejně jako explicitní
`max((m, [2]))`. `max((m, [1]))` naproti tomu vybírá první rozměr
explicitně a vrátí `2`. `min(m)` i `min((m, [vyraz]))` by v obou
případech vrátily `1`.

---

## 10. Složený datový typ (`obj`)

Nad rámec skalárních typů ([2](#2-datové-typy)) a polí
([5](#5-jednorozměrné-pole-array),
[6](#6-vícerozměrné-pole)) zavádí BASIX i vlastní,
pojmenovaný **složený datový typ** — `obj`, obdobu `struct` z C++.
Zatímco `code`/`while`/... ([4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break),
[4.4](#44-cyklus-s-podmínkou-while)) zavádí pojmenovaný **blok**, `obj`
zavádí pojmenovaný **typ**, složený z pojmenovaných polí (dále
„členů").

### 10.1 Definice typu (`obj(jmeno) ... end obj`)

```
obj(jmeno)
var(typ, jmeno, [vyraz])
var(typ, jmeno, [vyraz])
...
end obj
```

kde:

- `jmeno` (u `obj`) je identifikátor nového typu dle
  [3.2](#32-pojmenování-identifikátorů).
- tělo je sekvence jednoho nebo více příkazů
  `var(typ, jmeno, [vyraz])` ([4.1](#41-deklarace-a-inicializace-proměnné-var))
  — každý zavádí jedno pole (člen) nového typu, se svým typem, jménem a
  výchozí hodnotou.
- `end obj` ukončuje definici.

Jako každý příkaz stojí `obj(jmeno)` a `end obj` samostatně na svém
řádku ([3.1](#31-oddělování-příkazů)). Odsazení těla je, stejně jako u
`code`/`while`/`loop`/`for`/`dowhile`
([4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break)),
čistě vizuální konvence bez vlivu na syntaxi ani sémantiku.

**Zkrácená forma člena bez `[vyraz]`.** Stejně jako u samostatné proměnné
([4.1](#41-deklarace-a-inicializace-proměnné-var)) lze i jednotlivý člen
zapsat zkráceně jako `var(typ, jmeno)` místo `var(typ, jmeno, [vyraz])`,
se stejným efektem: člen dostane výchozí nulovou hodnotu svého typu
(`0`/`0.0`). Pravidlo z
[10.5](#105-výchozí-hodnota-člena--vyhodnocuje-se-při-každé-instanci)
(výchozí `[vyraz]` člena se vyhodnocuje znovu při každé instanci) se
zde uplatní beze změny — jen triviálně, protože „výraz" je pevně nulový
literál, takže každá instance nutně dostane stejnou, nulovou počáteční
hodnotu daného člena.

Příklad:

```
obj(bod)
var(int, x)
var(int, y)
end obj

var((obj, bod), p)
```

`p.x` i `p.y` dostanou po vzniku `p` hodnotu `0` — ekvivalentní zápisu
`var(int, x, [0])` `var(int, y, [0])` v definici `bod`.

**Pořadí členů.** Členy `obj` typu mají definované **pořadí** — jde o
pořadí, v jakém jsou v těle `obj(jmeno) ... end obj` zapsány
jednotlivé `var(...)` řádky, shora dolů. Toto pořadí je čistě
informativní vlastnost definice typu (kolikátý je který člen v pořadí
zápisu) — nezavádí se jím žádný pozicový přístup ke členům instance,
který zůstává výhradně přes jméno
([10.3](#103-čtení-hodnoty-člena-jmeno_instancejmeno_clenu),
[10.4](#104-zápis-do-člena-setjmeno_instancejmeno_clenu-výraz)).

**Minimální/maximální počet členů.** `obj` musí obsahovat **alespoň
jeden** `var(...)` člen — prázdný `obj` bez jediného člena je chyba při
kompilaci. Horní mez počtu členů **není** žádná, smí jich být libovolně
mnoho.

**Typ člena.** Členem `obj` smí být kterýkoliv typ, který zná
`var(...)` — tedy skalár (`int`, `real`,
[4.1](#41-deklarace-a-inicializace-proměnné-var)), jednorozměrné pole
(`array`, [5](#5-jednorozměrné-pole-array)), vícerozměrné pole
([6](#6-vícerozměrné-pole)), i jiný, dříve
definovaný `obj`.

### 10.2 Deklarace proměnné (instance) typu `obj`

```
var((obj, typ), jmeno)
```

kde:

- `obj` je doslovné klíčové slovo označující, že jde o instanci `obj`
  typu — analogicky k `(array, typ)` u pole, jednotně pro
  jednorozměrné i vícerozměrné
  ([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly),
  [6.2](#62-deklarace-a-inicializace-výchozí-nuly)).
- `typ` je jméno dříve deklarovaného `obj` — jméno použité v jeho
  vlastním `obj(jmeno) ... end obj` ([10.1](#101-definice-typu-objjmeno--end-obj)).
- `jmeno` je identifikátor nové proměnné — instance daného `obj` typu
  — dle [3.2](#32-pojmenování-identifikátorů).

Na rozdíl od `var(typ, jmeno, [vyraz])` u skaláru, nebo `var((array,
typ), jmeno, [vyraz])`/`var((array, typ), jmeno, ([vyraz], ...))` u
pole (skalární i vícerozměrná forma), zde **není** třetí argument
`[vyraz]` — instance se vždy
inicializuje výchozími hodnotami jednotlivých členů, tak jak byly
zapsány v definici `obj` jejich vlastními `var(typ, jmeno, [vyraz])`
(viz [10.5](#105-výchozí-hodnota-člena--vyhodnocuje-se-při-každé-instanci)
pro přesný okamžik, kdy se tyto výchozí `[vyraz]` vyhodnocují).

### 10.3 Čtení hodnoty člena (`jmeno_instance.jmeno_clenu`)

Hodnota člena instance `obj` se čte zápisem:

```
jmeno_instance.jmeno_clenu
```

tedy tečková konvence — jméno instance, tečka, jméno člena.

`jmeno_instance.jmeno_clenu` se zapojuje do gramatiky výrazu
([3.3](#33-syntaxe-výrazů)) jako nový druh **operandu**, analogicky k
`jmeno[index]` u polí ([5.4](#54-čtení-prvku-jmenoindex)) — lze ho tedy
použít kdekoliv, kde je operand očekáván, vždy obaleno vnější dvojicí
`[]`, např. `var(int, x, [jmeno_instance.jmeno_clenu])`. Je-li součástí
většího výrazu, obaluje se (spolu s celým výrazem) jen jednou vnější
dvojicí, např. `[jmeno_instance.jmeno_clenu + 1]` — stejná konvence
jako u `jmeno[index]` ([5.4](#54-čtení-prvku-jmenoindex)).

**Výsledný typ.** `jmeno_instance.jmeno_clenu` má stejný typ, jaký byl
deklarován pro daný člen v definici `obj` — dále se s ním zachází jako
s kterýmkoliv jiným operandem daného typu (hierarchie
[2.5](#25-hierarchie-typů-u-binárních-operací) atd.).

**Řetězení.** Je-li `jmeno_clenu` samo typu `obj`, tečkovou notaci lze
řetězit (`a.b.c`) — přístup postupuje přes libovolný počet vnořených
`obj` instancí, poslední článek řetězu určuje výsledný typ celého
výrazu.

### 10.4 Zápis do člena (`set(jmeno_instance.jmeno_clenu, [výraz])`)

Zápis do konkrétního člena instance `obj`:

```
set(jmeno_instance.jmeno_clenu, [vyraz])
```

analogicky k `set(jmeno[index], [vyraz])` u polí
([5.5](#55-zápis-do-prvku-setjmenoindex-výraz)):

- `jmeno_instance.jmeno_clenu` je **cíl** zápisu — stejná syntaxe jako
  u čtení ([10.3](#103-čtení-hodnoty-člena-jmeno_instancejmeno_clenu)),
  zde ale bez vlastního obalujícího `[]` navíc.
- `[vyraz]` je hranatými závorkami uzavřený výraz dle
  [3.3](#33-syntaxe-výrazů), jehož hodnota se (po implicitní konverzi
  na deklarovaný typ daného člena, [2.4](#24-implicitní-konverze-mezi-typy))
  zapíše do daného člena.

**Sémantika.** Mění se výhradně hodnota jednoho člena dané instance —
ostatní členy téže instance, i typ `obj` samotný, se tímto nikdy
nemění. Stejně jako u řetězeného čtení ([10.3](#103-čtení-hodnoty-člena-jmeno_instancejmeno_clenu)),
i cíl zápisu lze řetězit přes vnořené `obj` instance (`set(a.b.c,
[vyraz])`).

### 10.5 Výchozí hodnota člena — vyhodnocuje se při každé instanci

Výraz `[vyraz]` u každého člena `var(typ, jmeno, [vyraz])` uvnitř
definice `obj` se **nevyhodnocuje staticky, jednou, při definici
`obj`** — místo toho se vyhodnocuje **znovu, při každé instanci**,
tedy pokaždé, když vznikne nová proměnná `var((obj, typ), jmeno)`
([10.2](#102-deklarace-proměnné-instance-typu-obj)). Je-li `[vyraz]`
závislý na proměnné, jejíž hodnota se mezi vznikem dvou instancí změní,
dostanou tyto instance různé počáteční hodnoty daného člena.

Toto pravidlo je konzistentní s tím, jak se `[vyraz]` chová i jinde v
jazyce — např. u velikosti pole `var((array, typ), jmeno, [vyraz])`
([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly)),
kde `[vyraz]` také není statická konstanta typu, ale běžný výraz
vyhodnocovaný v místě `var`.

### 10.6 Jmenný prostor `obj` typů a kolizní pravidla

`obj` typy mají vlastní, **oddělený jmenný prostor** od jmen
proměnných, polí a labelů:

- Jméno `obj` typu (to `jmeno` v `obj(jmeno) ... end obj`)
  **nekoliduje** se jménem žádné proměnné, pole, ani labelu — smí být
  stejné jako jméno proměnné, instance, nebo labelu, aniž by šlo
  o chybu při kompilaci.
- Kontext je vždy jednoznačný: jméno `obj` typu se objevuje výhradně na
  místě `typ` uvnitř `(obj, typ)` u `var((obj, typ), jmeno)`
  ([10.2](#102-deklarace-proměnné-instance-typu-obj)) — nikdy jinde
  (nikdy jako operand výrazu, cíl `set`, ani label) — kompilátor tedy
  rozlišuje typ od proměnné/labelu podle syntaktické pozice, ne podle
  sdíleného jmenného prostoru. Stejný princip rozlišení podle pozice
  v gramatice BASIX používá i jinde — např. holé klíčové slovo `typ`
  u `var(typ, jmeno, ...)` ([4.1](#41-deklarace-a-inicializace-proměnné-var)),
  nebo `array` u `(array, typ)`, jednotně pro jednorozměrné i
  vícerozměrné pole
  ([5.2](#52-deklarace-a-inicializace--varianta-a-array-typ-výchozí-nuly),
  [6.2](#62-deklarace-a-inicializace-výchozí-nuly)).
- **Dvě definice `obj` se stejným jménem ve stejném viditelném rozsahu
  jsou chyba při kompilaci** — `obj` typy mezi sebou kolidují navzájem
  (jinak by `(obj, jmeno)` bylo nejednoznačné, kterou definici myslí).

### 10.7 Souhrnný příklad

```
obj(bod)
var(int, x, [0])
var(int, y, [0])
end obj

obj(usecka)
var((obj, bod), zacatek)
var((obj, bod), konec)
end obj

var((obj, usecka), u)
set(u.zacatek.x, [1])
set(u.zacatek.y, [2])
set(u.konec.x, [4])
set(u.konec.y, [6])

var(int, dx, [u.konec.x - u.zacatek.x])
var(int, dy, [u.konec.y - u.zacatek.y])
var(int, ctverec_delky, [dx * dx + dy * dy])
```

`bod` a `usecka` jsou dva `obj` typy — `usecka` používá `bod` jako typ
svých dvou členů (`zacatek`, `konec`), což demonstruje `obj` jako člen
jiného `obj` ([10.1](#101-definice-typu-objjmeno--end-obj)). Instance
`u` vznikne s oběma svými `bod` členy inicializovanými na `x = 0, y =
0`. Následné `set(u.zacatek.x, [1])` atd. zapisují do jednotlivých
souřadnic přes zřetězenou tečkovou notaci
([10.3](#103-čtení-hodnoty-člena-jmeno_instancejmeno_clenu),
[10.4](#104-zápis-do-člena-setjmeno_instancejmeno_clenu-výraz)). Po
všech čtyřech `set` příkazech je `u.zacatek = (1, 2)`, `u.konec = (4,
6)`; `dx = 3`, `dy = 4`, `ctverec_delky = 25`.

Příklad na vyhodnocení výchozí hodnoty **při každé instanci**
([10.5](#105-výchozí-hodnota-člena--vyhodnocuje-se-při-každé-instanci)):

```
var(int, pocitadlo, [10])

obj(citac)
var(int, hodnota, [pocitadlo])
end obj

var((obj, citac), c1)
set(pocitadlo, [20])
var((obj, citac), c2)
```

Ačkoliv `c1` i `c2` jsou instance téhož typu `citac` se stejnou
definicí členu `hodnota` (`[pocitadlo]`), `c1.hodnota` skončí na `10`
(hodnota `pocitadlo` v okamžiku vzniku `c1`), zatímco `c2.hodnota`
skončí na `20` (hodnota `pocitadlo` po pozdějším `set`, v okamžiku
vzniku `c2`) — obě instance dostaly různou počáteční hodnotu téhož
členu, protože `[pocitadlo]` se vyhodnotilo znovu při vzniku každé
z nich.

### 10.8 Konverze mezi `obj` a jinými typy — tiché vynechání

BASIX nezavádí žádnou implicitní ani explicitní konverzi, která by na
jedné ze stran zapojovala instanci `obj`. Konkrétně **žádná** konverze
neexistuje mezi:

- `obj` a skalárem (`int`/`real`);
- dvěma instancemi `obj` — bez ohledu na to, zda jde o stejný, nebo
  různý `obj` typ;
- `obj` a jednorozměrným, nebo vícerozměrným polem (`array`,
  [5](#5-jednorozměrné-pole-array),
  [6](#6-vícerozměrné-pole)) — v žádném směru.

**Tiché vynechání.** Tam, kde by taková konverze měla nastat (např.
`set(cil, [zdroj])`, kde jedna, nebo obě strany jsou `obj`, nebo
`{[obj_instance], ...}`, [5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)),
se místo konverze uplatní **tiché vynechání**: k žádnému přepisu
hodnoty **nedojde** a zúčastněné proměnné si ponechají svou dosavadní
hodnotu beze změny — stejná konvence tichého vynechání, jaká je použita
u výstupu pole odkazujícího na vícerozměrné pole v `print`
([7.3](#73-sémantika)).

Toto se týká i případů, kdy je `obj` členem jiného `obj`
([10.1](#101-definice-typu-objjmeno--end-obj)) — konverze na/z takového
vnořeného `obj` členu se řídí stejným pravidlem tichého vynechání, ne
rekurzivním prováděním konverze člen po členu.

**Vztah k obecnému konverznímu mechanismu polí.** Na rozdíl od
jednorozměrného a vícerozměrného pole, kde konverze mezi poli navzájem i mezi polem a
skalárem existuje a je přesně definovaná
([6.8](#68-implicitní-konverze-mezi-poli-a-mezi-polem-a-skalárem)), u
`obj` tedy žádná taková obdoba **záměrně nevzniká** v žádném směru —
mechanismus z [6.8](#68-implicitní-konverze-mezi-poli-a-mezi-polem-a-skalárem)
se na `obj` nijak nerozšiřuje. `obj` zůstává typem zcela mimo tento
konverzní mechanismus, se kterým lze pracovat výhradně po jednotlivých
členech ([10.3](#103-čtení-hodnoty-člena-jmeno_instancejmeno_clenu),
[10.4](#104-zápis-do-člena-setjmeno_instancejmeno_clenu-výraz)).

---

## 11. Funkce (`fun`)

### 11.1 Přehled

Základní pravidla:

1. **Funkce je pojmenovaný blok kódu s jedním povinným návratovým
   parametrem (`ret`) a libovolným počtem běžných parametrů (`par`)** —
   zapisuje se jako `fun(jmeno) ... end fun`, viz [11.2](#112-definice-funkce).
2. **Volání je vždy samostatný příkaz**, ne součást obecného `[vyraz]`
   — `jmeno([vyraz], ...)`, viz [11.4](#114-volání-funkce) a
   [11.8](#118-volání-jako-příkaz-vs-jako-součást-výrazu). Návratová
   hodnota se buď zahodí, nebo se zachytí speciální variantou `set`.
3. **`int`/`real` se předávají hodnotou, pole/`obj`
   odkazem** — viz [11.4](#114-volání-funkce). Odkaz se zapisuje
   zvláštním tvarem `[jmeno]`, ne obecným `[vyraz]`.
4. **Návrat z funkce** je buď explicitní (`return`), nebo přirozeným
   doběhnutím `tělo` na `end fun` — obojí rovnocenné, návratovou
   hodnotou je vždy aktuální hodnota `ret`, viz
   [11.3](#113-návratová-hodnota-return).
5. **Všechny funkce žijí na jediné globální úrovni**, nezávisle na
   pořadí zápisu i volání — odtud plyne i podpora přímé i nepřímé
   rekurze, viz [11.6](#116-rekurze) a
   [11.7](#117-globální-úroveň-definic-a-nezávislost-na-pořadí).
6. **Jména funkcí mají vlastní, oddělený jmenný prostor**, s výjimkou
   kolize s vyhrazenými klíčovými slovy jazyka — viz
   [11.5](#115-jmenný-prostor-funkcí-a-kolizní-pravidla).

### 11.2 Definice funkce

Definice funkce má tvar:

```
fun(jmeno)
ret(...)
par(...)
par(...)
par(...)
telo
end fun
```

**Odsazení.** Deklarace `ret(...)`/`par(...)` i celé `tělo` funkce se
zapisují odsazené doprava vůči řádkům `fun(jmeno)` a `end fun`,
jejichž jsou přímou součástí — stejná konvence jako odsazení `tělo`
vůči `code(label)`/`end code`
([4.3](#43-složený-příkaz-s-návěštím-code-a-jeho-ukončení-break)) a
obdobně u `while`/`loop`/`obj`. Jde ale, stejně jako u všech ostatních
složených příkazů hlavní specifikace, čistě o **vizuální konvenci**
pro čitelnost — odsazení (jeho přítomnost, míra, ani konzistence) nemá
žádný vliv na syntaxi ani sémantiku programu. Hranice definice funkce
určují výhradně samotné řádky `fun(jmeno)`/`end fun` a jednotlivých
`ret(...)`/`par(...)` deklarací; odsazení pouze opticky odlišuje tyto
deklarace a tělo od okolního programu.

kde:

- `jmeno` je identifikátor nové funkce, dle stejného pravidla pro
  pojmenování identifikátorů, jaké hlavní specifikace používá u
  proměnných, labelů a `obj` typů (3.2).
- `ret(...)` je deklarace **návratového parametru** — vždy přesně
  **jedna**, vždy jako **první** deklarace v definici funkce, hned za
  řádkem `fun(jmeno)`, před libovolným `par(...)`. Žádná funkce bez
  `ret(...)` není platná a `ret(...)` nesmí stát jinde než na této
  jediné, první pozici.
- `par(...)` značí obecně **libovolný počet** (0, 1, 2, ...) deklarací
  běžných parametrů funkce, každou na vlastním řádku, vždy až **za**
  jediným `ret(...)`. Na pořadí těchto deklarací záleží: pořadí, ve
  kterém jsou zapsány, přímo určuje jejich pořadí mezi sebou —
  relevantní pro poziční přiřazení argumentů při volání (viz pozdější
  sekce o volání funkce).
- `ret` i `par` mají **stejnou syntaxi jako `var(...)`** u proměnných
  (4.1) — liší se od `var(...)` výhradně tím, že místo klíčového
  slova `var` používají doslovné klíčové slovo `ret`, resp. `par`:

  ```
  ret(typ, jmeno_parametru)
  par(typ, jmeno_parametru)
  ```

  případně s třetím argumentem `[vyraz]`, stejně jako u `var(...)`:

  ```
  ret(typ, jmeno_parametru, [vyraz])
  par(typ, jmeno_parametru, [vyraz])
  ```

  kde `typ` je `int`, `real`, `(array, typ)`, nebo `(obj, typ)`
  (`(array, typ)` jednotně pro jednorozměrné i vícerozměrné pole),
  a `jmeno_parametru` je identifikátor parametru,
  platný uvnitř těla funkce jako běžná proměnná — beze změny oproti
  dřívějšímu návrhu parametrů.
- `telo` je tělo funkce — sekvence příkazů BASIXu, stejně jako
  `tělo`/`příkazy` u ostatních složených příkazů hlavní specifikace.
- `end fun` ukončuje definici.

Jako každý příkaz stojí `fun(jmeno)` a `end fun` samostatně na svém
řádku (3.1).

*(Jmenný prostor a kolizní pravidla viz
[11.5](#115-jmenný-prostor-funkcí-a-kolizní-pravidla), rekurze a
globální úroveň definic viz [11.6](#116-rekurze) a
[11.7](#117-globální-úroveň-definic-a-nezávislost-na-pořadí).)*

### 11.3 Návratová hodnota (`return`)

Příkaz pro návrat z funkce má tvar:

```
return
```

tedy holé klíčové slovo, **bez závorek a bez argumentu** — na rozdíl
od `break`/`continue`, které mohou (nepovinně) nést `label`
([4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue)),
`return` nepřijímá žádný argument ani label vůbec.

**Sémantika.** Provedení `return` okamžitě ukončí provádění **celé
funkce** (bez ohledu na to, kolik `code`/`while`/`loop`/`for`/
`dowhile`/`if`/`case` bloků je v tu chvíli vnořeno) — analogicky k
tomu, jak `break(label)` ukončí víceúrovňově všechny mezilehlé bloky
až po cílový ([4.5](#45-předčasné-ukončení-a-přeskočení-iterace-break-continue)),
jen zde je cílem vždy celá funkce, ne konkrétní label — `return` proto
sám žádný `label` nepotřebuje ani nepoužívá (funkce, na rozdíl od
`code`/`while`/.../`if`, nejsou vzájemně vnořitelné,
[11.7](#117-globální-úroveň-definic-a-nezávislost-na-pořadí), takže nemůže nastat nejednoznačnost,
„která" funkce se má ukončit). Návratovou hodnotou celého volání se
stává **aktuální hodnota návratového parametru** (`ret`,
[11.2](#112-definice-funkce)) — tedy taková, jaká je **v místě a
okamžiku provedení `return`**, přesně tak, jak ji tam zanechaly
případné předchozí `set(...)` do `ret` (žádná další úprava už
neproběhne).

**Přirozené doběhnutí `tělo` na konec — druhý, rovnocenný způsob
návratu.** Kromě explicitního `return` zůstává platné i přirozené
doběhnutí `tělo` funkce až na `end fun`, aniž by se po cestě provedl
jakýkoliv `return`. Funkce v takovém případě skončí stejně, jako by
na tomto místě (těsně před `end fun`) stálo `return` — návratovou
hodnotou volání se stává hodnota `ret` taková, jaká je **na konci
těla**. Obě cesty návratu (explicitní `return`, i přirozené
doběhnutí na konec) jsou tedy sémanticky rovnocenné v tom, co určuje
výslednou návratovou hodnotu — liší se jen v tom, odkud v `tělo`
k návratu dojde. Protože `ret` je vždy inicializován už při vstupu do
funkce (hodnotou z volání, resp. svou výchozí hodnotou dle
[11.2](#112-definice-funkce)), je dobře definovaná hodnota k vrácení
k dispozici v okamžiku jakéhokoliv návratu — nehrozí návrat
„nenastavené" hodnoty ani při zcela prázdném `tělo`.

### 11.4 Volání funkce

Volání funkce má tvar:

```
jmeno([vyraz], [vyraz], [vyraz])
```

kde:

- `jmeno` je identifikátor některé funkce definované na globální úrovni
  programu ([11.7](#117-globální-úroveň-definic-a-nezávislost-na-pořadí),
  `fun(jmeno) ... end fun`) — nezávisle na tom, zda se tato definice v
  textu programu nachází výše, nebo níže než dané volání
  ([11.7](#117-globální-úroveň-definic-a-nezávislost-na-pořadí)).
- **první** `[vyraz]` v seznamu je argument předávaný **návratovému
  parametru** `ret` — stává se jeho počáteční hodnotou při vstupu do
  funkce (`ret` může tuto hodnotu uvnitř `tělo` dál měnit přes
  `set(...)`, než se v okamžiku návratu — [11.3](#113-návratová-hodnota-return)
  — stane návratovou hodnotou volání).
- **ostatní** `[vyraz]` (druhý, třetí, ...) jsou argumenty předávané
  jednotlivým `par` parametrům — **poziční přiřazení zleva**: druhý
  `[vyraz]` odpovídá prvnímu `par(...)` v pořadí jeho deklarace
  ([11.2](#112-definice-funkce)), třetí `[vyraz]` druhému `par(...)`
  atd.
- Každý `[vyraz]` je hranatými závorkami uzavřený výraz dle
  [3.3](#33-syntaxe-výrazů) — stejná konvence jako u kteréhokoliv
  jiného `[vyraz]` v jazyce.

**Počet argumentů nemusí odpovídat počtu parametrů — chybějící se
doplní výchozí hodnotou.** Volání nemusí uvést argument pro **úplně
každý** `ret`/`par` parametr funkce: argumenty se parametrům přiřazují
pozičně **zleva** (viz výše — první `[vyraz]` vždy `ret`, další
postupně jednotlivým `par` v pořadí deklarace), a chybí-li na konci
seznamu argumentů volání jeden nebo více `[vyraz]`, zbylé (nejvíc
vpravo ležící) parametry — ať už `ret`, nebo některý z `par` — si
ponechají svou **výchozí hodnotu z vlastní definice**
([11.2](#112-definice-funkce)): explicitně zapsanou `[vyraz]` u
`ret(typ, jmeno, [vyraz])`/`par(typ, jmeno, [vyraz])`, nebo (není-li
`[vyraz]` u dané deklarace vůbec přítomen) implicitní nulovou hodnotu
daného typu — stejná konvence jako u zkráceného `var(typ, jmeno)`
([4.1](#41-deklarace-a-inicializace-proměnné-var)). Volání zcela bez
argumentů (`jmeno()`) je tedy platné u libovolné funkce — `ret` i
všechny `par` dostanou své výchozí hodnoty.

**Pořadí vyhodnocení argumentů je zleva doprava.** Jsou-li ve volání
uvedeny dva a více `[vyraz]` argumentů, vyhodnocují se v přesně tom
pořadí, v jakém jsou v seznamu volání textově zapsány — tedy nejprve
(úplně) první `[vyraz]` (ten pro `ret`), pak druhý (první `par`), pak
třetí atd., zleva doprava, jeden po druhém. Teprve až jsou takto
vyhodnoceny **všechny** uvedené argumenty, dosadí se jejich hodnoty do
odpovídajících `ret`/`par` parametrů a začne se provádět `tělo`
funkce ([11.2](#112-definice-funkce)) — vyhodnocení žádného argumentu
tedy nezávisí na tom, jestli už proběhlo dosazení do parametrů z
argumentu předchozího.

**`int`/`real` hodnotou, pole a `obj` odkazem.** Způsob, jakým se
argument stane hodnotou parametru `ret`/`par`, závisí na jeho typu
([11.2](#112-definice-funkce)):

- Je-li typ parametru `int` nebo `real`, předává se argument
  **hodnotou** — parametr při vstupu do funkce dostane vlastní,
  nezávislou **kopii** vyhodnocené hodnoty. Jakákoli případná další
  změna tohoto parametru přes `set(...)` uvnitř `tělo` funkce
  ([4.2](#42-přiřazení-hodnoty-do-proměnné-set))
  se nijak neprojeví na straně volajícího.
- Je-li typ parametru `(array, typ)`
  ([5](#5-jednorozměrné-pole-array),
  [6](#6-vícerozměrné-pole)), nebo
  `(obj, typ)`
  ([10](#10-složený-datový-typ-obj)), předává se
  argument **odkazem** — parametr uvnitř `tělo` funkce neoznačuje svou
  vlastní kopii, ale **tu samou** instanci pole/`obj`, kterou označuje
  argument na straně volajícího. Jakýkoli zápis do prvku pole
  ([5.5](#55-zápis-do-prvku-set-jmenoindex-výraz),
  [6.4](#64-zápis-do-prvku-set-jmenovyrazvyraz-vyraz))
  nebo do člena `obj` instance
  ([10.4](#104-zápis-do-člena-set-jmeno_instancejmeno_clenu-výraz))
  provedený uvnitř `tělo` funkce se tedy ihned projeví i na straně
  volajícího a přetrvá i po návratu z funkce — na rozdíl od `int`/`real`
  výše. To je odlišné od chování celého `set(...)` mezi dvěma poli
  mimo kontext volání funkce
  ([5.8](#58-zápis-celého-pole-jako-čísla-textu-nebo-kopie-jiného-pole-set)),
  kde jde o **kopii** obsahu — u předání pole/`obj` jako argumentu
  funkci žádná taková kopie nevzniká.
- **Důsledek pro `ret` typu pole/`obj`.** Platí pro něj totéž pravidlo
  odkazu jako pro `par` výše: je-li ve volání uveden argument, stává se
  `ret` odkazem na tutéž instanci, kterou argument označuje — veškeré
  změny `ret` uvnitř `tělo` se pak rovnou promítají do proměnné
  volajícího, nezávisle na tom, co se nakonec vrátí jako návratová
  hodnota volání ([11.3](#113-návratová-hodnota-return)). Není-li pro
  `ret` argument uveden (chybí, viz výše), nemá se k čemu odkazovat —
  `ret` v takovém případě dostane vlastní, novou instanci s výchozí
  hodnotou dle své definice, nezávislou na čemkoliv na straně
  volajícího.

**Syntaktická podoba argumentu pole/`obj` — `[jmeno]`.**
Je-li typ odpovídajícího `ret`/`par` parametru `(array, typ)`
(jednorozměrné i vícerozměrné), nebo `(obj, typ)`, nestojí na této
pozici argumentu obecný `[vyraz]` dle [3.3](#33-syntaxe-výrazů), ale
zvláštní, na tuto pozici vázaný tvar:

```
[jmeno]
```

kde `jmeno` je **holý identifikátor** již existující proměnné (nebo
jiného `par`/`ret` parametru, viz níže) přesně odpovídajícího typu —
stejná konvence, jakou hlavní specifikace už používá pro `[jmeno_pole]`
v [5.3](#53-deklarace-a-inicializace--varianta-b-hodnoty-velikost-dle-počtu)
a [5.8](#58-zápis-celého-pole-jako-čísla-textu-nebo-kopie-jiného-pole-set).
Tento tvar je zvláštní výjimka platná **jen na této konkrétní pozici**
(argument par/ret parametru typu pole/`obj` u volání
funkce) — nejde o rozšíření obecné gramatiky `[vyraz]` platné všude v
jazyce.

- **Jen holé jméno, nic jiného.** Na této pozici nesmí stát indexace
  (`pole[i]`), operace, ani literál — jen samotný identifikátor
  označující konkrétní, adresovatelnou instanci pole/`obj`.
- **Typ musí odpovídat přesně, žádná implicitní konverze.** Na rozdíl
  od `set(pole1, [pole2])`
  ([5.8](#58-zápis-celého-pole-jako-čísla-textu-nebo-kopie-jiného-pole-set)),
  kde se při kopírování smí prvky implicitně konvertovat `int ↔ real`
  ([2.4](#24-implicitní-konverze-mezi-typy)), zde
  jde o **alias**, ne o kopii: typ `jmeno` musí přesně odpovídat
  deklarovanému typu parametru (stejný typ prvku, stejná
  dimenzionalita u vícerozměrného pole, stejný `obj` typ u `obj`) — jiný,
  byť implicitně převoditelný typ, je chyba při kompilaci.
- **Velikost pole se při volání nekontroluje.** Typ `(array, typ)`
  neurčuje velikost (ta je vlastností konkrétní instance, ne typu) —
  parametr prostě přebírá velikost té instance, na kterou byl navázán;
  uvnitř `tělo` funkce ji lze zjistit obvyklým způsobem.
- **`jmeno` smí být i jiný `par`/`ret` parametr** typu pole/`obj` — to
  umožňuje odkaz „protáhnout" beze změny dál do vnořeného
  volání, aniž by vznikla jakákoli kopie; parametr se uvnitř `tělo`
  chová jako běžná proměnná odpovídajícího typu ([11.2](#112-definice-funkce)).

*(Volání jako výraz vs. jako samostatný příkaz viz
[11.8](#118-volání-jako-příkaz-vs-jako-součást-výrazu). Rekurze viz
[11.6](#116-rekurze).)*

---

### 11.5 Jmenný prostor funkcí a kolizní pravidla

Jména funkcí mají vlastní, **oddělený jmenný prostor** od jmen
proměnných, polí, labelů i `obj` typů — analogicky k tomu, jak vlastní
oddělený jmenný prostor mají `obj` typy
([10.6](#106-jmenný-prostor-obj-typů-a-kolizní-pravidla)):

- Jméno funkce (to `jmeno` v `fun(jmeno) ... end fun`,
  [11.2](#112-definice-funkce)) **nekoliduje** se jménem žádné
  proměnné, pole, labelu, ani `obj` typu — smí být stejné jako
  kterékoli z nich, aniž by šlo o chybu při kompilaci.
- Kontext je vždy jednoznačný: jméno funkce se objevuje výhradně na
  dvou místech — v definici (`fun(jmeno)`, [11.2](#112-definice-funkce))
  a při volání (`jmeno(...)`, [11.4](#114-volání-funkce)) — nikdy jinde
  (nikdy jako operand výrazu, cíl `set(...)`, label u `break`/`continue`,
  ani jako `typ` u `var(...)`). Kompilátor tedy rozlišuje jméno funkce
  od jména proměnné/pole/labelu/`obj` typu podle syntaktické pozice, ne
  podle sdíleného jmenného prostoru — stejný princip rozlišení podle
  pozice v gramatice, jaký používají `obj` typy
  ([10.6](#106-jmenný-prostor-obj-typů-a-kolizní-pravidla))
  i jinde v jazyce.
- **Dvě definice funkce se stejným jménem jsou chyba při kompilaci** —
  jména funkcí mezi sebou kolidují navzájem (jinak by volání
  `jmeno(...)` bylo nejednoznačné, kterou definici myslí) — stejné
  pravidlo jako u kolize dvou `obj` typů stejného jména
  ([10.6](#106-jmenný-prostor-obj-typů-a-kolizní-pravidla)).
  Protože všechny funkce žijí na jediné, společné globální úrovni
  ([11.7](#117-globální-úroveň-definic-a-nezávislost-na-pořadí)), je
  „stejný viditelný rozsah" u funkcí vždy **celý program** — na rozdíl
  od proměnných (kde o kolizi rozhoduje konkrétní lexikální
  rozsah/blok) tedy u funkcí není možné mít dvě různé funkce téhož
  jména vedle sebe v žádné kombinaci umístění v programu.

Jména funkcí navíc podléhají obecnému zákazu kolize s klíčovými slovy
jazyka z [3.2](#32-pojmenování-identifikátorů) — viz tam pro úplný
seznam i důvod (stejný vnější tvar `slovo(...)` jako volání funkce).

---

### 11.6 Rekurze

**Rekurze je v BASIXu povolena.** Funkce smí ve svém vlastním `tělo`
volat sama sebe — takové (přímé) rekurzivní volání se řídí zcela
stejnými pravidly jako volání jakékoli jiné funkce
([11.4](#114-volání-funkce)): stejná syntaxe `jmeno([vyraz], ...)`,
stejné poziční přiřazení argumentů `ret`/`par`, stejné doplnění
chybějících argumentů výchozími hodnotami. Žádné zvláštní klíčové
slovo ani odlišný zápis pro rekurzivní volání neexistuje.

**Jméno funkce je pro účely volání dostupné odkudkoli v programu.**
Aby bylo přímé rekurzivní volání vůbec možné, platí (upřesnění k
[11.4](#114-volání-funkce)): jméno funkce je platné pro volání bez
ohledu na to, kde přesně v textu programu leží `fun(jmeno) ... end fun`
vůči danému volání — tedy i uvnitř vlastního `tělo` dané funkce, ještě
před dosažením jejího `end fun`. Volání funkce jejím vlastním jménem
uvnitř jejího `tělo` proto není chybou „nedeklarovaného identifikátoru",
i když definice funkce v tu chvíli ještě formálně nedoběhla k `end
fun`. Toto je jen speciální případ (funkce volající sebe samu) obecného
pravidla, že jméno žádné funkce v BASIXu nezávisí na pořadí zápisu
vůči jinému místu v programu — viz
[11.7](#117-globální-úroveň-definic-a-nezávislost-na-pořadí).

**Každé (i rekurzivní) volání má vlastní, nezávislou instanci
parametrů.** Každé volání funkce — ať vzniklé zvenčí, nebo rekurzivně
zevnitř jiného, dosud neukončeného volání téže funkce — dostává svou
**vlastní, od ostatních současně rozběhnutých volání nezávislou**
instanci `ret` i všech `par` ([11.2](#112-definice-funkce)). Volání,
které rekurzivně zavolalo další (vnořené) volání, zůstává po dobu jeho
běhu pozastavené (analogicky k tomu, jak volání funkce obecně čeká na
dokončení volané funkce, [11.3](#113-návratová-hodnota-return)) — se
svými vlastními hodnotami `ret`/`par` beze změny — a pokračuje dál (od
místa za rekurzivním voláním) až po jeho návratu. Změny `ret`/`par`
provedené uvnitř vnořeného (rekurzivního) volání se tedy nijak
neprojeví na hodnotách `ret`/`par` volání, ze kterého bylo zavoláno.

Toto neomezuje ani nemění, jak funkce samotné **nejsou vzájemně
vnořitelné na úrovni definice**
([11.7](#117-globální-úroveň-definic-a-nezávislost-na-pořadí))
— to pravidlo se týká zápisu `fun ... end fun` bloků v kódu (nelze
napsat definici funkce dovnitř těla jiné definice) a rekurze na úrovni
**volání za běhu** se s ním nijak nekříží — pořád jde o jedinou
definici, jen volanou (potenciálně) vícekrát „do hloubky".

**Nepřímá (vzájemná) rekurze je tímto také vyřešena.** Protože všechny
funkce žijí na jediné, společné globální úrovni, nezávisle na pořadí
svého zápisu v textu programu ([11.7](#117-globální-úroveň-definic-a-nezávislost-na-pořadí)),
smí funkce **A** volat funkci **B**, i když je `fun(B)` v textu
programu zapsáno **až za** `fun(A)` — a `B` smí zpětně volat `A`. Řetěz
vzájemných volání se tak může uzavřít v cyklus (A → B → A → ...) stejně
jako u přímé rekurze výše; jde jen o řadu volání „za běhu" mezi více
různými, ale všemi rovnocenně dostupnými funkcemi.

*(Limit hloubky rekurze — přímé i nepřímé — daný reálnými prostředky
běhového prostředí, na rozdíl od jazyka samotného, není předmětem této
specifikace.)*

---

### 11.7 Globální úroveň definic a nezávislost na pořadí

**Všechny funkce musí být definovány na globální úrovni programu.**
Definice funkce (`fun(jmeno) ... end fun`, [11.2](#112-definice-funkce))
smí být zapsána pouze přímo na nejvyšší (globální) úrovni programu —
**nikdy** vnořeně dovnitř jiného složeného příkazu hlavní specifikace
(`code`, `while`, `loop`, `for`, `dowhile`, `if`, `case`) ani dovnitř
`tělo` jiné funkce. Toto je přísnější, obecnější verze pravidla, že
funkce nejsou vzájemně vnořitelné — netýká se to jen jiných funkcí, ale úplně libovolného obklopujícího
bloku: `fun(jmeno)` prostě nesmí mít nad sebou v hierarchii bloků nic
jiného než samotný program.

**Na pořadí definic ani volání nezáleží.** Všechny funkce definované
na globální úrovni jsou navzájem — bez ohledu na to, v jakém pořadí je
program textově zapisuje — **stejnou měrou viditelné a volatelné** z
`tělo` kterékoli z nich, i z hlavního těla programu mimo libovolnou
funkci. Konkrétně to znamená:

- Funkce `A` smí volat funkci `B`, i když je `fun(B)` v textu programu
  zapsáno **až za** `fun(A)` (tzv. „dopředné volání") — na rozdíl od
  toho, jak u proměnných obecně platí, že musí být deklarovány dřív,
  než se použijí ([4.1](#41-deklarace-a-inicializace-proměnné-var)),
  u funkcí žádná taková podmínka pořadí neplatí.
- Odsud přímo plyne i to, že přímá rekurze ([11.6](#116-rekurze)) i
  nepřímá/vzájemná rekurze mezi libovolným počtem funkcí jsou obě
  platné bez výjimky — jde jen o zvláštní případ tohoto obecnějšího
  pravidla nezávislosti na pořadí.
- Toto pravidlo se týká výhradně **volání** funkcí (11.4) — nemění nic
  na tom, že dvě funkce nesmí sdílet stejné jméno
  ([11.5](#115-jmenný-prostor-funkcí-a-kolizní-pravidla)); jde o
  viditelnost/dostupnost ke správně, jednoznačně pojmenovaným funkcím,
  ne o rozvolnění kolizních pravidel.

---

### 11.8 Volání jako příkaz vs. jako součást výrazu

**Volání funkce zůstává výhradně samostatným příkazem** —
`jmeno([vyraz], ...)` ([11.4](#114-volání-funkce)) smí stát jen
samostatně na svém řádku, ne jako operand uvnitř obecného `[vyraz]`
([3.3](#33-syntaxe-výrazů)). Zápis jako `[foo(1) + bar(2)]` je tedy
**neplatný** — volání funkce se **nesmí** objevit uvnitř hranatých
závorek `[vyraz]` spolu s operátory, literály, ani jinými proměnnými.

**Důvod.** Operandy obecné gramatiky výrazu (literál, proměnná,
vnořená operace, [3.3](#33-syntaxe-výrazů)) jsou dnes vždy beze
**vedlejších účinků** — u operace jako `a + b` proto nezáleží na
pořadí, v jakém by se `a` a `b` případně vyhodnocovaly, protože ani
jedno vyhodnocení nemůže ovlivnit to druhé. Volání funkce ale vedlejší
účinky mít **může** — může měnit pole/`obj` předané odkazem
([11.4](#114-volání-funkce)). Kdyby se volání směla objevovat jako
operandy uvnitř `[vyraz]`, musela by se navíc zavést zcela nová
pravidla o pořadí vyhodnocení operandů **libovolné** operace v jazyce
— což by byl zásah do gramatiky `[vyraz]` sdílené napříč celou hlavní
specifikací, ne jen do funkcí. Tomuto zásahu se tímto pravidlem
záměrně vyhýbáme — ze stejného důvodu, proč byl v
[11.4](#114-volání-funkce) zvolen samostatný, na pozici vázaný tvar
`[jmeno]` pro argumenty pole/`obj`, místo rozšíření obecné gramatiky
`[vyraz]`.

**Zachycení návratové hodnoty — nová, čtvrtá speciální varianta
`set`.** Aby šlo návratovou hodnotu volání přesto použít dál (uložit
do proměnné), zavádí se — po vzoru tří speciálních variant `set`
popsaných v hlavní specifikaci
([5.8](#58-zápis-celého-pole-jako-čísla-textu-nebo-kopie-jiného-pole-set),
varianty A/B/C) — **čtvrtá** speciální varianta:

```
set(cil, jmeno([vyraz], ...))
```

kde zdrojová pozice (druhý argument `set`) není obecné `[vyraz]`, ale
přímo volání funkce ([11.4](#114-volání-funkce)) bez vlastních
obalujících `[]` (volání už má svoje vlastní kulaté závorky
`jmeno(...)`, další vnější hranaté `[]` by byly nadbytečné a nejsou
součástí tohoto tvaru). Volání se provede celé (včetně vyhodnocení
všech jeho argumentů, [11.4](#114-volání-funkce)) a jeho výslednou
návratovou hodnotou ([11.3](#113-návratová-hodnota-return)) se přepíše
`cil`, stejnou konvencí jako u běžného `set(cil, [vyraz])`
([4.2](#42-přiřazení-hodnoty-do-proměnné-set)).

- `cil` musí typem odpovídat typu `ret` volané funkce ([11.2](#112-definice-funkce)).
- Je-li typ `ret` volané funkce `int`/`real`, jde o běžné přiřazení
  hodnotou — `cil` je tedy typicky sám `int`/`real`.
- Je-li typ `ret` pole/`obj`, `ret` je (byl-li ve volání
  uveden argument) odkazem na existující instanci již od okamžiku
  volání ([11.4](#114-volání-funkce)) — zachytávat návratovou hodnotu
  touto variantou `set` proto typicky nemá smysl (odkaz na výslednou
  instanci má volající už ze svého vlastního argumentu); tato varianta
  `set` je tedy určena především pro `ret` typu `int`/`real`.

**Volání zůstává platné i bez zachycení návratové hodnoty.** Prostý
samostatný příkaz `jmeno([vyraz], ...)` beze `set` zůstává i nadále
plně platný — návratová hodnota se v takovém případě prostě zahodí;
volání je i tak smysluplné, mění-li funkce pole/`obj` předané odkazem,
nebo provádí-li výstup (`print`, ...) uvnitř svého `tělo`.

---

*Dokument bude průběžně aktualizován podle dalších rozhodnutí o návrhu
jazyka BASIX. Generování samotného kompilátoru začne až po výslovném
pokynu.*
