mirror of
https://github.com/Nexoniarz/Finch.git
synced 2026-11-03 00:44:27 +00:00
Docs for Finch 2.0: beginners, technicians, engineers (en, pl); READMEs; raylib example
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
parent
c7ddd4d8b6
commit
3e55da2645
13 changed files with 2590 additions and 2140 deletions
69
README.md
69
README.md
|
|
@ -25,19 +25,24 @@ fn main() {
|
||||||
## Why Finch
|
## Why Finch
|
||||||
|
|
||||||
- **Simple.** No semicolons, no headers, no preprocessor. Each thing has one way to do it.
|
- **Simple.** No semicolons, no headers, no preprocessor. Each thing has one way to do it.
|
||||||
- **Fast.** It compiles through LLVM's `-O2` pipeline to native code, with no runtime or garbage collector.
|
- **Fast.** It compiles through LLVM's `-O2` pipeline to native code, with no garbage collector.
|
||||||
Recursive `fib(40)` runs in about 0.19 s (`clang -O2` on the same C: about 0.23 s).
|
Recursive `fib(40)` runs in about 0.19 s (`clang -O2` on the same C: about 0.23 s); bounds-checked
|
||||||
- **Safer than C, where it is cheap.** No silent narrowing and no signed/unsigned mixing. Division by zero
|
array code matches C.
|
||||||
and null `.value` stop with a clear runtime error instead of undefined behavior. Operator precedence
|
- **Memory without the pain.** Lists, text and structs are values: assigning copies, and the end of a
|
||||||
that does not bite (`x & 1 == 0` means what it says).
|
block frees them. There is no `free` to forget, no use-after-free, and every test is clean under valgrind.
|
||||||
|
- **Safer than C, where it is cheap.** No silent narrowing and no signed/unsigned mixing. Out-of-range
|
||||||
|
indexes, division by zero and null pointers stop with a clear runtime error instead of undefined behavior.
|
||||||
|
Operator precedence that does not bite (`x & 1 == 0` means what it says).
|
||||||
- **Errors that talk like a person:**
|
- **Errors that talk like a person:**
|
||||||
```
|
```
|
||||||
game.fn:3:13: error: 'y' must be i32, but this is int (use i32(...) to convert)
|
game.fn:3:13: error: 'y' must be i32, but this is int (use i32(...) to convert)
|
||||||
3 | i32 y = x
|
3 | i32 y = x
|
||||||
| ^
|
| ^
|
||||||
```
|
```
|
||||||
- **Any C library, directly.** `import "GLFW/glfw3.h"` + `link "glfw"`, and you can call it.
|
- **Any C library, directly.** `import "raylib.h"` + `link "raylib"`, and you can call it, structs by value
|
||||||
Headers are read by libclang, so there is nothing to declare by hand.
|
and callbacks included. Headers are read by libclang, so there is nothing to declare by hand.
|
||||||
|
- **Written in itself, too.** `boot/` is a Finch compiler written in Finch that compiles itself to a
|
||||||
|
byte-identical result.
|
||||||
|
|
||||||
## Quick start
|
## Quick start
|
||||||
|
|
||||||
|
|
@ -52,7 +57,8 @@ ninja -C build
|
||||||
|
|
||||||
./build/finch run examples/hello.fn
|
./build/finch run examples/hello.fn
|
||||||
./build/finch build examples/tour.fn -o tour && ./tour
|
./build/finch build examples/tour.fn -o tour && ./tour
|
||||||
tests/run.sh # 34 passed, 0 failed
|
tests/run.sh # 58 passed, 0 failed
|
||||||
|
tests/boot.sh # the compiler written in Finch builds itself
|
||||||
```
|
```
|
||||||
|
|
||||||
## Documentation
|
## Documentation
|
||||||
|
|
@ -70,14 +76,17 @@ Pick the guide that fits you:
|
||||||
| | |
|
| | |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Variables | `x := 5` (inferred) or `int x = 5` |
|
| Variables | `x := 5` (inferred) or `int x = 5` |
|
||||||
| Types | `int` `float` `bool` `char` `str`, sized `i8`…`i64` `u8`…`u64` `f32` `f64`, pointers `ptr[T]` / `ptr` |
|
| Types | `int` `float` `bool` `char` `str`, sized `i8`…`i64` `u8`…`u64` `f32` `f64`, arrays `[]T`, pointers `ptr[T]` |
|
||||||
| Functions | `fn add(int a, int b) -> int { return a + b }` |
|
| Functions | `fn add(int a, int b) -> int { return a + b }` |
|
||||||
| Control | `if` / `else if` / `else`, `while`, `for i in 0..10`, `break`, `continue` |
|
| Structs | `struct Point { … }` with one field per line (`int x`, `int y = 0`); create with `Point(1, 2)` or `Point(x: 1)` |
|
||||||
| Pointers | `p := addr(x)`, `p.value = 5`, `null` |
|
| Arrays | `nums := [1, 2, 3]`, `nums.push(4)`, `nums[0]`, `nums.len`, `for n in nums { }` |
|
||||||
| Conversions | `int(3.9)`, `u8(x)`, `float(n)` (implicit only when nothing is lost) |
|
| Text | `"a" + "b"`, `str(42)`, `int("42")`, `s.split(",")`, `s.upper()`, `s[0]` |
|
||||||
| Operators | `+ - * / %`, `& \| ^ << >> ~`, `== != < <= > >=`, `&& \|\| !` |
|
| Control | `if` / `else if` / `else`, `while`, `for i in 0..10`, `break`, `continue`, `defer` |
|
||||||
| C interop | `import "stdio.h"`, `link "glfw"` |
|
| Memory | automatic for arrays, text and structs; `new(...)` / `free(...)` for your own heap structures |
|
||||||
| Output | `print(a, b, c)` prints anything, separated by spaces |
|
| Modules | `import shapes` → `shapes.area(b)` |
|
||||||
|
| C interop | `import "stdio.h"`, `link "glfw"`, `link "mine.c"`, `addr(fn)` for callbacks |
|
||||||
|
| I/O | `print(...)`, `input("? ")`, `read_file`, `write_file`, `shell` |
|
||||||
|
| Tools | `finch run/build/ir`, `-g` for gdb, `-O0` |
|
||||||
|
|
||||||
## Examples
|
## Examples
|
||||||
|
|
||||||
|
|
@ -85,32 +94,42 @@ Pick the guide that fits you:
|
||||||
|---|---|
|
|---|---|
|
||||||
| [`examples/hello.fn`](examples/hello.fn) | the smallest program |
|
| [`examples/hello.fn`](examples/hello.fn) | the smallest program |
|
||||||
| [`examples/tour.fn`](examples/tour.fn) | variables, functions, conditions, loops |
|
| [`examples/tour.fn`](examples/tour.fn) | variables, functions, conditions, loops |
|
||||||
|
| [`examples/guess.fn`](examples/guess.fn) | a guessing game: input, loops, C's `rand` |
|
||||||
|
| [`examples/todo.fn`](examples/todo.fn) | structs, arrays, strings and files |
|
||||||
|
| [`examples/structs.fn`](examples/structs.fn) | structs, arrays of structs, a linked list with `new`/`free` |
|
||||||
| [`examples/types.fn`](examples/types.fn) | sized numbers and pointers |
|
| [`examples/types.fn`](examples/types.fn) | sized numbers and pointers |
|
||||||
| [`examples/c_import.fn`](examples/c_import.fn) | `printf`, `math.h`, `malloc`/`free`, `stderr` |
|
| [`examples/c_import.fn`](examples/c_import.fn) | `printf`, `math.h`, `malloc`/`free`, `stderr` |
|
||||||
| [`examples/window.fn`](examples/window.fn) | a GLFW + OpenGL window |
|
| [`examples/window.fn`](examples/window.fn) | a GLFW + OpenGL window |
|
||||||
|
| [`examples/raylib.fn`](examples/raylib.fn) | raylib with C structs by value |
|
||||||
| [`examples/llvm.fn`](examples/llvm.fn) | Finch building LLVM IR through the LLVM-C API |
|
| [`examples/llvm.fn`](examples/llvm.fn) | Finch building LLVM IR through the LLVM-C API |
|
||||||
|
| [`boot/`](boot/) | the Finch compiler, written in Finch |
|
||||||
|
|
||||||
## Roadmap
|
## Roadmap
|
||||||
|
|
||||||
- [x] Lexer, parser, LLVM codegen, O2 optimization
|
- [x] Lexer, parser, LLVM codegen, O2 optimization
|
||||||
- [x] Types incl. sized integers, pointers, conversions; functions; `if`/`while`/`for`
|
- [x] Types incl. sized integers, pointers, conversions; functions; `if`/`while`/`for`
|
||||||
- [x] Readable compile errors; runtime checks (division, null)
|
- [x] Readable compile errors; runtime checks (division, null, bounds)
|
||||||
- [x] Bitwise operators with sane precedence
|
- [x] Bitwise operators with sane precedence
|
||||||
- [x] C headers through libclang; `link` with pkg-config; link-error advice
|
- [x] C headers through libclang; `link` with pkg-config; link-error advice
|
||||||
- [ ] `struct` (and C structs by value)
|
- [x] `struct`, including C structs by value (System V ABI) and callbacks
|
||||||
- [ ] Arrays/slices with `.len` and bounds checks
|
- [x] Arrays with `.len`, bounds checks and methods; `for x in list`
|
||||||
- [ ] Memory: automatic free at the end of the owning block, `defer`, manual `free` when wanted
|
- [x] Memory: values freed at the end of their block, `defer`, `new`/`free`
|
||||||
- [ ] Strings: `+`, `len`, `str(x)`; `input()`
|
- [x] Strings: `+`, `.len`, indexing, methods, `str(x)`, `int(s)`; `input()`; files
|
||||||
- [ ] Finch modules (`import math`)
|
- [x] Finch modules (`import name`)
|
||||||
- [ ] Debug info (DWARF)
|
- [x] Debug info (`-g`)
|
||||||
- [ ] Bootstrap: the Finch compiler written in Finch
|
- [x] Bootstrap: a Finch compiler written in Finch that builds itself
|
||||||
|
- [ ] Methods on structs, maps, `match`
|
||||||
|
- [ ] Error values instead of stopping the program
|
||||||
|
- [ ] More platforms (ARM64, macOS)
|
||||||
|
|
||||||
## Layout
|
## Layout
|
||||||
|
|
||||||
```
|
```
|
||||||
src/ compiler: lexer, parser, AST, codegen, C import, driver (C++17, ~2.4k lines)
|
src/ compiler: lexer, parser, AST, codegen, C import + ABI, driver (C++17, ~4.5k lines)
|
||||||
|
runtime/ the small C runtime linked into every program
|
||||||
|
boot/ the Finch compiler written in Finch (~3k lines)
|
||||||
examples/ example programs
|
examples/ example programs
|
||||||
tests/ run/ (golden output), fail/ (expected errors), run.sh
|
tests/ run/ (golden output), fail/ (expected errors), run.sh, boot.sh
|
||||||
docs/ en/ and pl/ guides for three audiences
|
docs/ en/ and pl/ guides for three audiences
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
65
README.pl.md
65
README.pl.md
|
|
@ -25,10 +25,13 @@ fn main() {
|
||||||
## Dlaczego Finch
|
## Dlaczego Finch
|
||||||
|
|
||||||
- **Prosty.** Bez średników, bez plików nagłówkowych, bez preprocesora. Każdą rzecz robi się na jeden sposób.
|
- **Prosty.** Bez średników, bez plików nagłówkowych, bez preprocesora. Każdą rzecz robi się na jeden sposób.
|
||||||
- **Szybki.** Kompiluje się przez potok `-O2` z LLVM do kodu natywnego, bez środowiska uruchomieniowego i garbage collectora.
|
- **Szybki.** Kompiluje się przez potok `-O2` z LLVM do kodu natywnego, bez garbage collectora.
|
||||||
Rekurencyjne `fib(40)` trwa ok. 0,19 s (`clang -O2` na tym samym kodzie C: ok. 0,23 s).
|
Rekurencyjne `fib(40)` trwa ok. 0,19 s (`clang -O2` na tym samym kodzie C: ok. 0,23 s), a kod na tablicach
|
||||||
|
z kontrolą zakresu dorównuje C.
|
||||||
|
- **Pamięć bez bólu.** Listy, teksty i struktury są wartościami: przypisanie kopiuje, a koniec bloku je zwalnia.
|
||||||
|
Nie ma `free`, o którym można zapomnieć, nie ma użycia po zwolnieniu, a każdy test jest czysty pod valgrindem.
|
||||||
- **Bezpieczniejszy niż C tam, gdzie to tanie.** Nie ma cichego zwężania typów ani mieszania liczb ze znakiem
|
- **Bezpieczniejszy niż C tam, gdzie to tanie.** Nie ma cichego zwężania typów ani mieszania liczb ze znakiem
|
||||||
i bez znaku. Dzielenie przez zero i `.value` na null zatrzymują program czytelnym błędem, zamiast
|
i bez znaku. Indeks poza zakresem, dzielenie przez zero i null zatrzymują program czytelnym błędem, zamiast
|
||||||
powodować niezdefiniowane zachowanie. Priorytety operatorów nie gryzą (`x & 1 == 0` znaczy to, co widać).
|
powodować niezdefiniowane zachowanie. Priorytety operatorów nie gryzą (`x & 1 == 0` znaczy to, co widać).
|
||||||
- **Błędy mówią po ludzku:**
|
- **Błędy mówią po ludzku:**
|
||||||
```
|
```
|
||||||
|
|
@ -36,8 +39,10 @@ fn main() {
|
||||||
3 | i32 y = x
|
3 | i32 y = x
|
||||||
| ^
|
| ^
|
||||||
```
|
```
|
||||||
- **Każda biblioteka C, bezpośrednio.** Piszesz `import "GLFW/glfw3.h"` i `link "glfw"`, i możesz z niej korzystać.
|
- **Każda biblioteka C, bezpośrednio.** Piszesz `import "raylib.h"` i `link "raylib"`, i możesz z niej korzystać,
|
||||||
Nagłówki czyta libclang, więc nie trzeba niczego deklarować ręcznie.
|
także ze struktur przekazywanych przez wartość i z callbacków. Nagłówki czyta libclang, więc nie trzeba niczego deklarować ręcznie.
|
||||||
|
- **Napisany także w sobie.** `boot/` to kompilator Fincha napisany w Finchu, który kompiluje sam siebie
|
||||||
|
do identycznego co do bajtu wyniku.
|
||||||
|
|
||||||
## Szybki start
|
## Szybki start
|
||||||
|
|
||||||
|
|
@ -52,7 +57,8 @@ ninja -C build
|
||||||
|
|
||||||
./build/finch run examples/hello.fn
|
./build/finch run examples/hello.fn
|
||||||
./build/finch build examples/tour.fn -o tour && ./tour
|
./build/finch build examples/tour.fn -o tour && ./tour
|
||||||
tests/run.sh # 34 passed, 0 failed
|
tests/run.sh # 58 passed, 0 failed
|
||||||
|
tests/boot.sh # kompilator napisany w Finchu buduje sam siebie
|
||||||
```
|
```
|
||||||
|
|
||||||
## Dokumentacja
|
## Dokumentacja
|
||||||
|
|
@ -70,14 +76,17 @@ Wybierz przewodnik dla siebie:
|
||||||
| | |
|
| | |
|
||||||
|---|---|
|
|---|---|
|
||||||
| Zmienne | `x := 5` (typ zgadnięty) albo `int x = 5` |
|
| Zmienne | `x := 5` (typ zgadnięty) albo `int x = 5` |
|
||||||
| Typy | `int` `float` `bool` `char` `str`, z rozmiarem `i8`…`i64` `u8`…`u64` `f32` `f64`, wskaźniki `ptr[T]` / `ptr` |
|
| Typy | `int` `float` `bool` `char` `str`, z rozmiarem `i8`…`i64` `u8`…`u64` `f32` `f64`, tablice `[]T`, wskaźniki `ptr[T]` |
|
||||||
| Funkcje | `fn add(int a, int b) -> int { return a + b }` |
|
| Funkcje | `fn add(int a, int b) -> int { return a + b }` |
|
||||||
| Sterowanie | `if` / `else if` / `else`, `while`, `for i in 0..10`, `break`, `continue` |
|
| Struktury | `struct Punkt { … }` z jednym polem na linijkę (`int x`, `int y = 0`); tworzenie przez `Punkt(1, 2)` albo `Punkt(x: 1)` |
|
||||||
| Wskaźniki | `p := addr(x)`, `p.value = 5`, `null` |
|
| Tablice | `liczby := [1, 2, 3]`, `liczby.push(4)`, `liczby[0]`, `liczby.len`, `for n in liczby { }` |
|
||||||
| Konwersje | `int(3.9)`, `u8(x)`, `float(n)` (niejawne tylko wtedy, gdy nic nie ginie) |
|
| Tekst | `"a" + "b"`, `str(42)`, `int("42")`, `s.split(",")`, `s.upper()`, `s[0]` |
|
||||||
| Operatory | `+ - * / %`, `& \| ^ << >> ~`, `== != < <= > >=`, `&& \|\| !` |
|
| Sterowanie | `if` / `else if` / `else`, `while`, `for i in 0..10`, `break`, `continue`, `defer` |
|
||||||
| Współpraca z C | `import "stdio.h"`, `link "glfw"` |
|
| Pamięć | automatyczna dla tablic, tekstów i struktur; `new(...)` / `free(...)` dla własnych struktur na stercie |
|
||||||
| Wypisywanie | `print(a, b, c)` wypisuje wszystko, oddzielając spacjami |
|
| Moduły | `import ksztalty` → `ksztalty.pole(p)` |
|
||||||
|
| Współpraca z C | `import "stdio.h"`, `link "glfw"`, `link "moje.c"`, `addr(fn)` dla callbacków |
|
||||||
|
| Wejście/wyjście | `print(...)`, `input("? ")`, `read_file`, `write_file`, `shell` |
|
||||||
|
| Narzędzia | `finch run/build/ir`, `-g` dla gdb, `-O0` |
|
||||||
|
|
||||||
## Przykłady
|
## Przykłady
|
||||||
|
|
||||||
|
|
@ -85,32 +94,42 @@ Wybierz przewodnik dla siebie:
|
||||||
|---|---|
|
|---|---|
|
||||||
| [`examples/hello.fn`](examples/hello.fn) | najmniejszy program |
|
| [`examples/hello.fn`](examples/hello.fn) | najmniejszy program |
|
||||||
| [`examples/tour.fn`](examples/tour.fn) | zmienne, funkcje, warunki, pętle |
|
| [`examples/tour.fn`](examples/tour.fn) | zmienne, funkcje, warunki, pętle |
|
||||||
|
| [`examples/guess.fn`](examples/guess.fn) | gra w zgadywanie: wejście, pętle, `rand` z C |
|
||||||
|
| [`examples/todo.fn`](examples/todo.fn) | struktury, tablice, teksty i pliki |
|
||||||
|
| [`examples/structs.fn`](examples/structs.fn) | struktury, tablice struktur, lista wiązana z `new`/`free` |
|
||||||
| [`examples/types.fn`](examples/types.fn) | liczby z rozmiarem i wskaźniki |
|
| [`examples/types.fn`](examples/types.fn) | liczby z rozmiarem i wskaźniki |
|
||||||
| [`examples/c_import.fn`](examples/c_import.fn) | `printf`, `math.h`, `malloc`/`free`, `stderr` |
|
| [`examples/c_import.fn`](examples/c_import.fn) | `printf`, `math.h`, `malloc`/`free`, `stderr` |
|
||||||
| [`examples/window.fn`](examples/window.fn) | okno GLFW + OpenGL |
|
| [`examples/window.fn`](examples/window.fn) | okno GLFW + OpenGL |
|
||||||
|
| [`examples/raylib.fn`](examples/raylib.fn) | raylib ze strukturami C przez wartość |
|
||||||
| [`examples/llvm.fn`](examples/llvm.fn) | Finch budujący LLVM IR przez API LLVM-C |
|
| [`examples/llvm.fn`](examples/llvm.fn) | Finch budujący LLVM IR przez API LLVM-C |
|
||||||
|
| [`boot/`](boot/) | kompilator Fincha napisany w Finchu |
|
||||||
|
|
||||||
## Plan rozwoju
|
## Plan rozwoju
|
||||||
|
|
||||||
- [x] Lekser, parser, generowanie kodu LLVM, optymalizacja O2
|
- [x] Lekser, parser, generowanie kodu LLVM, optymalizacja O2
|
||||||
- [x] Typy, w tym liczby z rozmiarem, wskaźniki, konwersje; funkcje; `if`/`while`/`for`
|
- [x] Typy, w tym liczby z rozmiarem, wskaźniki, konwersje; funkcje; `if`/`while`/`for`
|
||||||
- [x] Czytelne błędy kompilacji; kontrole w czasie działania (dzielenie, null)
|
- [x] Czytelne błędy kompilacji; kontrole w czasie działania (dzielenie, null, zakres)
|
||||||
- [x] Operatory bitowe z rozsądnymi priorytetami
|
- [x] Operatory bitowe z rozsądnymi priorytetami
|
||||||
- [x] Nagłówki C przez libclang; `link` z pkg-config; porady przy błędach linkowania
|
- [x] Nagłówki C przez libclang; `link` z pkg-config; porady przy błędach linkowania
|
||||||
- [ ] `struct` (i struktury C przez wartość)
|
- [x] `struct`, także struktury C przez wartość (ABI System V) i callbacki
|
||||||
- [ ] Tablice/wycinki z `.len` i kontrolą zakresu
|
- [x] Tablice z `.len`, kontrolą zakresu i metodami; `for x in lista`
|
||||||
- [ ] Pamięć: automatyczne zwalnianie na końcu bloku, `defer`, ręczne `free` dla chętnych
|
- [x] Pamięć: zwalnianie na końcu bloku, `defer`, `new`/`free`
|
||||||
- [ ] Teksty: `+`, `len`, `str(x)`; `input()`
|
- [x] Teksty: `+`, `.len`, indeksowanie, metody, `str(x)`, `int(s)`; `input()`; pliki
|
||||||
- [ ] Moduły Fincha (`import math`)
|
- [x] Moduły Fincha (`import nazwa`)
|
||||||
- [ ] Informacje dla debuggera (DWARF)
|
- [x] Informacje dla debuggera (`-g`)
|
||||||
- [ ] Bootstrap: kompilator Fincha napisany w Finchu
|
- [x] Bootstrap: kompilator Fincha napisany w Finchu, który buduje sam siebie
|
||||||
|
- [ ] Metody w strukturach, mapy, `match`
|
||||||
|
- [ ] Błędy jako wartości zamiast zatrzymywania programu
|
||||||
|
- [ ] Więcej platform (ARM64, macOS)
|
||||||
|
|
||||||
## Struktura
|
## Struktura
|
||||||
|
|
||||||
```
|
```
|
||||||
src/ kompilator: lekser, parser, AST, codegen, import C, sterownik (C++17, ok. 2,4 tys. linii)
|
src/ kompilator: lekser, parser, AST, codegen, import C + ABI, sterownik (C++17, ok. 4,5 tys. linii)
|
||||||
|
runtime/ mały runtime w C dołączany do każdego programu
|
||||||
|
boot/ kompilator Fincha napisany w Finchu (ok. 3 tys. linii)
|
||||||
examples/ przykładowe programy
|
examples/ przykładowe programy
|
||||||
tests/ run/ (wzorcowe wyjście), fail/ (oczekiwane błędy), run.sh
|
tests/ run/ (wzorcowe wyjście), fail/ (oczekiwane błędy), run.sh, boot.sh
|
||||||
docs/ przewodniki en/ i pl/ dla trzech grup odbiorców
|
docs/ przewodniki en/ i pl/ dla trzech grup odbiorców
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -20,10 +20,15 @@ Take it slowly, one section at a time, and type every example yourself: that is
|
||||||
8. [Making decisions: if](#8-making-decisions-if)
|
8. [Making decisions: if](#8-making-decisions-if)
|
||||||
9. [Repeating things: loops](#9-repeating-things-loops)
|
9. [Repeating things: loops](#9-repeating-things-loops)
|
||||||
10. [Your own commands: functions](#10-your-own-commands-functions)
|
10. [Your own commands: functions](#10-your-own-commands-functions)
|
||||||
11. [When something goes wrong](#11-when-something-goes-wrong)
|
11. [Lists: many values in one box](#11-lists-many-values-in-one-box)
|
||||||
12. [Small projects to try](#12-small-projects-to-try)
|
12. [Playing with text](#12-playing-with-text)
|
||||||
13. [Cheat sheet](#13-cheat-sheet)
|
13. [Asking the user](#13-asking-the-user)
|
||||||
14. [Words you will hear](#14-words-you-will-hear)
|
14. [Your own kinds of values: structs](#14-your-own-kinds-of-values-structs)
|
||||||
|
15. [Saving to a file](#15-saving-to-a-file)
|
||||||
|
16. [When something goes wrong](#16-when-something-goes-wrong)
|
||||||
|
17. [Small projects to try](#17-small-projects-to-try)
|
||||||
|
18. [Cheat sheet](#18-cheat-sheet)
|
||||||
|
19. [Words you will hear](#19-words-you-will-hear)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -72,7 +77,7 @@ To check it works, type:
|
||||||
./build/finch version
|
./build/finch version
|
||||||
```
|
```
|
||||||
|
|
||||||
You should see something like `finch 1.0.0`.
|
You should see something like `finch 2.0.0`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -441,7 +446,200 @@ It does not matter where in the file you put your functions, above or below `mai
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11. When something goes wrong
|
## 11. Lists: many values in one box
|
||||||
|
|
||||||
|
Sometimes one box is not enough. A shopping list has many things on it.
|
||||||
|
A **list** (programmers also say **array**) keeps many values in order:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
fruits := ["apple", "banana", "cherry"]
|
||||||
|
print(fruits)
|
||||||
|
print("I have", fruits.len, "fruits")
|
||||||
|
print("The first one is", fruits[0])
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
["apple", "banana", "cherry"]
|
||||||
|
I have 3 fruits
|
||||||
|
The first one is apple
|
||||||
|
```
|
||||||
|
|
||||||
|
- Square brackets `[ ]` make a list. Commas separate the values.
|
||||||
|
- `.len` tells you how many things are in the list.
|
||||||
|
- `fruits[0]` is the **first** thing. Counting starts at **0**, so `fruits[1]` is the second, and `fruits[2]` the third.
|
||||||
|
|
||||||
|
If you ask for a place that doesn't exist, like `fruits[10]`, the program stops and tells you:
|
||||||
|
`index 10 is out of range (the length is 3)`.
|
||||||
|
|
||||||
|
### Adding and taking away
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
[]int scores // an empty list of whole numbers
|
||||||
|
scores.push(10) // put 10 at the end
|
||||||
|
scores.push(25)
|
||||||
|
scores.push(7)
|
||||||
|
print(scores) // [10, 25, 7]
|
||||||
|
|
||||||
|
last := scores.pop() // take the last one out
|
||||||
|
print(last, scores) // 7 [10, 25]
|
||||||
|
|
||||||
|
scores.sort()
|
||||||
|
print(scores)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Going through a list
|
||||||
|
|
||||||
|
`for ... in` visits every value, one by one:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
total := 0
|
||||||
|
for n in [3, 5, 2] {
|
||||||
|
total += n
|
||||||
|
}
|
||||||
|
print("Total:", total) // Total: 10
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Lists can do more: `contains`, `find`, `insert`, `remove`, `sort`, `reverse`, `join`.
|
||||||
|
The [guide for technicians](for-technicians.md#arrays) lists them all.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Playing with text
|
||||||
|
|
||||||
|
Text can be glued together with `+`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
name := "Ola"
|
||||||
|
greeting := "Hello, " + name + "!"
|
||||||
|
print(greeting)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
To glue a number to text, turn the number into text first with `str(...)`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
age := 10
|
||||||
|
print("Age: " + str(age))
|
||||||
|
```
|
||||||
|
|
||||||
|
Text has handy tools too:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
word := "Finch"
|
||||||
|
print(word.len) // 5 letters
|
||||||
|
print(word[0]) // F (the first letter)
|
||||||
|
print(word.upper()) // FINCH
|
||||||
|
print(word.lower()) // finch
|
||||||
|
print(word.contains("in")) // true
|
||||||
|
for letter in word {
|
||||||
|
print(letter) // F, i, n, c, h, one per line
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Asking the user
|
||||||
|
|
||||||
|
`input` shows a question and waits until the person types an answer and presses Enter:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
name := input("What's your name? ")
|
||||||
|
print("Nice to meet you,", name)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
The answer is always **text**. If you need a number, turn it into one with `int(...)`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
answer := input("How old are you? ")
|
||||||
|
age := int(answer)
|
||||||
|
print("Next year you will be", age + 1)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
If the person types something that isn't a number, the program stops with a message
|
||||||
|
like `can't turn "abc" into int`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Your own kinds of values: structs
|
||||||
|
|
||||||
|
Imagine a card in a library: each card has a title, an author and a year.
|
||||||
|
A **struct** lets you make your own kind of value with named parts:
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct Book {
|
||||||
|
str title
|
||||||
|
str author
|
||||||
|
int year
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
b := Book(title: "The Hobbit", author: "Tolkien", year: 1937)
|
||||||
|
print(b.title, "by", b.author)
|
||||||
|
b.year = 1938
|
||||||
|
print(b)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
The Hobbit by Tolkien
|
||||||
|
Book(title: "The Hobbit", author: "Tolkien", year: 1938)
|
||||||
|
```
|
||||||
|
|
||||||
|
- `struct Book { ... }` describes what every book has. Put it **outside** `main`.
|
||||||
|
- `Book(title: ..., author: ..., year: ...)` makes one book.
|
||||||
|
- `b.title` reads one part. `b.year = 1938` changes it.
|
||||||
|
|
||||||
|
You can give parts a starting value. Then you don't have to fill them in:
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct Player {
|
||||||
|
str name
|
||||||
|
int lives = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
p := Player(name: "Ola")
|
||||||
|
print(p.lives) // 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
And you can keep many of them in a list: `[]Book shelf`, then `shelf.push(b)`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. Saving to a file
|
||||||
|
|
||||||
|
Programs forget everything when they end. To remember things, save them to a file:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
write_file("note.txt", "Buy milk")
|
||||||
|
print(read_file("note.txt"))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `write_file(name, text)` saves the text in a file (and replaces what was there).
|
||||||
|
- `read_file(name)` gives you the file's text back.
|
||||||
|
- `file_exists(name)` tells you if the file is there (`true` or `false`).
|
||||||
|
|
||||||
|
The file appears in the folder where you ran the program.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. When something goes wrong
|
||||||
|
|
||||||
Everyone makes mistakes when programming, even experts, every day.
|
Everyone makes mistakes when programming, even experts, every day.
|
||||||
Finch tries hard to explain what went wrong in plain words. Example:
|
Finch tries hard to explain what went wrong in plain words. Example:
|
||||||
|
|
@ -479,10 +677,13 @@ Here we simply misspelled `age`.
|
||||||
| `this '{' is never closed` | A `}` is missing | Add the `}` |
|
| `this '{' is never closed` | A `}` is missing | Add the `}` |
|
||||||
| `a condition must be bool` | `if` needs a yes/no question | Compare something: `if x > 0` |
|
| `a condition must be bool` | `if` needs a yes/no question | Compare something: `if x > 0` |
|
||||||
| `runtime error: division by zero` | You divided by 0 while the program ran | Check the number before dividing |
|
| `runtime error: division by zero` | You divided by 0 while the program ran | Check the number before dividing |
|
||||||
|
| `index 5 is out of range (the length is 3)` | You asked a list for a place it doesn't have | Remember counting starts at 0; check `.len` |
|
||||||
|
| `can't turn "abc" into int` | `int(...)` got text that isn't a number | Check what the person typed |
|
||||||
|
| `can't use '+' on str and int` | Text plus a number | Use `str(...)` on the number |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12. Small projects to try
|
## 17. Small projects to try
|
||||||
|
|
||||||
Try writing each one yourself first. Look at the solution only if you get stuck.
|
Try writing each one yourself first. Look at the solution only if you get stuck.
|
||||||
|
|
||||||
|
|
@ -589,9 +790,60 @@ fn main() {
|
||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### Project 6: Guess the number
|
||||||
|
|
||||||
|
The computer picks a secret number. The player guesses until they find it,
|
||||||
|
and the computer says "higher" or "lower" each time.
|
||||||
|
|
||||||
|
<details><summary>Solution</summary>
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
secret := 42
|
||||||
|
tries := 0
|
||||||
|
while true {
|
||||||
|
guess := int(input("Your guess: "))
|
||||||
|
tries += 1
|
||||||
|
if guess < secret {
|
||||||
|
print("Higher!")
|
||||||
|
} else if guess > secret {
|
||||||
|
print("Lower!")
|
||||||
|
} else {
|
||||||
|
print("Yes! You needed", tries, "tries")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`return` inside `main` ends the program. (A version with a random number is in `examples/guess.fn`.)
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Project 7: Class average
|
||||||
|
|
||||||
|
Ask for 3 grades, keep them in a list, and show the list and the average.
|
||||||
|
|
||||||
|
<details><summary>Solution</summary>
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
[]int grades
|
||||||
|
for i in 0..3 {
|
||||||
|
grades.push(int(input("Grade: ")))
|
||||||
|
}
|
||||||
|
sum := 0
|
||||||
|
for g in grades {
|
||||||
|
sum += g
|
||||||
|
}
|
||||||
|
print("Grades:", grades)
|
||||||
|
print("Average:", float(sum) / grades.len)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13. Cheat sheet
|
## 18. Cheat sheet
|
||||||
|
|
||||||
```c
|
```c
|
||||||
// a comment
|
// a comment
|
||||||
|
|
@ -624,11 +876,21 @@ fn main() { // the program starts here
|
||||||
fn add(int a, int b) -> int { // your own command
|
fn add(int a, int b) -> int { // your own command
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Pet { // your own kind of value
|
||||||
|
str name
|
||||||
|
int age = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// lists: nums := [1, 2, 3] nums.push(4) nums[0] nums.len for n in nums { }
|
||||||
|
// text: "a" + "b" str(42) int("42") s.len s.upper() s.contains("x")
|
||||||
|
// ask: name := input("Name? ")
|
||||||
|
// files: write_file("f.txt", text) read_file("f.txt")
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14. Words you will hear
|
## 19. Words you will hear
|
||||||
|
|
||||||
| Word | Meaning |
|
| Word | Meaning |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
|
@ -641,6 +903,10 @@ fn add(int a, int b) -> int { // your own command
|
||||||
| **function** | A named group of steps you can use again |
|
| **function** | A named group of steps you can use again |
|
||||||
| **loop** | Steps that repeat |
|
| **loop** | Steps that repeat |
|
||||||
| **condition** | A yes/no question, like `x > 5` |
|
| **condition** | A yes/no question, like `x > 5` |
|
||||||
|
| **list / array** | Many values kept in order, like `[1, 2, 3]` |
|
||||||
|
| **index** | The position of a value in a list, starting at 0 |
|
||||||
|
| **struct** | Your own kind of value, made of named parts |
|
||||||
|
| **input** | What the person types into the program |
|
||||||
| **error** | A message saying something is wrong, and where |
|
| **error** | A message saying something is wrong, and where |
|
||||||
| **bug** | A mistake in a program |
|
| **bug** | A mistake in a program |
|
||||||
|
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -1,9 +1,9 @@
|
||||||
# Finch for Technicians
|
# Finch for Technicians
|
||||||
|
|
||||||
**For people who know their way around a computer, but little or no programming.**
|
**For people who know their way around a computer, but little or no programming.**
|
||||||
This guide covers installing Finch, using the `finch` tool, the whole language, using
|
This guide covers installing Finch, using the `finch` tool, the whole language, memory,
|
||||||
C libraries, and fixing common problems. It does not cover how the compiler works inside.
|
modules, C libraries, debugging and fixing common problems. It does not cover how the
|
||||||
For that, see the [guide for engineers](for-engineers.md).
|
compiler works inside. For that, see the [guide for engineers](for-engineers.md).
|
||||||
|
|
||||||
> 🇵🇱 Polska wersja: [dla-technikow.md](../pl/dla-technikow.md)
|
> 🇵🇱 Polska wersja: [dla-technikow.md](../pl/dla-technikow.md)
|
||||||
|
|
||||||
|
|
@ -20,12 +20,19 @@ For that, see the [guide for engineers](for-engineers.md).
|
||||||
7. [Operators](#7-operators)
|
7. [Operators](#7-operators)
|
||||||
8. [Control flow](#8-control-flow)
|
8. [Control flow](#8-control-flow)
|
||||||
9. [Functions](#9-functions)
|
9. [Functions](#9-functions)
|
||||||
10. [Pointers](#10-pointers)
|
10. [Arrays](#10-arrays)
|
||||||
11. [Using C libraries](#11-using-c-libraries)
|
11. [Text (str)](#11-text-str)
|
||||||
12. [Errors](#12-errors)
|
12. [Structs](#12-structs)
|
||||||
13. [Troubleshooting](#13-troubleshooting)
|
13. [Memory: who frees what](#13-memory-who-frees-what)
|
||||||
14. [Project layout and tests](#14-project-layout-and-tests)
|
14. [Pointers](#14-pointers)
|
||||||
15. [Current limits](#15-current-limits)
|
15. [Built-in functions](#15-built-in-functions)
|
||||||
|
16. [Modules](#16-modules)
|
||||||
|
17. [Using C libraries](#17-using-c-libraries)
|
||||||
|
18. [Errors](#18-errors)
|
||||||
|
19. [Debugging](#19-debugging)
|
||||||
|
20. [Troubleshooting](#20-troubleshooting)
|
||||||
|
21. [Project layout and tests](#21-project-layout-and-tests)
|
||||||
|
22. [Current limits](#22-current-limits)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -37,9 +44,13 @@ file into a real program (a native executable, like the ones made from C), using
|
||||||
|
|
||||||
What that gives you:
|
What that gives you:
|
||||||
|
|
||||||
- **Speed close to C.** There is no interpreter, virtual machine or garbage collector.
|
- **Speed close to C.** No interpreter, virtual machine or garbage collector. Array bounds
|
||||||
|
checks and other safety checks cost almost nothing after optimization.
|
||||||
- **Small, standalone programs** that you can copy and run.
|
- **Small, standalone programs** that you can copy and run.
|
||||||
- **Direct access to C libraries.** `import "stdio.h"` and call anything in it.
|
- **Memory handled for you.** Lists and text are freed automatically at the end of the block
|
||||||
|
that owns them, with no garbage collector involved.
|
||||||
|
- **Direct access to C libraries.** `import "stdio.h"` and call anything in it, even functions
|
||||||
|
that take structs.
|
||||||
|
|
||||||
The design rules: one way to do each thing, C-like syntax without C's traps, and error
|
The design rules: one way to do each thing, C-like syntax without C's traps, and error
|
||||||
messages that tell you how to fix the problem.
|
messages that tell you how to fix the problem.
|
||||||
|
|
@ -56,10 +67,10 @@ Other LLVM versions will likely fail to compile, because LLVM's C++ API changes
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/Nexoniarz/Finch.git
|
git clone https://github.com/Nexoniarz/Finch.git
|
||||||
cd Finch
|
cd Finch
|
||||||
nix-shell # downloads LLVM, libclang, cmake, ninja, pkg-config
|
nix-shell # downloads LLVM, libclang, clang, cmake, ninja, pkg-config
|
||||||
cmake -S . -B build -G Ninja
|
cmake -S . -B build -G Ninja
|
||||||
ninja -C build
|
ninja -C build
|
||||||
./build/finch version # finch 1.0.0 (LLVM 21.x)
|
./build/finch version # finch 2.0.0 (LLVM 21.x)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Option B: your distribution's packages
|
### Option B: your distribution's packages
|
||||||
|
|
@ -73,7 +84,7 @@ libclang 21 development files, and optionally `pkg-config`.
|
||||||
| Fedora | `gcc-c++ cmake ninja-build pkgconf llvm-devel clang-devel` |
|
| Fedora | `gcc-c++ cmake ninja-build pkgconf llvm-devel clang-devel` |
|
||||||
| Arch | `base-devel cmake ninja pkgconf llvm clang` |
|
| Arch | `base-devel cmake ninja pkgconf llvm clang` |
|
||||||
|
|
||||||
If CMake cannot find LLVM, point it there:
|
These have not been tested; if CMake cannot find LLVM, point it there:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cmake -S . -B build -G Ninja -DLLVM_DIR=/usr/lib/llvm-21/lib/cmake/llvm
|
cmake -S . -B build -G Ninja -DLLVM_DIR=/usr/lib/llvm-21/lib/cmake/llvm
|
||||||
|
|
@ -87,21 +98,22 @@ sudo cp build/finch /usr/local/bin/
|
||||||
finch version
|
finch version
|
||||||
```
|
```
|
||||||
|
|
||||||
Finch needs a working C compiler (`cc`) at run time. It uses it as the **linker** that
|
At run time Finch needs a C compiler (`cc`). It is used to link programs, and once to build
|
||||||
turns compiled code into a program. Set the `CC` environment variable to use a different one.
|
Finch's small runtime library, which is kept in `~/.cache/finch`. Set `CC` to use a different one.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. The finch command
|
## 3. The finch command
|
||||||
|
|
||||||
```
|
```
|
||||||
finch run <file.fn> compile and run right away
|
finch run <file.fn> [args...] compile and run right away
|
||||||
finch build <file.fn> [-o name] compile into a program (default name: the file's name)
|
finch build <file.fn> [-o name] compile into a program (default name: the file's name)
|
||||||
finch ir <file.fn> print the LLVM IR (for the curious)
|
finch ir <file.fn> print the LLVM IR (for the curious)
|
||||||
finch version show the version
|
finch version show the version
|
||||||
|
|
||||||
options:
|
options:
|
||||||
-l <lib> link a C library, same as link "lib" in the file
|
-l <lib> link a C library, same as link "lib" in the file
|
||||||
|
-g add debug info (for gdb / lldb)
|
||||||
-O0 skip optimizations
|
-O0 skip optimizations
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -109,13 +121,13 @@ Examples:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
finch run hello.fn # prints the output
|
finch run hello.fn # prints the output
|
||||||
|
finch run tool.fn input.txt -v # arguments after the file go to the program
|
||||||
finch build game.fn -o mygame # creates ./mygame
|
finch build game.fn -o mygame # creates ./mygame
|
||||||
./mygame
|
finch build game.fn -g -O0 # a build for the debugger
|
||||||
finch run window.fn -l glfw # with a C library
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`finch run` passes on your program's exit code. If the program crashes, it tells you
|
`finch run` passes on your program's exit code. If the program crashes, it says how
|
||||||
how (for example `the program crashed: Segmentation fault`).
|
(for example `the program crashed: Segmentation fault`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -126,8 +138,14 @@ how (for example `the program crashed: Segmentation fault`).
|
||||||
/* or span
|
/* or span
|
||||||
several lines */
|
several lines */
|
||||||
|
|
||||||
import "math.h" // C headers (optional), always at the top
|
import "math.h" // C headers (optional), at the top
|
||||||
link "m" // C libraries to link (optional)
|
import shapes // Finch modules (optional): shapes.fn next to this file
|
||||||
|
link "m" // C libraries or C files to link (optional)
|
||||||
|
|
||||||
|
struct Point { // your own types
|
||||||
|
int x
|
||||||
|
int y
|
||||||
|
}
|
||||||
|
|
||||||
fn main() { // the program starts here
|
fn main() { // the program starts here
|
||||||
print("Hello")
|
print("Hello")
|
||||||
|
|
@ -136,13 +154,14 @@ fn main() { // the program starts here
|
||||||
|
|
||||||
Rules worth knowing:
|
Rules worth knowing:
|
||||||
|
|
||||||
- **One statement per line.** There are no semicolons. To split a long expression,
|
- **One statement per line.** There are no semicolons. To split a long expression, break the line
|
||||||
break the line **after** an operator (`a +⏎ b`) or anywhere inside brackets `( )`.
|
**after** an operator (`a +⏎ b`) or anywhere inside brackets `( )` or `[ ]`.
|
||||||
- **Curly braces are always required** after `if`, `else`, `for`, `while`, and the opening
|
- **Curly braces are always required** after `if`, `else`, `for`, `while`, and the opening `{`
|
||||||
`{` goes on the same line.
|
goes on the same line.
|
||||||
- **No brackets around conditions:** `if x > 5 {`, not `if (x > 5) {`.
|
- **No brackets around conditions:** `if x > 5 {`, not `if (x > 5) {`.
|
||||||
- Functions can be in any order in the file.
|
- Functions and structs can be in any order in the file.
|
||||||
- `main` is either `fn main()` or `fn main() -> int` (returns the exit code).
|
- `main` is `fn main()`, `fn main() -> int` (returns the exit code) or `fn main([]str args)`
|
||||||
|
(gets the command-line arguments; `args[0]` is the program's own path).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -151,7 +170,8 @@ Rules worth knowing:
|
||||||
```c
|
```c
|
||||||
x := 5 // new variable, type inferred (int)
|
x := 5 // new variable, type inferred (int)
|
||||||
int y = 10 // new variable, type written explicitly
|
int y = 10 // new variable, type written explicitly
|
||||||
int z // no value: starts at zero ("" for str, null for pointers)
|
int z // no value: starts at zero ("" for str, [] for arrays, null for pointers)
|
||||||
|
Point p // a struct with no value: zero, or the struct's default values
|
||||||
|
|
||||||
x = 7 // assign
|
x = 7 // assign
|
||||||
x += 1 // also -= *= /= %=
|
x += 1 // also -= *= /= %=
|
||||||
|
|
@ -160,10 +180,10 @@ x += 1 // also -= *= /= %=
|
||||||
- A name can be declared **once** in a function. Finch does not allow reusing a name in an
|
- A name can be declared **once** in a function. Finch does not allow reusing a name in an
|
||||||
inner block (no "shadowing"), because that is a common source of confusion.
|
inner block (no "shadowing"), because that is a common source of confusion.
|
||||||
- Variables exist from their declaration to the end of the `{ }` block they are in.
|
- Variables exist from their declaration to the end of the `{ }` block they are in.
|
||||||
- Names: ASCII letters, digits and `_`, not starting with a digit. Non-ASCII letters are allowed only inside strings. Type names (`int`, `u8`, …) and
|
- Names: ASCII letters, digits and `_`, not starting with a digit. Non-ASCII letters are allowed only inside strings.
|
||||||
keywords are reserved.
|
Type names (`int`, `u8`, …), built-in function names and keywords are reserved.
|
||||||
|
|
||||||
**Keywords:** `fn return if else while for in break continue true false null import link`
|
**Keywords:** `fn return if else while for in break continue true false null import link struct defer`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -177,7 +197,9 @@ x += 1 // also -= *= /= %=
|
||||||
| `float` | decimal number, 64-bit (same as `f64`) | `3.14` |
|
| `float` | decimal number, 64-bit (same as `f64`) | `3.14` |
|
||||||
| `bool` | `true` or `false` | |
|
| `bool` | `true` or `false` | |
|
||||||
| `char` | one byte-sized character | `'A'`, `'\n'` |
|
| `char` | one byte-sized character | `'A'`, `'\n'` |
|
||||||
| `str` | text (a C string) | `"hello\tworld"` |
|
| `str` | text | `"hello\tworld"` |
|
||||||
|
| `[]T` | a list (array) of `T` | `[1, 2, 3]` |
|
||||||
|
| your structs | named groups of values | `Point(1, 2)` |
|
||||||
|
|
||||||
String and char escapes: `\n` new line, `\t` tab, `\r`, `\0`, `\\`, `\"`, `\'`.
|
String and char escapes: `\n` new line, `\t` tab, `\r`, `\0`, `\\`, `\"`, `\'`.
|
||||||
|
|
||||||
|
|
@ -192,11 +214,6 @@ String and char escapes: `\n` new line, `\t` tab, `\r`, `\0`, `\\`, `\"`, `\'`.
|
||||||
|
|
||||||
`f32` is a 32-bit decimal number (about 7 significant digits), `f64` a 64-bit one (about 15–16).
|
`f32` is a 32-bit decimal number (about 7 significant digits), `f64` a 64-bit one (about 15–16).
|
||||||
|
|
||||||
### Pointers
|
|
||||||
|
|
||||||
`ptr[T]` points to a value of type `T`. Plain `ptr` points to "something" with unknown
|
|
||||||
type, like `void*` in C. See [Pointers](#10-pointers).
|
|
||||||
|
|
||||||
### Conversions
|
### Conversions
|
||||||
|
|
||||||
Finch converts automatically **only when nothing can be lost**:
|
Finch converts automatically **only when nothing can be lost**:
|
||||||
|
|
@ -208,32 +225,30 @@ Finch converts automatically **only when nothing can be lost**:
|
||||||
| any whole number | `float` / `f32` | ✅ |
|
| any whole number | `float` / `f32` | ✅ |
|
||||||
| `f32` | `f64` | ✅ |
|
| `f32` | `f64` | ✅ |
|
||||||
| `null` | any pointer | ✅ |
|
| `null` | any pointer | ✅ |
|
||||||
| any pointer, `str` | `ptr` | ✅ |
|
| any pointer | `ptr`, and `ptr` to any pointer | ✅ |
|
||||||
| `ptr` | any `ptr[T]` | ✅ |
|
|
||||||
| anything else | | ❌ write it: `type(value)` |
|
| anything else | | ❌ write it: `type(value)` |
|
||||||
|
|
||||||
**Number literals adapt.** A number written in the code fits into any type that can hold it:
|
**Number literals adapt.** A number written in the code fits into any type that can hold it:
|
||||||
`u8 b = 200` works, `u8 b = 300` is an error (`the number 300 doesn't fit in u8`).
|
`u8 b = 200` works, `u8 b = 300` is an error. The same applies to constants imported from C headers.
|
||||||
The same applies to constants imported from C headers.
|
|
||||||
|
|
||||||
**Explicit conversions** use the type name like a function:
|
**Explicit conversions** use the type name like a function:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int(3.99) // 3 (cuts off the fraction)
|
int(3.99) // 3 (cuts off the fraction)
|
||||||
int(-3.99) // -3
|
float(7) / 2 // 3.5
|
||||||
float(7) / 2 // 3.5
|
u8(300) // 44 (keeps the lowest 8 bits)
|
||||||
u8(300) // 44 (keeps the lowest 8 bits)
|
int('A') // 65
|
||||||
i8(200) // -56
|
char(66) // 'B'
|
||||||
int('A') // 65
|
bool(0) // false (any non-zero number is true)
|
||||||
char(66) // 'B'
|
str(42) // "42" (also floats, bools, chars; str([]u8) turns bytes into text)
|
||||||
bool(0) // false (any non-zero number is true)
|
int("42") // 42 (stops the program if the text isn't a number)
|
||||||
ptr(text) // a str as an untyped pointer
|
float("2.5") // 2.5
|
||||||
str(p) // a pointer as a str
|
ptr(p) // a typed pointer as an untyped one
|
||||||
|
str(p) // a C char pointer as text
|
||||||
```
|
```
|
||||||
|
|
||||||
**Fixed-size numbers wrap around**, like real hardware: a `u8` holding 255 plus 1 becomes 0.
|
**Fixed-size numbers wrap around**, like real hardware: a `u8` holding 255 plus 1 becomes 0.
|
||||||
Calculations happen in the type of the values involved, so `u8(250) + 10` is `4`, not `260`.
|
Calculations happen in the type of the values involved, so `u8(250) + 10` is `4`, not `260`.
|
||||||
Convert first if you need more room: `int(x) + 10`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -244,7 +259,7 @@ Convert first if you need more room: `int(x) + 10`.
|
||||||
| Priority | Operators | Meaning |
|
| Priority | Operators | Meaning |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 5 | `*` `/` `%` `<<` `>>` `&` | multiply, divide, remainder, shift left/right, bitwise AND |
|
| 5 | `*` `/` `%` `<<` `>>` `&` | multiply, divide, remainder, shift left/right, bitwise AND |
|
||||||
| 4 | `+` `-` `\|` `^` | add, subtract, bitwise OR, bitwise XOR |
|
| 4 | `+` `-` `\|` `^` | add (and join text), subtract, bitwise OR, bitwise XOR |
|
||||||
| 3 | `==` `!=` `<` `<=` `>` `>=` | comparisons |
|
| 3 | `==` `!=` `<` `<=` `>` `>=` | comparisons |
|
||||||
| 2 | `&&` | logical AND |
|
| 2 | `&&` | logical AND |
|
||||||
| 1 | `\|\|` | logical OR |
|
| 1 | `\|\|` | logical OR |
|
||||||
|
|
@ -252,18 +267,16 @@ Convert first if you need more room: `int(x) + 10`.
|
||||||
Unary (in front of a value): `-x` negate, `!x` logical NOT, `~x` flip all bits.
|
Unary (in front of a value): `-x` negate, `!x` logical NOT, `~x` flip all bits.
|
||||||
|
|
||||||
> **Different from C, on purpose:** bit operators bind tighter than comparisons, so
|
> **Different from C, on purpose:** bit operators bind tighter than comparisons, so
|
||||||
> `flags & 4 != 0` means `(flags & 4) != 0`. In C it silently means something else.
|
> `flags & 4 != 0` means `(flags & 4) != 0`.
|
||||||
|
|
||||||
Notes:
|
Notes:
|
||||||
|
|
||||||
- `/` on whole numbers rounds toward zero: `7 / 2` is `3`, `-7 / 2` is `-3`. `%` takes the sign of the left side.
|
- `/` on whole numbers rounds toward zero: `7 / 2` is `3`. `%` takes the sign of the left side.
|
||||||
- Dividing by zero **stops the program** with `runtime error: division by zero` and the line number.
|
- Dividing by zero **stops the program** with `runtime error: division by zero` and the line number.
|
||||||
If the zero is written in the code, it is a compile error instead.
|
|
||||||
- `&&` and `||` only evaluate the right side if needed.
|
- `&&` and `||` only evaluate the right side if needed.
|
||||||
- Text (`str`) can be compared with `==` and `!=` (it compares the contents). `<` and `>` do not work on text.
|
- Text: `+` joins, `==` `!=` compare contents, `<` `>` compare alphabetically (byte by byte).
|
||||||
- Pointers can be compared with `==` and `!=`, including against `null`.
|
- Pointers can be compared with `==` and `!=`, including against `null`. A `str` is never `null`.
|
||||||
- Bit operators need whole numbers. For `bool` use `&&` and `||`.
|
- Arrays and structs can't be compared with `==`; compare their parts.
|
||||||
- `>>` on signed numbers keeps the sign (`-16 >> 2` is `-4`). On unsigned numbers it fills with zeros.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -286,14 +299,32 @@ for i in 0..10 { // i = 0, 1, …, 9 (the end is not included)
|
||||||
if i == 3 { continue }
|
if i == 3 { continue }
|
||||||
if i == 8 { break }
|
if i == 8 { break }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name in names { // every element of an array (or every char of a str)
|
||||||
|
print(name)
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- A condition must be a `bool`. `if x {` with a number is an error; write `if x != 0 {`.
|
- A condition must be a `bool`. `if x {` with a number is an error; write `if x != 0 {`.
|
||||||
- In `for i in a..b`, both ends are whole numbers evaluated **once** before the loop starts.
|
- In `for i in a..b`, both ends are evaluated **once**. `i` is an `int` and cannot be changed in the loop.
|
||||||
`i` is an `int` and cannot be changed inside the loop.
|
- In `for x in list`, `x` cannot be changed either. To change elements, loop over the indexes:
|
||||||
|
`for i in 0..list.len { list[i] = ... }`. Adding to the list inside the loop is fine.
|
||||||
- `while true { ... }` loops until a `break` or `return`.
|
- `while true { ... }` loops until a `break` or `return`.
|
||||||
- Code after `return`, `break` or `continue` in the same block is an error, because it can never run.
|
- Code after `return`, `break` or `continue` in the same block is an error, because it can never run.
|
||||||
|
|
||||||
|
### defer
|
||||||
|
|
||||||
|
`defer` runs a statement when the current block ends, however it ends: normally, by `return`,
|
||||||
|
`break` or `continue`. Several defers run in reverse order. Handy for cleanup:
|
||||||
|
|
||||||
|
```c
|
||||||
|
f := fopen("data.txt", "r")
|
||||||
|
defer fclose(f)
|
||||||
|
// ... use f; it is closed when the block ends, on every path
|
||||||
|
```
|
||||||
|
|
||||||
|
A deferred statement can't contain `return`, `break` or `continue`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9. Functions
|
## 9. Functions
|
||||||
|
|
@ -309,32 +340,129 @@ fn no_result(str message) { // no "->": returns nothing
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- Parameters are copies. Changing a parameter does not change the caller's variable.
|
- Arguments behave like copies: changing a parameter never changes the caller's variable.
|
||||||
Use a pointer for that (see below).
|
(Finch only really copies when needed: a function that doesn't change an array gets it for free.)
|
||||||
|
To change the caller's variable, pass a pointer: see [Pointers](#14-pointers).
|
||||||
- A function with `-> type` must return a value on every path. Finch checks this.
|
- A function with `-> type` must return a value on every path. Finch checks this.
|
||||||
- A function cannot be defined inside another function.
|
- A function cannot be defined inside another function.
|
||||||
- Built-in names you cannot reuse: `print`, `addr`, and all type names.
|
|
||||||
|
|
||||||
### Built-in functions
|
|
||||||
|
|
||||||
| Function | What it does |
|
|
||||||
|---|---|
|
|
||||||
| `print(a, b, ...)` | Prints all values separated by spaces, then a new line. Works with every type. |
|
|
||||||
| `addr(x)` | Gives a pointer to variable `x`. |
|
|
||||||
| `int(x)`, `u8(x)`, `float(x)`, … | Converts types (see [Conversions](#conversions)). |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10. Pointers
|
## 10. Arrays
|
||||||
|
|
||||||
A pointer holds the **address** of a value: where it lives in memory. Finch uses words
|
```c
|
||||||
instead of C's `*` and `&`:
|
nums := [5, 3, 8] // an array of int
|
||||||
|
[]str names // an empty array of str
|
||||||
|
grid := [[1, 2], [3, 4]] // arrays of arrays
|
||||||
|
[]f32 xs = [1, 2.5] // the type decides what the numbers become
|
||||||
|
```
|
||||||
|
|
||||||
|
| Operation | Meaning |
|
||||||
|
|---|---|
|
||||||
|
| `a.len` | number of elements |
|
||||||
|
| `a[i]` | element `i` (from 0); out of range stops the program with a clear message |
|
||||||
|
| `a[i] = x` | change an element |
|
||||||
|
| `a.push(x)` | add at the end |
|
||||||
|
| `a.pop()` | remove the last one and give it back |
|
||||||
|
| `a.insert(i, x)` | put `x` at position `i`, moving the rest |
|
||||||
|
| `a.remove(i)` | remove position `i` and give it back |
|
||||||
|
| `a.clear()` | remove everything |
|
||||||
|
| `a.resize(n)` | make it `n` long (new elements are zero) |
|
||||||
|
| `a.contains(x)`, `a.find(x)` | is `x` there? its index, or -1 (numbers, chars, bools, str) |
|
||||||
|
| `a.sort()`, `a.reverse()` | in place (numbers, chars, str) |
|
||||||
|
| `a.slice(s, e)` | a new array with elements `s` … `e-1` |
|
||||||
|
| `a.join(sep)` | for `[]str`: one text with `sep` between the parts |
|
||||||
|
| `a.ptr` | the address of the first element (for C) |
|
||||||
|
| `print(a)` | prints `[1, 2, 3]` |
|
||||||
|
|
||||||
|
**Assigning copies:** after `b := a`, changing `b` does not change `a`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Text (str)
|
||||||
|
|
||||||
|
```c
|
||||||
|
s := "Hello"
|
||||||
|
s += ", world" // join
|
||||||
|
print(s.len, s[0]) // 12 H (.len counts bytes; ą, ż, … take 2)
|
||||||
|
s[0] = 'J' // change a character
|
||||||
|
```
|
||||||
|
|
||||||
|
| Method | Gives back |
|
||||||
|
|---|---|
|
||||||
|
| `s.sub(a, b)` | the part from `a` to `b-1` |
|
||||||
|
| `s.find(t)` | where `t` starts, or -1 |
|
||||||
|
| `s.contains(t)`, `s.starts_with(t)`, `s.ends_with(t)` | `bool` |
|
||||||
|
| `s.split(sep)` | `[]str`; `split("")` gives single characters |
|
||||||
|
| `s.trim()` | without spaces/newlines at both ends |
|
||||||
|
| `s.upper()`, `s.lower()` | A–Z / a–z changed (ASCII letters) |
|
||||||
|
| `s.replace(a, b)` | every `a` replaced by `b` |
|
||||||
|
| `s.repeat(n)` | `s` n times |
|
||||||
|
| `s.bytes()` | `[]u8` with the bytes |
|
||||||
|
| `s.ptr` | a `ptr[char]` for C (valid while `s` lives) |
|
||||||
|
|
||||||
|
`str` keeps its length, so `.len` is instant, and it is always NUL-terminated, so passing it
|
||||||
|
to C as `char*` works.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Structs
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct Player {
|
||||||
|
str name
|
||||||
|
int lives = 3 // a default value
|
||||||
|
[]int scores
|
||||||
|
Point pos // structs inside structs
|
||||||
|
}
|
||||||
|
|
||||||
|
p := Player(name: "Ola") // by name: missing fields get their default (or zero)
|
||||||
|
q := Point(1, 2) // in order: then every field must be given
|
||||||
|
p.lives -= 1
|
||||||
|
p.scores.push(10)
|
||||||
|
p.pos.x = 5
|
||||||
|
print(p) // Player(name: "Ola", lives: 2, scores: [10], pos: Point(x: 5, y: 0))
|
||||||
|
```
|
||||||
|
|
||||||
|
- Assigning or passing a struct copies it, together with its arrays and text.
|
||||||
|
- A struct can't contain itself directly; use `ptr[Node]` or `[]Node` for that field (trees, lists).
|
||||||
|
- Structs have no methods. Write functions that take the struct: `fn heal(Player p) -> Player`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Memory: who frees what
|
||||||
|
|
||||||
|
You never free arrays, text or structs. Finch does it for you, at a predictable moment:
|
||||||
|
**when the block that owns the value ends** (`}`), or earlier on `return`, `break`, `continue`.
|
||||||
|
|
||||||
|
- A variable **owns** its value. Assigning copies it, so two variables never share one list.
|
||||||
|
- A value produced by a function call or an expression is **moved** where it's stored: no copy.
|
||||||
|
- `return list` moves the variable out of the function: no copy.
|
||||||
|
- Function parameters are **lent**: the function gets the caller's value without a copy. If the
|
||||||
|
function changes the parameter, Finch makes it a private copy first. You never notice except in speed.
|
||||||
|
|
||||||
|
For memory you manage yourself (linked lists, trees, sharing between structures):
|
||||||
|
|
||||||
|
```c
|
||||||
|
node := new(Node(value: 1)) // put a value on the heap, get a ptr[Node]
|
||||||
|
defer free(node) // free(...) gives it back (and frees its arrays and text)
|
||||||
|
```
|
||||||
|
|
||||||
|
Memory from C (`malloc`, library objects) is freed with C's functions, as in C.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Pointers
|
||||||
|
|
||||||
|
A pointer holds the **address** of a value. Finch uses words instead of C's `*` and `&`:
|
||||||
|
|
||||||
| C | Finch | Meaning |
|
| C | Finch | Meaning |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `int *p` | `ptr[int] p` | p points to an int |
|
| `int *p` | `ptr[int] p` | p points to an int |
|
||||||
| `&x` | `addr(x)` | the address of x |
|
| `&x` | `addr(x)` | the address of x (also `addr(a[i])`, `addr(s.field)`) |
|
||||||
| `*p` | `p.value` | the value p points to |
|
| `*p` | `p.value` | the value p points to |
|
||||||
|
| `p->field` | `p.field` | a field of the struct p points to |
|
||||||
|
| `p[i]` | `p[i]` | C-style indexing (no bounds check) |
|
||||||
| `NULL` | `null` | points nowhere |
|
| `NULL` | `null` | points nowhere |
|
||||||
| `void *` | `ptr` | points to something of unknown type |
|
| `void *` | `ptr` | points to something of unknown type |
|
||||||
|
|
||||||
|
|
@ -343,38 +471,74 @@ fn double(ptr[int] p) {
|
||||||
p.value = p.value * 2
|
p.value = p.value * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
x := 21
|
||||||
x := 21
|
double(addr(x)) // x is 42
|
||||||
double(addr(x))
|
|
||||||
print(x) // 42
|
|
||||||
|
|
||||||
ptr[int] nothing = null
|
|
||||||
if nothing == null {
|
|
||||||
print("empty")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Pointers can point to pointers: `ptr[ptr[int]]`, then `pp.value.value`.
|
If a struct has its own field called `value`, then `p.value` on a pointer to it means that field.
|
||||||
|
|
||||||
Using `.value` on a `null` pointer **stops the program** with
|
Using `.value`, `.field` or `[i]` on a `null` pointer **stops the program** with a clear message.
|
||||||
`runtime error: used .value on a null pointer` instead of crashing randomly.
|
|
||||||
|
|
||||||
⚠️ A pointer to a variable must not be used after the function that owns the variable
|
⚠️ A pointer to a variable must not be used after the variable's block has ended. Finch does not check this.
|
||||||
has returned. The variable no longer exists then. Finch does not check this yet.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11. Using C libraries
|
## 15. Built-in functions
|
||||||
|
|
||||||
Almost every library on Linux has a C interface: graphics, sound, networking, databases.
|
| Function | What it does |
|
||||||
Finch can use them directly.
|
|---|---|
|
||||||
|
| `print(a, b, ...)` | Prints all values separated by spaces, then a new line. Works with every type, including arrays and structs. |
|
||||||
|
| `input()`, `input("question")` | Reads one line typed by the user (without the newline). Empty text at end of input. |
|
||||||
|
| `read_file(path)` | The whole file as `str`. Stops the program with a clear message if it can't be read. |
|
||||||
|
| `write_file(path, text)` | Writes (replaces) the file; gives back `true` if it worked. |
|
||||||
|
| `file_exists(path)` | `true` / `false` |
|
||||||
|
| `shell(command)` | Runs a shell command, gives back its exit code. |
|
||||||
|
| `exit(code)` | Ends the program right away. |
|
||||||
|
| `addr(x)` | A pointer to `x`; `addr(function)` gives C a function pointer (callback). |
|
||||||
|
| `new(value)`, `free(p)` | Manual heap memory (see [Memory](#13-memory-who-frees-what)). |
|
||||||
|
| `int(x)`, `str(x)`, `u8(x)`, … | Conversions (see [Conversions](#conversions)). |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. Modules
|
||||||
|
|
||||||
|
Split a program into files. `import shapes` loads `shapes.fn` from the same folder (or from a
|
||||||
|
folder listed in the `FINCH_PATH` environment variable, separated by `:`).
|
||||||
|
|
||||||
|
```c
|
||||||
|
// shapes.fn
|
||||||
|
struct Box {
|
||||||
|
float w
|
||||||
|
float h
|
||||||
|
}
|
||||||
|
|
||||||
|
fn area(Box b) -> float {
|
||||||
|
return b.w * b.h
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```c
|
||||||
|
// main.fn
|
||||||
|
import shapes
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
b := shapes.Box(2, 3)
|
||||||
|
print(shapes.area(b))
|
||||||
|
shapes.Box other // a module's type in a declaration
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Everything in a module is used with the module's name in front: `shapes.area`, `shapes.Box`.
|
||||||
|
- A module doesn't have `main`. Modules can import other modules.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 17. Using C libraries
|
||||||
|
|
||||||
### Step 1: import the header
|
### Step 1: import the header
|
||||||
|
|
||||||
```c
|
```c
|
||||||
import "stdio.h"
|
import "stdio.h"
|
||||||
import "math.h"
|
|
||||||
import "GLFW/glfw3.h" // a path inside the system include folders
|
import "GLFW/glfw3.h" // a path inside the system include folders
|
||||||
import "mylib.h" // a header next to your .fn file
|
import "mylib.h" // a header next to your .fn file
|
||||||
```
|
```
|
||||||
|
|
@ -382,33 +546,23 @@ import "mylib.h" // a header next to your .fn file
|
||||||
Finch reads the header with **libclang** (clang's C parser) and makes these usable:
|
Finch reads the header with **libclang** (clang's C parser) and makes these usable:
|
||||||
|
|
||||||
- **functions**, including ones with a variable number of arguments, like `printf`,
|
- **functions**, including ones with a variable number of arguments, like `printf`,
|
||||||
- **`enum` values**,
|
- **structs**, by value and by pointer (`Vector2`, `SDL_Rect`, `CXCursor`, …), with their fields,
|
||||||
- **simple `#define` constants** that are a single number, like `M_PI`, `EOF`, `GL_COLOR_BUFFER_BIT`,
|
- **`enum` values** and **simple `#define` constants** (`M_PI`, `GL_COLOR_BUFFER_BIT`),
|
||||||
- **global variables**, like `stdout` and `stderr`.
|
- **global variables**, like `stdout` and `stderr`.
|
||||||
|
|
||||||
### Step 2: link the library
|
### Step 2: link the library
|
||||||
|
|
||||||
A header only *describes* functions. Their actual code is in a library file (`libNAME.so`).
|
|
||||||
Tell Finch which library to use, at the top of the file:
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
link "glfw" // uses libglfw.so
|
link "glfw" // uses libglfw.so (pkg-config is asked first, if installed)
|
||||||
link "GL" // uses libGL.so
|
link "helpers.c" // compile and link your own C file (next to the .fn file)
|
||||||
|
link "prebuilt.a" // or an object file / static library
|
||||||
```
|
```
|
||||||
|
|
||||||
Write just the name: for `libglfw.so` that is `glfw`. If `pkg-config` knows the name, Finch uses
|
|
||||||
its settings (paths and extra libraries). Otherwise it passes `-lNAME` to the linker.
|
|
||||||
The C standard library and the math library (`libm`) are always linked.
|
|
||||||
|
|
||||||
On the command line, `-l NAME` does the same as `link "NAME"`.
|
|
||||||
|
|
||||||
If you forget the `link` line, Finch tells you exactly what is missing:
|
If you forget the `link` line, Finch tells you exactly what is missing:
|
||||||
|
|
||||||
```
|
```
|
||||||
error: glfwInit, glfwCreateWindow, glfwMakeContextCurrent and 5 more come from "GLFW/glfw3.h", but its library isn't linked
|
error: glfwInit, glfwCreateWindow, glfwMakeContextCurrent and 5 more come from "GLFW/glfw3.h", but its library isn't linked
|
||||||
the header only says the functions exist; their code lives in a library.
|
...
|
||||||
add this at the top of your file (with the library's real name):
|
|
||||||
|
|
||||||
link "glfw"
|
link "glfw"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -422,52 +576,46 @@ error: glfwInit, glfwCreateWindow, glfwMakeContextCurrent and 5 more come from "
|
||||||
| `float`, `double` | `f32`, `f64` |
|
| `float`, `double` | `f32`, `f64` |
|
||||||
| `_Bool` / `bool` | `bool` |
|
| `_Bool` / `bool` | `bool` |
|
||||||
| `enum` | the matching signed integer |
|
| `enum` | the matching signed integer |
|
||||||
| `char *`, `const char *` | `str` |
|
| `char *` as a **parameter or result** | `str` |
|
||||||
| `int *`, `double *`, … | `ptr[i32]`, `ptr[f64]`, … |
|
| `char *` inside a struct or behind a pointer | `ptr[char]` (use `str(p)` to read it) |
|
||||||
| `void *`, `struct X *`, `FILE *`, function pointers | `ptr` |
|
| `struct X` by value | `X`, a struct with the same fields |
|
||||||
|
| `struct X *`, `int *`, … | `ptr[X]`, `ptr[i32]`, … |
|
||||||
|
| `int arr[16]` inside a struct | `[16]i32`: index it and use `.len` |
|
||||||
|
| `void *`, function pointers, incomplete structs | `ptr` |
|
||||||
|
|
||||||
So C's `int` is Finch's `i32`. Literals adapt automatically (`abs(-5)` works),
|
### Example: structs and callbacks
|
||||||
but a Finch `int` variable must be converted: `abs(i32(x))`.
|
|
||||||
|
|
||||||
### Example
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
import "stdio.h"
|
import "raylib.h"
|
||||||
import "math.h"
|
link "raylib"
|
||||||
import "stdlib.h"
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
printf("%d + %d = %d\n", 2, 3, 5)
|
InitWindow(800, 450, "Finch")
|
||||||
print(sqrt(2), M_PI, RAND_MAX)
|
while !WindowShouldClose() {
|
||||||
|
BeginDrawing()
|
||||||
ptr[i32] n = malloc(4) // ask C for 4 bytes of memory
|
ClearBackground(Color(r: 30, g: 30, b: 40, a: 255))
|
||||||
n.value = 7
|
DrawCircleV(Vector2(400, 225), 50, Color(255, 136, 0, 255))
|
||||||
print(n.value)
|
EndDrawing()
|
||||||
free(n) // and give them back
|
}
|
||||||
|
CloseWindow()
|
||||||
fprintf(stderr, "this goes to the error output\n")
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
A complete graphics example is in `examples/window.fn`: a GLFW + OpenGL window that changes color.
|
To give C a function to call back (like `qsort`'s comparator), use `addr(myFunction)`.
|
||||||
`examples/llvm.fn` shows that Finch can even drive LLVM itself through its C API.
|
Its parameters must be C types (numbers, pointers, C structs).
|
||||||
|
|
||||||
### What does not work yet
|
### What does not work yet
|
||||||
|
|
||||||
- C functions that take or return a **`struct` by value**, such as `div()`. Finch says so
|
- C **unions** by value, and structs with **bit fields** by value (pointers to them work).
|
||||||
clearly if you try. Functions taking a *pointer* to a struct are fine.
|
- **Function-like macros** and macros that are not a single number.
|
||||||
- **Function-like macros** (`#define MAX(a,b) ...`) and macros that are not a single number.
|
|
||||||
- `long double`, 128-bit integers.
|
- `long double`, 128-bit integers.
|
||||||
- Reading the **fields** of a C struct.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12. Errors
|
## 18. Errors
|
||||||
|
|
||||||
### Compile errors
|
### Compile errors
|
||||||
|
|
||||||
Finch stops at the first problem and shows where it is:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
game.fn:12:9: error: 'score' must be int, but this is str
|
game.fn:12:9: error: 'score' must be int, but this is str
|
||||||
12 | score = "high"
|
12 | score = "high"
|
||||||
|
|
@ -478,64 +626,87 @@ Format: `file:line:column: error: explanation`, then the line with a `^` under t
|
||||||
|
|
||||||
### Runtime errors
|
### Runtime errors
|
||||||
|
|
||||||
Some problems can only be seen while the program runs. Instead of undefined behavior
|
Instead of undefined behavior (as in C), Finch stops with a message and exit code 1:
|
||||||
(as in C), Finch stops with a clear message on the error output and exit code 1:
|
|
||||||
|
|
||||||
| Message | Cause |
|
| Message | Cause |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `runtime error: division by zero` | `/` or `%` by a variable that was 0 |
|
| `runtime error: division by zero` | `/` or `%` by a variable that was 0 |
|
||||||
| `runtime error: division overflows …` | the smallest signed number divided by −1 |
|
| `runtime error: division overflows …` | the smallest signed number divided by −1 |
|
||||||
| `runtime error: used .value on a null pointer` | reading or writing `p.value` while `p` is `null` |
|
| `runtime error: index 5 is out of range (the length is 3)` | `a[5]` on a shorter array or str |
|
||||||
|
| `runtime error: pop() on an empty array` | |
|
||||||
|
| `runtime error: used .value on a null pointer` | also `.field` and `[i]` through `null` |
|
||||||
|
| `runtime error: can't turn "x" into int` | `int(...)` / `float(...)` on text that isn't a number |
|
||||||
|
| `runtime error: can't read the file "…"` | `read_file` on a missing or unreadable file |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13. Troubleshooting
|
## 19. Debugging
|
||||||
|
|
||||||
|
```sh
|
||||||
|
finch build game.fn -g -O0 -o game
|
||||||
|
gdb ./game
|
||||||
|
(gdb) break game.fn:12
|
||||||
|
(gdb) run
|
||||||
|
(gdb) bt # where are we, through which functions
|
||||||
|
(gdb) info locals # all variables
|
||||||
|
(gdb) print player.lives
|
||||||
|
```
|
||||||
|
|
||||||
|
`-g` adds debug info (lines, functions, variables, struct fields). `-O0` keeps every variable
|
||||||
|
visible; without it the optimizer may remove some.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 20. Troubleshooting
|
||||||
|
|
||||||
| Problem | Solution |
|
| Problem | Solution |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `can't find the C header 'x.h'` | The library's development files are missing. Install them (on Debian: `libx-dev`; on Nix: add to `shell.nix`). For your own header, put it next to the `.fn` file. |
|
| `can't find the C header 'x.h'` | The library's development files are missing. Install them (Debian: `libx-dev`; Nix: add to `shell.nix`). |
|
||||||
| `… come from "x.h", but its library isn't linked` | Add `link "name"` at the top of the file. |
|
| `… come from "x.h", but its library isn't linked` | Add `link "name"` at the top of the file. |
|
||||||
| `the library 'x' wasn't found` | The library is not installed, or the name is wrong. On Nix, add it to `shell.nix` and run inside `nix-shell`. |
|
| `the library 'x' wasn't found` | Not installed, or a wrong name. On Nix, add it to `shell.nix` and run inside `nix-shell`. |
|
||||||
| `the C function 'f' can't be used from Finch yet` | It uses a struct by value, or another unsupported type. Look for a variant that takes pointers. |
|
| `the C function 'f' can't be used from Finch yet` | It uses a union, bit fields or another unsupported type by value. Look for a variant that takes pointers. |
|
||||||
| `no C compiler found to link with` | Install gcc or clang, or set `CC`. |
|
| `can't find the module 'x'` | Put `x.fn` next to the importing file, or set `FINCH_PATH`. |
|
||||||
| The program runs, but a C library is not found at start | It was linked from a path the system does not search. Run it inside the same `nix-shell`, or install the library system-wide. |
|
| `couldn't build the Finch runtime` | No working C compiler. Install gcc or clang, or set `CC`. |
|
||||||
| CMake: `libclang not found` | Install the libclang dev package, or run `cmake` inside `nix-shell`. |
|
| A library is not found when the program starts | It was linked from a folder the system doesn't search. Run inside the same `nix-shell`, or install it system-wide. |
|
||||||
| Build fails with LLVM API errors | You have a different LLVM version than 21. |
|
| `clang` inside `nix-shell` can't find `stdio.h` | You have an old `shell.nix`: `llvmPackages.clang` must be listed before `llvmPackages.libclang`. |
|
||||||
| A program never ends | A loop condition never becomes false. Press Ctrl+C. |
|
| A program never ends | A loop condition never becomes false. Press Ctrl+C. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14. Project layout and tests
|
## 21. Project layout and tests
|
||||||
|
|
||||||
```
|
```
|
||||||
Finch/
|
Finch/
|
||||||
├── src/ the compiler (C++)
|
├── src/ the compiler (C++)
|
||||||
├── examples/ example programs (hello, tour, types, c_import, window, llvm)
|
├── runtime/ finch_rt.c: the small runtime (text, arrays, input, files)
|
||||||
|
├── boot/ the Finch compiler written in Finch (see the engineers' guide)
|
||||||
|
├── examples/ hello, tour, types, structs, todo, guess, c_import, window, raylib, llvm
|
||||||
├── tests/
|
├── tests/
|
||||||
│ ├── run/ programs + the exact output they must print (.out)
|
│ ├── run/ programs + the exact output they must print (.out), input (.in)
|
||||||
│ ├── fail/ programs that must fail, with the expected error in line 1
|
│ ├── fail/ programs that must fail, with the expected error in line 1
|
||||||
│ └── run.sh the test runner
|
│ ├── run.sh the test runner (MEMCHECK=1 also checks memory with valgrind)
|
||||||
|
│ └── boot.sh builds the self-hosted compiler with itself and compares
|
||||||
├── docs/ this documentation (en, pl)
|
├── docs/ this documentation (en, pl)
|
||||||
├── shell.nix the Nix development environment
|
├── shell.nix the Nix development environment
|
||||||
└── CMakeLists.txt
|
└── CMakeLists.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
Run the tests after building:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
tests/run.sh # → 34 passed, 0 failed
|
tests/run.sh # → 58 passed, 0 failed
|
||||||
|
MEMCHECK=1 tests/run.sh # the same under valgrind: no leaks, no bad memory access
|
||||||
|
tests/boot.sh # the self-hosting check (needs clang)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 15. Current limits
|
## 22. Current limits
|
||||||
|
|
||||||
Finch 1.0 is a solid core, not a finished language. Not there yet:
|
Finch 2.0 is a complete small language, but not a finished one. Not there yet:
|
||||||
|
|
||||||
- `struct`, arrays, reading keyboard input (`input()`), string building (`"a" + "b"`).
|
- Methods on structs, generics, maps/dictionaries, `match`. (Use arrays of structs and functions.)
|
||||||
For now, use C functions for these (`scanf`, `snprintf`, `malloc`…).
|
- Error values: errors in `int("x")` or `read_file` stop the program. Check first (`file_exists`).
|
||||||
- Automatic memory management (planned: memory freed at the end of the block, plus `defer`).
|
- Unicode-aware text: `.len`, `s[i]` and `upper()` work on bytes / ASCII.
|
||||||
- Finch modules (one program = one `.fn` file for now).
|
- Threads.
|
||||||
- Platforms other than Linux x86-64.
|
- Platforms other than Linux x86-64.
|
||||||
|
|
||||||
See the [roadmap in the README](../../README.md#roadmap).
|
See the [roadmap in the README](../../README.md#roadmap).
|
||||||
|
|
|
||||||
File diff suppressed because it is too large
Load diff
|
|
@ -20,10 +20,15 @@ Czytaj powoli, po jednym rozdziale, i przepisuj każdy przykład samodzielnie. T
|
||||||
8. [Podejmowanie decyzji: if](#8-podejmowanie-decyzji-if)
|
8. [Podejmowanie decyzji: if](#8-podejmowanie-decyzji-if)
|
||||||
9. [Powtarzanie: pętle](#9-powtarzanie-pętle)
|
9. [Powtarzanie: pętle](#9-powtarzanie-pętle)
|
||||||
10. [Własne polecenia: funkcje](#10-własne-polecenia-funkcje)
|
10. [Własne polecenia: funkcje](#10-własne-polecenia-funkcje)
|
||||||
11. [Kiedy coś pójdzie nie tak](#11-kiedy-coś-pójdzie-nie-tak)
|
11. [Listy: wiele wartości w jednym pudełku](#11-listy-wiele-wartości-w-jednym-pudełku)
|
||||||
12. [Małe projekty do zrobienia](#12-małe-projekty-do-zrobienia)
|
12. [Zabawa tekstem](#12-zabawa-tekstem)
|
||||||
13. [Ściąga](#13-ściąga)
|
13. [Pytanie użytkownika](#13-pytanie-użytkownika)
|
||||||
14. [Słowniczek](#14-słowniczek)
|
14. [Własne rodzaje wartości: struktury](#14-własne-rodzaje-wartości-struktury)
|
||||||
|
15. [Zapisywanie do pliku](#15-zapisywanie-do-pliku)
|
||||||
|
16. [Kiedy coś pójdzie nie tak](#16-kiedy-coś-pójdzie-nie-tak)
|
||||||
|
17. [Małe projekty do zrobienia](#17-małe-projekty-do-zrobienia)
|
||||||
|
18. [Ściąga](#18-ściąga)
|
||||||
|
19. [Słowniczek](#19-słowniczek)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -72,7 +77,7 @@ Jeśli ostatnia linijka skończy się bez słowa `error`, Finch jest gotowy.
|
||||||
./build/finch version
|
./build/finch version
|
||||||
```
|
```
|
||||||
|
|
||||||
Powinieneś zobaczyć coś w stylu `finch 1.0.0`.
|
Powinieneś zobaczyć coś w stylu `finch 2.0.0`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -446,7 +451,202 @@ Nie ma znaczenia, gdzie w pliku umieścisz swoje funkcje, nad czy pod `main`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11. Kiedy coś pójdzie nie tak
|
## 11. Listy: wiele wartości w jednym pudełku
|
||||||
|
|
||||||
|
Czasem jedno pudełko nie wystarczy. Na liście zakupów jest wiele rzeczy.
|
||||||
|
**Lista** (programiści mówią też **tablica**) trzyma wiele wartości po kolei:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
owoce := ["jabłko", "banan", "wiśnia"]
|
||||||
|
print(owoce)
|
||||||
|
print("Mam", owoce.len, "owoce")
|
||||||
|
print("Pierwszy to", owoce[0])
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
["jabłko", "banan", "wiśnia"]
|
||||||
|
Mam 3 owoce
|
||||||
|
Pierwszy to jabłko
|
||||||
|
```
|
||||||
|
|
||||||
|
- Nawiasy kwadratowe `[ ]` tworzą listę. Wartości oddzielamy przecinkami.
|
||||||
|
- `.len` mówi, ile rzeczy jest na liście.
|
||||||
|
- `owoce[0]` to **pierwsza** rzecz. Liczymy od **0**, więc `owoce[1]` to druga, a `owoce[2]` trzecia.
|
||||||
|
|
||||||
|
Jeśli zapytasz o miejsce, którego nie ma, np. `owoce[10]`, program się zatrzyma i powie:
|
||||||
|
`index 10 is out of range (the length is 3)`, czyli „indeks 10 jest poza zakresem (długość to 3)”.
|
||||||
|
|
||||||
|
### Dodawanie i zabieranie
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
[]int wyniki // pusta lista liczb całkowitych
|
||||||
|
wyniki.push(10) // dołóż 10 na koniec
|
||||||
|
wyniki.push(25)
|
||||||
|
wyniki.push(7)
|
||||||
|
print(wyniki) // [10, 25, 7]
|
||||||
|
|
||||||
|
ostatni := wyniki.pop() // zabierz ostatni
|
||||||
|
print(ostatni, wyniki) // 7 [10, 25]
|
||||||
|
|
||||||
|
wyniki.sort() // posortuj
|
||||||
|
print(wyniki)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
### Przechodzenie po liście
|
||||||
|
|
||||||
|
`for ... in` odwiedza każdą wartość po kolei:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
suma := 0
|
||||||
|
for n in [3, 5, 2] {
|
||||||
|
suma += n
|
||||||
|
}
|
||||||
|
print("Suma:", suma) // Suma: 10
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Listy umieją więcej: `contains` (czy zawiera), `find` (znajdź), `insert` (wstaw), `remove` (usuń),
|
||||||
|
`sort` (sortuj), `reverse` (odwróć), `join` (połącz). Wszystkie opisuje [przewodnik dla techników](dla-technikow.md#tablice).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Zabawa tekstem
|
||||||
|
|
||||||
|
Teksty sklejasz znakiem `+`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
imie := "Ola"
|
||||||
|
powitanie := "Cześć, " + imie + "!"
|
||||||
|
print(powitanie)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Żeby dokleić liczbę do tekstu, najpierw zamień ją na tekst przez `str(...)`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
wiek := 10
|
||||||
|
print("Wiek: " + str(wiek))
|
||||||
|
```
|
||||||
|
|
||||||
|
Teksty mają też przydatne narzędzia:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
slowo := "Finch"
|
||||||
|
print(slowo.len) // 5 liter
|
||||||
|
print(slowo[0]) // F (pierwsza litera)
|
||||||
|
print(slowo.upper()) // FINCH (wielkimi literami)
|
||||||
|
print(slowo.lower()) // finch (małymi literami)
|
||||||
|
print(slowo.contains("in")) // true (czy zawiera "in")
|
||||||
|
for litera in slowo {
|
||||||
|
print(litera) // F, i, n, c, h, każda w osobnej linijce
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
⚠️ `.len` liczy bajty, a polskie litery (ą, ę, ż…) zajmują po 2 bajty. `"żółw".len` to 7, a nie 4.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Pytanie użytkownika
|
||||||
|
|
||||||
|
`input` pokazuje pytanie i czeka, aż ktoś wpisze odpowiedź i naciśnie Enter:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
imie := input("Jak masz na imię? ")
|
||||||
|
print("Miło cię poznać,", imie)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Odpowiedź jest zawsze **tekstem**. Jeśli potrzebujesz liczby, zamień ją przez `int(...)`:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
odpowiedz := input("Ile masz lat? ")
|
||||||
|
wiek := int(odpowiedz)
|
||||||
|
print("Za rok będziesz mieć", wiek + 1)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Jeśli ktoś wpisze coś, co nie jest liczbą, program zatrzyma się z komunikatem
|
||||||
|
w stylu `can't turn "abc" into int` („nie da się zamienić "abc" na int”).
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Własne rodzaje wartości: struktury
|
||||||
|
|
||||||
|
Wyobraź sobie kartę w bibliotece: każda karta ma tytuł, autora i rok.
|
||||||
|
**Struktura** (`struct`) pozwala zrobić własny rodzaj wartości z nazwanymi częściami:
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct Ksiazka {
|
||||||
|
str tytul
|
||||||
|
str autor
|
||||||
|
int rok
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
k := Ksiazka(tytul: "Hobbit", autor: "Tolkien", rok: 1937)
|
||||||
|
print(k.tytul, "napisał", k.autor)
|
||||||
|
k.rok = 1938
|
||||||
|
print(k)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```
|
||||||
|
Hobbit napisał Tolkien
|
||||||
|
Ksiazka(tytul: "Hobbit", autor: "Tolkien", rok: 1938)
|
||||||
|
```
|
||||||
|
|
||||||
|
- `struct Ksiazka { ... }` opisuje, co ma każda książka. Pisz to **poza** `main`.
|
||||||
|
- `Ksiazka(tytul: ..., autor: ..., rok: ...)` tworzy jedną książkę.
|
||||||
|
- `k.tytul` odczytuje jedną część, a `k.rok = 1938` ją zmienia.
|
||||||
|
|
||||||
|
Częściom możesz nadać wartość początkową. Wtedy nie trzeba ich podawać:
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct Gracz {
|
||||||
|
str imie
|
||||||
|
int zycia = 3
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
g := Gracz(imie: "Ola")
|
||||||
|
print(g.zycia) // 3
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
Możesz też trzymać wiele struktur na liście: `[]Ksiazka polka`, a potem `polka.push(k)`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 15. Zapisywanie do pliku
|
||||||
|
|
||||||
|
Program zapomina wszystko, kiedy się kończy. Żeby coś zapamiętać, zapisz to do pliku:
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
write_file("notatka.txt", "Kupić mleko")
|
||||||
|
print(read_file("notatka.txt"))
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- `write_file(nazwa, tekst)` zapisuje tekst w pliku (i zastępuje to, co tam było).
|
||||||
|
- `read_file(nazwa)` oddaje tekst z pliku.
|
||||||
|
- `file_exists(nazwa)` mówi, czy plik istnieje (`true` albo `false`).
|
||||||
|
|
||||||
|
Plik pojawi się w folderze, w którym uruchomiłeś program.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. Kiedy coś pójdzie nie tak
|
||||||
|
|
||||||
Każdy się myli przy programowaniu, nawet eksperci, codziennie.
|
Każdy się myli przy programowaniu, nawet eksperci, codziennie.
|
||||||
Finch stara się tłumaczyć, co poszło nie tak, prostymi słowami (na razie po angielsku). Przykład:
|
Finch stara się tłumaczyć, co poszło nie tak, prostymi słowami (na razie po angielsku). Przykład:
|
||||||
|
|
@ -485,10 +685,13 @@ Tutaj po prostu źle napisaliśmy `wiek`. Komunikat znaczy: „nie ma zmiennej o
|
||||||
| `a condition must be bool` | `if` potrzebuje pytania tak/nie | Porównaj coś: `if x > 0` |
|
| `a condition must be bool` | `if` potrzebuje pytania tak/nie | Porównaj coś: `if x > 0` |
|
||||||
| `unexpected character 'ż'` | Polska litera w nazwie | Zmień na zwykłą literę: `zolw` |
|
| `unexpected character 'ż'` | Polska litera w nazwie | Zmień na zwykłą literę: `zolw` |
|
||||||
| `runtime error: division by zero` | Program podzielił przez 0 w trakcie działania | Sprawdź liczbę przed dzieleniem |
|
| `runtime error: division by zero` | Program podzielił przez 0 w trakcie działania | Sprawdź liczbę przed dzieleniem |
|
||||||
|
| `index 5 is out of range (the length is 3)` | Zapytałeś listę o miejsce, którego nie ma | Pamiętaj, że liczymy od 0; sprawdź `.len` |
|
||||||
|
| `can't turn "abc" into int` | `int(...)` dostał tekst, który nie jest liczbą | Sprawdź, co wpisał użytkownik |
|
||||||
|
| `can't use '+' on str and int` | Tekst plus liczba | Zamień liczbę na tekst przez `str(...)` |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12. Małe projekty do zrobienia
|
## 17. Małe projekty do zrobienia
|
||||||
|
|
||||||
Spróbuj najpierw napisać każdy sam. Do rozwiązania zajrzyj dopiero, gdy utkniesz.
|
Spróbuj najpierw napisać każdy sam. Do rozwiązania zajrzyj dopiero, gdy utkniesz.
|
||||||
|
|
||||||
|
|
@ -595,9 +798,59 @@ fn main() {
|
||||||
```
|
```
|
||||||
</details>
|
</details>
|
||||||
|
|
||||||
|
### Projekt 6: Zgadnij liczbę
|
||||||
|
|
||||||
|
Komputer ma tajną liczbę. Gracz zgaduje, aż trafi, a komputer za każdym razem mówi „więcej” albo „mniej”.
|
||||||
|
|
||||||
|
<details><summary>Rozwiązanie</summary>
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
tajna := 42
|
||||||
|
proby := 0
|
||||||
|
while true {
|
||||||
|
strzal := int(input("Twój strzał: "))
|
||||||
|
proby += 1
|
||||||
|
if strzal < tajna {
|
||||||
|
print("Więcej!")
|
||||||
|
} else if strzal > tajna {
|
||||||
|
print("Mniej!")
|
||||||
|
} else {
|
||||||
|
print("Tak! Potrzebowałeś", proby, "prób")
|
||||||
|
return
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
`return` w `main` kończy program. (Wersja z losową liczbą jest w `examples/guess.fn`.)
|
||||||
|
</details>
|
||||||
|
|
||||||
|
### Projekt 7: Średnia ocen
|
||||||
|
|
||||||
|
Zapytaj o 3 oceny, zapisz je na liście, a potem pokaż listę i średnią.
|
||||||
|
|
||||||
|
<details><summary>Rozwiązanie</summary>
|
||||||
|
|
||||||
|
```c
|
||||||
|
fn main() {
|
||||||
|
[]int oceny
|
||||||
|
for i in 0..3 {
|
||||||
|
oceny.push(int(input("Ocena: ")))
|
||||||
|
}
|
||||||
|
suma := 0
|
||||||
|
for o in oceny {
|
||||||
|
suma += o
|
||||||
|
}
|
||||||
|
print("Oceny:", oceny)
|
||||||
|
print("Średnia:", float(suma) / oceny.len)
|
||||||
|
}
|
||||||
|
```
|
||||||
|
</details>
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13. Ściąga
|
## 18. Ściąga
|
||||||
|
|
||||||
```c
|
```c
|
||||||
// komentarz
|
// komentarz
|
||||||
|
|
@ -630,11 +883,21 @@ fn main() { // tu zaczyna się program
|
||||||
fn dodaj(int a, int b) -> int { // własne polecenie
|
fn dodaj(int a, int b) -> int { // własne polecenie
|
||||||
return a + b
|
return a + b
|
||||||
}
|
}
|
||||||
|
|
||||||
|
struct Zwierzak { // własny rodzaj wartości
|
||||||
|
str imie
|
||||||
|
int wiek = 1
|
||||||
|
}
|
||||||
|
|
||||||
|
// listy: liczby := [1, 2, 3] liczby.push(4) liczby[0] liczby.len for n in liczby { }
|
||||||
|
// tekst: "a" + "b" str(42) int("42") s.len s.upper() s.contains("x")
|
||||||
|
// pytanie: imie := input("Imię? ")
|
||||||
|
// pliki: write_file("p.txt", tekst) read_file("p.txt")
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14. Słowniczek
|
## 19. Słowniczek
|
||||||
|
|
||||||
| Słowo | Znaczenie |
|
| Słowo | Znaczenie |
|
||||||
|---|---|
|
|---|---|
|
||||||
|
|
@ -647,6 +910,10 @@ fn dodaj(int a, int b) -> int { // własne polecenie
|
||||||
| **funkcja** | Nazwana grupa kroków, której można używać wiele razy |
|
| **funkcja** | Nazwana grupa kroków, której można używać wiele razy |
|
||||||
| **pętla** | Kroki, które się powtarzają |
|
| **pętla** | Kroki, które się powtarzają |
|
||||||
| **warunek** | Pytanie tak/nie, np. `x > 5` |
|
| **warunek** | Pytanie tak/nie, np. `x > 5` |
|
||||||
|
| **lista / tablica** | Wiele wartości po kolei, np. `[1, 2, 3]` |
|
||||||
|
| **indeks** | Pozycja wartości na liście, liczona od 0 |
|
||||||
|
| **struktura** (struct) | Własny rodzaj wartości złożony z nazwanych części |
|
||||||
|
| **wejście** (input) | To, co użytkownik wpisuje do programu |
|
||||||
| **błąd** (error) | Komunikat, że coś jest nie tak, i gdzie |
|
| **błąd** (error) | Komunikat, że coś jest nie tak, i gdzie |
|
||||||
| **bug** | Pomyłka w programie |
|
| **bug** | Pomyłka w programie |
|
||||||
|
|
||||||
|
|
@ -662,6 +929,10 @@ fn dodaj(int a, int b) -> int { // własne polecenie
|
||||||
| `return` | zwróć (oddaj) |
|
| `return` | zwróć (oddaj) |
|
||||||
| `true` / `false` | prawda / fałsz |
|
| `true` / `false` | prawda / fałsz |
|
||||||
| `fn` (od *function*) | funkcja |
|
| `fn` (od *function*) | funkcja |
|
||||||
|
| `struct` | struktura |
|
||||||
|
| `push` / `pop` | dołóż / zabierz |
|
||||||
|
| `input` | wejście (pytanie) |
|
||||||
|
| `len` (od *length*) | długość |
|
||||||
| `error` | błąd |
|
| `error` | błąd |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
|
||||||
|
|
@ -1,9 +1,9 @@
|
||||||
# Finch dla techników
|
# Finch dla techników
|
||||||
|
|
||||||
**Dla osób, które dobrze znają komputery, ale programować nie umieją albo umieją niewiele.**
|
**Dla osób, które dobrze znają komputery, ale programować nie umieją albo umieją niewiele.**
|
||||||
Ten przewodnik opisuje instalację Fincha, obsługę polecenia `finch`, cały język,
|
Ten przewodnik opisuje instalację Fincha, obsługę polecenia `finch`, cały język, pamięć,
|
||||||
korzystanie z bibliotek C i rozwiązywanie typowych problemów. Nie opisuje, jak kompilator
|
moduły, biblioteki C, debugowanie i rozwiązywanie typowych problemów. Nie opisuje, jak
|
||||||
działa w środku. Do tego służy [przewodnik dla inżynierów](dla-inzynierow.md).
|
kompilator działa w środku. Do tego służy [przewodnik dla inżynierów](dla-inzynierow.md).
|
||||||
|
|
||||||
> 🇬🇧 English version: [for-technicians.md](../en/for-technicians.md)
|
> 🇬🇧 English version: [for-technicians.md](../en/for-technicians.md)
|
||||||
|
|
||||||
|
|
@ -20,26 +20,37 @@ działa w środku. Do tego służy [przewodnik dla inżynierów](dla-inzynierow.
|
||||||
7. [Operatory](#7-operatory)
|
7. [Operatory](#7-operatory)
|
||||||
8. [Sterowanie przebiegiem](#8-sterowanie-przebiegiem)
|
8. [Sterowanie przebiegiem](#8-sterowanie-przebiegiem)
|
||||||
9. [Funkcje](#9-funkcje)
|
9. [Funkcje](#9-funkcje)
|
||||||
10. [Wskaźniki](#10-wskaźniki)
|
10. [Tablice](#10-tablice)
|
||||||
11. [Biblioteki z C](#11-biblioteki-z-c)
|
11. [Tekst (str)](#11-tekst-str)
|
||||||
12. [Błędy](#12-błędy)
|
12. [Struktury](#12-struktury)
|
||||||
13. [Rozwiązywanie problemów](#13-rozwiązywanie-problemów)
|
13. [Pamięć: kto co zwalnia](#13-pamięć-kto-co-zwalnia)
|
||||||
14. [Struktura projektu i testy](#14-struktura-projektu-i-testy)
|
14. [Wskaźniki](#14-wskaźniki)
|
||||||
15. [Obecne ograniczenia](#15-obecne-ograniczenia)
|
15. [Funkcje wbudowane](#15-funkcje-wbudowane)
|
||||||
|
16. [Moduły](#16-moduły)
|
||||||
|
17. [Biblioteki z C](#17-biblioteki-z-c)
|
||||||
|
18. [Błędy](#18-błędy)
|
||||||
|
19. [Debugowanie](#19-debugowanie)
|
||||||
|
20. [Rozwiązywanie problemów](#20-rozwiązywanie-problemów)
|
||||||
|
21. [Struktura projektu i testy](#21-struktura-projektu-i-testy)
|
||||||
|
22. [Obecne ograniczenia](#22-obecne-ograniczenia)
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 1. Czym jest Finch
|
## 1. Czym jest Finch
|
||||||
|
|
||||||
Finch to język **kompilowany**. Narzędzie `finch` tłumaczy plik `.fn` na prawdziwy program
|
Finch to język **kompilowany**. Narzędzie `finch` tłumaczy plik `.fn` na prawdziwy program
|
||||||
(natywny plik wykonywalny, taki sam jak te z C). Korzysta przy tym z **LLVM**, tego samego
|
(natywny plik wykonywalny, taki jak te z C). Korzysta przy tym z **LLVM**, tego samego zaplecza
|
||||||
zaplecza kompilatorów, na którym działają clang, Rust i Swift.
|
kompilatorów, na którym działają clang, Rust i Swift.
|
||||||
|
|
||||||
Co to daje:
|
Co to daje:
|
||||||
|
|
||||||
- **Szybkość zbliżoną do C.** Nie ma interpretera, maszyny wirtualnej ani garbage collectora.
|
- **Szybkość zbliżoną do C.** Nie ma interpretera, maszyny wirtualnej ani garbage collectora.
|
||||||
|
Kontrola zakresu tablic i inne zabezpieczenia po optymalizacji prawie nic nie kosztują.
|
||||||
- **Małe, samodzielne programy**, które można skopiować i uruchomić.
|
- **Małe, samodzielne programy**, które można skopiować i uruchomić.
|
||||||
- **Bezpośredni dostęp do bibliotek C.** Piszesz `import "stdio.h"` i wołasz, co chcesz.
|
- **Pamięć obsługiwana za ciebie.** Listy i teksty są zwalniane automatycznie na końcu bloku,
|
||||||
|
do którego należą, bez garbage collectora.
|
||||||
|
- **Bezpośredni dostęp do bibliotek C.** Piszesz `import "stdio.h"` i wołasz, co chcesz,
|
||||||
|
nawet funkcje przyjmujące struktury.
|
||||||
|
|
||||||
Zasady projektu: jeden sposób na każdą rzecz, składnia podobna do C bez jej pułapek
|
Zasady projektu: jeden sposób na każdą rzecz, składnia podobna do C bez jej pułapek
|
||||||
i komunikaty błędów, które mówią, jak problem naprawić.
|
i komunikaty błędów, które mówią, jak problem naprawić.
|
||||||
|
|
@ -56,10 +67,10 @@ Z innymi wersjami LLVM prawdopodobnie się nie skompiluje, bo API C++ LLVM zmien
|
||||||
```sh
|
```sh
|
||||||
git clone https://github.com/Nexoniarz/Finch.git
|
git clone https://github.com/Nexoniarz/Finch.git
|
||||||
cd Finch
|
cd Finch
|
||||||
nix-shell # pobiera LLVM, libclang, cmake, ninja, pkg-config
|
nix-shell # pobiera LLVM, libclang, clang, cmake, ninja, pkg-config
|
||||||
cmake -S . -B build -G Ninja
|
cmake -S . -B build -G Ninja
|
||||||
ninja -C build
|
ninja -C build
|
||||||
./build/finch version # finch 1.0.0 (LLVM 21.x)
|
./build/finch version # finch 2.0.0 (LLVM 21.x)
|
||||||
```
|
```
|
||||||
|
|
||||||
### Opcja B: pakiety z twojej dystrybucji
|
### Opcja B: pakiety z twojej dystrybucji
|
||||||
|
|
@ -73,7 +84,7 @@ i libclang 21, a opcjonalnie `pkg-config`.
|
||||||
| Fedora | `gcc-c++ cmake ninja-build pkgconf llvm-devel clang-devel` |
|
| Fedora | `gcc-c++ cmake ninja-build pkgconf llvm-devel clang-devel` |
|
||||||
| Arch | `base-devel cmake ninja pkgconf llvm clang` |
|
| Arch | `base-devel cmake ninja pkgconf llvm clang` |
|
||||||
|
|
||||||
Jeśli CMake nie znajduje LLVM, wskaż mu katalog:
|
Ta opcja nie była testowana. Jeśli CMake nie znajduje LLVM, wskaż mu katalog:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
cmake -S . -B build -G Ninja -DLLVM_DIR=/usr/lib/llvm-21/lib/cmake/llvm
|
cmake -S . -B build -G Ninja -DLLVM_DIR=/usr/lib/llvm-21/lib/cmake/llvm
|
||||||
|
|
@ -87,21 +98,23 @@ sudo cp build/finch /usr/local/bin/
|
||||||
finch version
|
finch version
|
||||||
```
|
```
|
||||||
|
|
||||||
Podczas pracy Finch potrzebuje działającego kompilatora C (`cc`). Używa go jako **linkera**,
|
Podczas pracy Finch potrzebuje kompilatora C (`cc`). Używa go do linkowania programów i jednorazowo
|
||||||
który skleja skompilowany kod w gotowy program. Inny kompilator wskażesz zmienną środowiskową `CC`.
|
do zbudowania swojej małej biblioteki uruchomieniowej, którą trzyma w `~/.cache/finch`.
|
||||||
|
Inny kompilator wskażesz zmienną `CC`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 3. Polecenie finch
|
## 3. Polecenie finch
|
||||||
|
|
||||||
```
|
```
|
||||||
finch run <plik.fn> skompiluj i od razu uruchom
|
finch run <plik.fn> [argumenty...] skompiluj i od razu uruchom
|
||||||
finch build <plik.fn> [-o nazwa] skompiluj do programu (domyślna nazwa: nazwa pliku)
|
finch build <plik.fn> [-o nazwa] skompiluj do programu (domyślna nazwa: nazwa pliku)
|
||||||
finch ir <plik.fn> pokaż LLVM IR (dla ciekawskich)
|
finch ir <plik.fn> pokaż LLVM IR (dla ciekawskich)
|
||||||
finch version pokaż wersję
|
finch version pokaż wersję
|
||||||
|
|
||||||
opcje:
|
opcje:
|
||||||
-l <lib> dolinkuj bibliotekę C, to samo co link "lib" w pliku
|
-l <lib> dolinkuj bibliotekę C, to samo co link "lib" w pliku
|
||||||
|
-g dodaj informacje dla debuggera (gdb / lldb)
|
||||||
-O0 bez optymalizacji
|
-O0 bez optymalizacji
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -109,13 +122,13 @@ Przykłady:
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
finch run hello.fn # wypisuje wynik
|
finch run hello.fn # wypisuje wynik
|
||||||
|
finch run narzedzie.fn dane.txt -v # argumenty po nazwie pliku trafiają do programu
|
||||||
finch build gra.fn -o mojagra # tworzy ./mojagra
|
finch build gra.fn -o mojagra # tworzy ./mojagra
|
||||||
./mojagra
|
finch build gra.fn -g -O0 # wersja dla debuggera
|
||||||
finch run okno.fn -l glfw # z biblioteką C
|
|
||||||
```
|
```
|
||||||
|
|
||||||
`finch run` przekazuje dalej kod wyjścia twojego programu. Jeśli program się wysypie,
|
`finch run` przekazuje dalej kod wyjścia programu. Jeśli program się wysypie, powie jak
|
||||||
powie jak (np. `the program crashed: Segmentation fault`).
|
(np. `the program crashed: Segmentation fault`).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -126,8 +139,14 @@ powie jak (np. `the program crashed: Segmentation fault`).
|
||||||
/* albo zajmuje
|
/* albo zajmuje
|
||||||
kilka linijek */
|
kilka linijek */
|
||||||
|
|
||||||
import "math.h" // nagłówki C (opcjonalne), zawsze na górze
|
import "math.h" // nagłówki C (opcjonalne), na górze
|
||||||
link "m" // biblioteki C do dolinkowania (opcjonalne)
|
import ksztalty // moduły Fincha (opcjonalne): ksztalty.fn obok tego pliku
|
||||||
|
link "m" // biblioteki albo pliki C do dolinkowania (opcjonalne)
|
||||||
|
|
||||||
|
struct Punkt { // własne typy
|
||||||
|
int x
|
||||||
|
int y
|
||||||
|
}
|
||||||
|
|
||||||
fn main() { // tu zaczyna się program
|
fn main() { // tu zaczyna się program
|
||||||
print("Cześć")
|
print("Cześć")
|
||||||
|
|
@ -136,12 +155,13 @@ fn main() { // tu zaczyna się program
|
||||||
|
|
||||||
Zasady, które warto znać:
|
Zasady, które warto znać:
|
||||||
|
|
||||||
- **Jedna instrukcja na linijkę.** Średników nie ma. Długie wyrażenie możesz złamać
|
- **Jedna instrukcja na linijkę.** Średników nie ma. Długie wyrażenie możesz złamać **po** operatorze
|
||||||
**po** operatorze (`a +⏎ b`) albo w dowolnym miejscu wewnątrz nawiasów `( )`.
|
(`a +⏎ b`) albo w dowolnym miejscu wewnątrz nawiasów `( )` lub `[ ]`.
|
||||||
- **Klamry są zawsze obowiązkowe** po `if`, `else`, `for`, `while`, a otwierająca `{` stoi w tej samej linijce.
|
- **Klamry są zawsze obowiązkowe** po `if`, `else`, `for`, `while`, a otwierająca `{` stoi w tej samej linijce.
|
||||||
- **Bez nawiasów wokół warunków:** `if x > 5 {`, a nie `if (x > 5) {`.
|
- **Bez nawiasów wokół warunków:** `if x > 5 {`, a nie `if (x > 5) {`.
|
||||||
- Funkcje mogą być w pliku w dowolnej kolejności.
|
- Funkcje i struktury mogą być w pliku w dowolnej kolejności.
|
||||||
- `main` to `fn main()` albo `fn main() -> int` (zwraca kod wyjścia).
|
- `main` to `fn main()`, `fn main() -> int` (zwraca kod wyjścia) albo `fn main([]str args)`
|
||||||
|
(dostaje argumenty z linii poleceń; `args[0]` to ścieżka samego programu).
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -150,19 +170,20 @@ Zasady, które warto znać:
|
||||||
```c
|
```c
|
||||||
x := 5 // nowa zmienna, typ zgadnięty (int)
|
x := 5 // nowa zmienna, typ zgadnięty (int)
|
||||||
int y = 10 // nowa zmienna, typ podany jawnie
|
int y = 10 // nowa zmienna, typ podany jawnie
|
||||||
int z // bez wartości: startuje od zera ("" dla str, null dla wskaźników)
|
int z // bez wartości: startuje od zera ("" dla str, [] dla tablic, null dla wskaźników)
|
||||||
|
Punkt p // struktura bez wartości: zera albo wartości domyślne struktury
|
||||||
|
|
||||||
x = 7 // przypisanie
|
x = 7 // przypisanie
|
||||||
x += 1 // także -= *= /= %=
|
x += 1 // także -= *= /= %=
|
||||||
```
|
```
|
||||||
|
|
||||||
- Nazwę można zadeklarować **raz** w funkcji. Finch nie pozwala użyć tej samej nazwy ponownie
|
- Nazwę można zadeklarować **raz** w funkcji. Finch nie pozwala użyć jej ponownie w bloku
|
||||||
w bloku wewnętrznym (nie ma „przesłaniania”), bo to częste źródło pomyłek.
|
wewnętrznym (nie ma „przesłaniania”), bo to częste źródło pomyłek.
|
||||||
- Zmienna istnieje od deklaracji do końca bloku `{ }`, w którym powstała.
|
- Zmienna istnieje od deklaracji do końca bloku `{ }`, w którym powstała.
|
||||||
- Nazwy: litery ASCII, cyfry i `_`, bez cyfry na początku. Polskie litery tylko w tekstach w cudzysłowie.
|
- Nazwy: litery ASCII, cyfry i `_`, bez cyfry na początku. Polskie litery tylko w tekstach w cudzysłowie.
|
||||||
Nazwy typów (`int`, `u8`, …) i słowa kluczowe są zarezerwowane.
|
Nazwy typów (`int`, `u8`, …), funkcji wbudowanych i słowa kluczowe są zarezerwowane.
|
||||||
|
|
||||||
**Słowa kluczowe:** `fn return if else while for in break continue true false null import link`
|
**Słowa kluczowe:** `fn return if else while for in break continue true false null import link struct defer`
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -176,7 +197,9 @@ x += 1 // także -= *= /= %=
|
||||||
| `float` | liczba z przecinkiem, 64-bitowa (to samo co `f64`) | `3.14` |
|
| `float` | liczba z przecinkiem, 64-bitowa (to samo co `f64`) | `3.14` |
|
||||||
| `bool` | `true` albo `false` | |
|
| `bool` | `true` albo `false` | |
|
||||||
| `char` | jeden znak wielkości bajtu | `'A'`, `'\n'` |
|
| `char` | jeden znak wielkości bajtu | `'A'`, `'\n'` |
|
||||||
| `str` | tekst (napis w stylu C) | `"cześć\tświecie"` |
|
| `str` | tekst | `"cześć\tświecie"` |
|
||||||
|
| `[]T` | lista (tablica) elementów `T` | `[1, 2, 3]` |
|
||||||
|
| twoje struktury | nazwane grupy wartości | `Punkt(1, 2)` |
|
||||||
|
|
||||||
Znaki specjalne w tekstach: `\n` nowa linia, `\t` tabulator, `\r`, `\0`, `\\`, `\"`, `\'`.
|
Znaki specjalne w tekstach: `\n` nowa linia, `\t` tabulator, `\r`, `\0`, `\\`, `\"`, `\'`.
|
||||||
|
|
||||||
|
|
@ -191,48 +214,41 @@ Znaki specjalne w tekstach: `\n` nowa linia, `\t` tabulator, `\r`, `\0`, `\\`, `
|
||||||
|
|
||||||
`f32` to 32-bitowa liczba z przecinkiem (ok. 7 cyfr znaczących), `f64` to 64-bitowa (ok. 15–16).
|
`f32` to 32-bitowa liczba z przecinkiem (ok. 7 cyfr znaczących), `f64` to 64-bitowa (ok. 15–16).
|
||||||
|
|
||||||
### Wskaźniki
|
|
||||||
|
|
||||||
`ptr[T]` wskazuje na wartość typu `T`. Samo `ptr` wskazuje na „coś” nieznanego typu,
|
|
||||||
jak `void*` w C. Szczegóły w rozdziale [Wskaźniki](#10-wskaźniki).
|
|
||||||
|
|
||||||
### Zamiana typów
|
### Zamiana typów
|
||||||
|
|
||||||
Finch zamienia typy sam **tylko wtedy, gdy nic nie może zginąć**:
|
Finch zamienia typy sam **tylko wtedy, gdy nic nie może zginąć**:
|
||||||
|
|
||||||
| Z | Na | Automatycznie? |
|
| Z | Na | Automatycznie? |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| mniejsza liczba całkowita | większa o tej samej „znakowości” (`i8`→`i32`, `u8`→`u64`) | ✅ |
|
| mniejsza liczba całkowita | większa o tej samej znakowości (`i8`→`i32`, `u8`→`u64`) | ✅ |
|
||||||
| bez znaku | ściśle większa ze znakiem (`u8`→`i16`, `u32`→`i64`) | ✅ |
|
| bez znaku | ściśle większa ze znakiem (`u8`→`i16`, `u32`→`i64`) | ✅ |
|
||||||
| dowolna liczba całkowita | `float` / `f32` | ✅ |
|
| dowolna liczba całkowita | `float` / `f32` | ✅ |
|
||||||
| `f32` | `f64` | ✅ |
|
| `f32` | `f64` | ✅ |
|
||||||
| `null` | dowolny wskaźnik | ✅ |
|
| `null` | dowolny wskaźnik | ✅ |
|
||||||
| dowolny wskaźnik, `str` | `ptr` | ✅ |
|
| dowolny wskaźnik | `ptr`, a `ptr` na dowolny wskaźnik | ✅ |
|
||||||
| `ptr` | dowolny `ptr[T]` | ✅ |
|
|
||||||
| wszystko inne | | ❌ napisz to jawnie: `typ(wartość)` |
|
| wszystko inne | | ❌ napisz to jawnie: `typ(wartość)` |
|
||||||
|
|
||||||
**Liczby wpisane w kod się dopasowują.** Liczba napisana wprost w kodzie pasuje do każdego typu,
|
**Liczby wpisane w kod się dopasowują.** Liczba napisana wprost w kodzie pasuje do każdego typu,
|
||||||
który ją pomieści: `u8 b = 200` działa, a `u8 b = 300` to błąd (`the number 300 doesn't fit in u8`).
|
który ją pomieści: `u8 b = 200` działa, a `u8 b = 300` to błąd. To samo dotyczy stałych z nagłówków C.
|
||||||
To samo dotyczy stałych z nagłówków C.
|
|
||||||
|
|
||||||
**Jawna zamiana** wygląda jak wywołanie funkcji o nazwie typu:
|
**Jawna zamiana** wygląda jak wywołanie funkcji o nazwie typu:
|
||||||
|
|
||||||
```c
|
```c
|
||||||
int(3.99) // 3 (obcina część ułamkową)
|
int(3.99) // 3 (obcina część ułamkową)
|
||||||
int(-3.99) // -3
|
float(7) / 2 // 3.5
|
||||||
float(7) / 2 // 3.5
|
u8(300) // 44 (zostawia najniższe 8 bitów)
|
||||||
u8(300) // 44 (zostawia najniższe 8 bitów)
|
int('A') // 65
|
||||||
i8(200) // -56
|
char(66) // 'B'
|
||||||
int('A') // 65
|
bool(0) // false (każda liczba różna od zera to true)
|
||||||
char(66) // 'B'
|
str(42) // "42" (też float, bool, char; str([]u8) zamienia bajty na tekst)
|
||||||
bool(0) // false (każda liczba różna od zera to true)
|
int("42") // 42 (zatrzymuje program, jeśli tekst nie jest liczbą)
|
||||||
ptr(tekst) // str jako wskaźnik bez typu
|
float("2.5") // 2.5
|
||||||
str(p) // wskaźnik jako str
|
ptr(p) // wskaźnik z typem jako wskaźnik bez typu
|
||||||
|
str(p) // wskaźnik na znaki z C jako tekst
|
||||||
```
|
```
|
||||||
|
|
||||||
**Liczby o stałym rozmiarze się „zawijają”**, jak w prawdziwym sprzęcie: `u8` równe 255 plus 1 daje 0.
|
**Liczby o stałym rozmiarze się „zawijają”**, jak w prawdziwym sprzęcie: `u8` równe 255 plus 1 daje 0.
|
||||||
Działania liczą się w typie użytych wartości, więc `u8(250) + 10` daje `4`, a nie `260`.
|
Działania liczą się w typie użytych wartości, więc `u8(250) + 10` daje `4`, a nie `260`.
|
||||||
Jeśli potrzebujesz więcej miejsca, najpierw zamień typ: `int(x) + 10`.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -242,8 +258,8 @@ Jeśli potrzebujesz więcej miejsca, najpierw zamień typ: `int(x) + 10`.
|
||||||
|
|
||||||
| Priorytet | Operatory | Znaczenie |
|
| Priorytet | Operatory | Znaczenie |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| 5 | `*` `/` `%` `<<` `>>` `&` | mnożenie, dzielenie, reszta, przesunięcie bitów w lewo/prawo, bitowe AND |
|
| 5 | `*` `/` `%` `<<` `>>` `&` | mnożenie, dzielenie, reszta, przesunięcia bitów, bitowe AND |
|
||||||
| 4 | `+` `-` `\|` `^` | dodawanie, odejmowanie, bitowe OR, bitowe XOR |
|
| 4 | `+` `-` `\|` `^` | dodawanie (i sklejanie tekstu), odejmowanie, bitowe OR, bitowe XOR |
|
||||||
| 3 | `==` `!=` `<` `<=` `>` `>=` | porównania |
|
| 3 | `==` `!=` `<` `<=` `>` `>=` | porównania |
|
||||||
| 2 | `&&` | logiczne I |
|
| 2 | `&&` | logiczne I |
|
||||||
| 1 | `\|\|` | logiczne LUB |
|
| 1 | `\|\|` | logiczne LUB |
|
||||||
|
|
@ -251,18 +267,16 @@ Jeśli potrzebujesz więcej miejsca, najpierw zamień typ: `int(x) + 10`.
|
||||||
Jednoargumentowe (przed wartością): `-x` zmiana znaku, `!x` logiczne NIE, `~x` odwrócenie wszystkich bitów.
|
Jednoargumentowe (przed wartością): `-x` zmiana znaku, `!x` logiczne NIE, `~x` odwrócenie wszystkich bitów.
|
||||||
|
|
||||||
> **Celowo inaczej niż w C:** operatory bitowe wiążą mocniej niż porównania, więc
|
> **Celowo inaczej niż w C:** operatory bitowe wiążą mocniej niż porównania, więc
|
||||||
> `flagi & 4 != 0` znaczy `(flagi & 4) != 0`. W C to samo po cichu znaczy co innego.
|
> `flagi & 4 != 0` znaczy `(flagi & 4) != 0`.
|
||||||
|
|
||||||
Uwagi:
|
Uwagi:
|
||||||
|
|
||||||
- `/` na liczbach całkowitych zaokrągla w stronę zera: `7 / 2` to `3`, `-7 / 2` to `-3`. `%` ma znak lewej strony.
|
- `/` na liczbach całkowitych zaokrągla w stronę zera: `7 / 2` to `3`. `%` ma znak lewej strony.
|
||||||
- Dzielenie przez zero **zatrzymuje program** komunikatem `runtime error: division by zero` z numerem linijki.
|
- Dzielenie przez zero **zatrzymuje program** komunikatem `runtime error: division by zero` z numerem linijki.
|
||||||
Jeśli zero jest wpisane wprost w kod, jest to błąd już przy kompilacji.
|
|
||||||
- `&&` i `||` liczą prawą stronę tylko wtedy, gdy to potrzebne.
|
- `&&` i `||` liczą prawą stronę tylko wtedy, gdy to potrzebne.
|
||||||
- Tekst (`str`) można porównywać przez `==` i `!=` (porównuje zawartość). `<` i `>` na tekstach nie działają.
|
- Tekst: `+` skleja, `==` `!=` porównują treść, `<` `>` porównują alfabetycznie (bajt po bajcie).
|
||||||
- Wskaźniki porównuje się przez `==` i `!=`, także z `null`.
|
- Wskaźniki porównuje się przez `==` i `!=`, także z `null`. `str` nigdy nie jest `null`.
|
||||||
- Operatory bitowe wymagają liczb całkowitych. Dla `bool` używaj `&&` i `||`.
|
- Tablic i struktur nie porównasz przez `==`; porównuj ich części.
|
||||||
- `>>` na liczbach ze znakiem zachowuje znak (`-16 >> 2` to `-4`). Na liczbach bez znaku wypełnia zerami.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|
@ -285,14 +299,33 @@ for i in 0..10 { // i = 0, 1, …, 9 (koniec nie jest wliczany)
|
||||||
if i == 3 { continue }
|
if i == 3 { continue }
|
||||||
if i == 8 { break }
|
if i == 8 { break }
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for imie in imiona { // każdy element tablicy (albo każdy znak str)
|
||||||
|
print(imie)
|
||||||
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- Warunek musi być typu `bool`. `if x {` z liczbą to błąd; napisz `if x != 0 {`.
|
- Warunek musi być typu `bool`. `if x {` z liczbą to błąd; napisz `if x != 0 {`.
|
||||||
- W `for i in a..b` oba końce są liczbami całkowitymi obliczanymi **raz**, przed startem pętli.
|
- W `for i in a..b` oba końce są liczone **raz**. `i` jest typu `int` i nie można go zmieniać w pętli.
|
||||||
`i` jest typu `int` i nie można go zmieniać wewnątrz pętli.
|
- W `for x in lista` zmiennej `x` też nie zmienisz. Żeby zmieniać elementy, przechodź po indeksach:
|
||||||
|
`for i in 0..lista.len { lista[i] = ... }`. Dodawanie do listy w trakcie pętli jest dozwolone.
|
||||||
- `while true { ... }` kręci się do `break` albo `return`.
|
- `while true { ... }` kręci się do `break` albo `return`.
|
||||||
- Kod po `return`, `break` lub `continue` w tym samym bloku to błąd, bo nigdy się nie wykona.
|
- Kod po `return`, `break` lub `continue` w tym samym bloku to błąd, bo nigdy się nie wykona.
|
||||||
|
|
||||||
|
### defer
|
||||||
|
|
||||||
|
`defer` uruchamia instrukcję, gdy bieżący blok się kończy, niezależnie od tego, jak się kończy:
|
||||||
|
normalnie, przez `return`, `break` lub `continue`. Kilka `defer` wykonuje się w odwrotnej kolejności.
|
||||||
|
Przydaje się do sprzątania:
|
||||||
|
|
||||||
|
```c
|
||||||
|
f := fopen("dane.txt", "r")
|
||||||
|
defer fclose(f)
|
||||||
|
// ... używaj f; zostanie zamknięty na końcu bloku, na każdej ścieżce
|
||||||
|
```
|
||||||
|
|
||||||
|
Instrukcja w `defer` nie może zawierać `return`, `break` ani `continue`.
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 9. Funkcje
|
## 9. Funkcje
|
||||||
|
|
@ -308,32 +341,129 @@ fn bez_wyniku(str wiadomosc) { // bez "->": nic nie zwraca
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
- Parametry są kopiami. Zmiana parametru nie zmienia zmiennej u wywołującego.
|
- Argumenty zachowują się jak kopie: zmiana parametru nigdy nie zmienia zmiennej u wywołującego.
|
||||||
Do tego służą wskaźniki (niżej).
|
(Finch kopiuje naprawdę tylko wtedy, gdy trzeba: funkcja, która nie zmienia tablicy, dostaje ją za darmo.)
|
||||||
|
Żeby zmienić zmienną wywołującego, przekaż wskaźnik, zobacz [Wskaźniki](#14-wskaźniki).
|
||||||
- Funkcja z `-> typ` musi zwrócić wartość na każdej ścieżce. Finch to sprawdza.
|
- Funkcja z `-> typ` musi zwrócić wartość na każdej ścieżce. Finch to sprawdza.
|
||||||
- Funkcji nie można definiować wewnątrz innej funkcji.
|
- Funkcji nie można definiować wewnątrz innej funkcji.
|
||||||
- Wbudowane nazwy, których nie możesz użyć: `print`, `addr` i wszystkie nazwy typów.
|
|
||||||
|
|
||||||
### Funkcje wbudowane
|
|
||||||
|
|
||||||
| Funkcja | Co robi |
|
|
||||||
|---|---|
|
|
||||||
| `print(a, b, ...)` | Wypisuje wszystkie wartości oddzielone spacjami i przechodzi do nowej linii. Działa z każdym typem. |
|
|
||||||
| `addr(x)` | Daje wskaźnik na zmienną `x`. |
|
|
||||||
| `int(x)`, `u8(x)`, `float(x)`, … | Zamienia typy (zobacz [Zamiana typów](#zamiana-typów)). |
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 10. Wskaźniki
|
## 10. Tablice
|
||||||
|
|
||||||
Wskaźnik przechowuje **adres** wartości, czyli miejsce w pamięci, gdzie ona leży. Finch zamiast
|
```c
|
||||||
`*` i `&` z C używa słów:
|
liczby := [5, 3, 8] // tablica int
|
||||||
|
[]str imiona // pusta tablica str
|
||||||
|
siatka := [[1, 2], [3, 4]] // tablice tablic
|
||||||
|
[]f32 xs = [1, 2.5] // typ decyduje, czym staną się liczby
|
||||||
|
```
|
||||||
|
|
||||||
|
| Operacja | Znaczenie |
|
||||||
|
|---|---|
|
||||||
|
| `a.len` | liczba elementów |
|
||||||
|
| `a[i]` | element `i` (od 0); poza zakresem program zatrzymuje się z czytelnym komunikatem |
|
||||||
|
| `a[i] = x` | zmiana elementu |
|
||||||
|
| `a.push(x)` | dodaj na końcu |
|
||||||
|
| `a.pop()` | zabierz ostatni i go oddaj |
|
||||||
|
| `a.insert(i, x)` | wstaw `x` na pozycję `i`, przesuwając resztę |
|
||||||
|
| `a.remove(i)` | usuń pozycję `i` i ją oddaj |
|
||||||
|
| `a.clear()` | usuń wszystko |
|
||||||
|
| `a.resize(n)` | zmień długość na `n` (nowe elementy to zera) |
|
||||||
|
| `a.contains(x)`, `a.find(x)` | czy `x` jest w środku? jego indeks albo -1 (liczby, znaki, bool, str) |
|
||||||
|
| `a.sort()`, `a.reverse()` | w miejscu (liczby, znaki, str) |
|
||||||
|
| `a.slice(s, e)` | nowa tablica z elementami `s` … `e-1` |
|
||||||
|
| `a.join(sep)` | dla `[]str`: jeden tekst z `sep` między częściami |
|
||||||
|
| `a.ptr` | adres pierwszego elementu (dla C) |
|
||||||
|
| `print(a)` | wypisuje `[1, 2, 3]` |
|
||||||
|
|
||||||
|
**Przypisanie kopiuje:** po `b := a` zmiana `b` nie zmienia `a`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 11. Tekst (str)
|
||||||
|
|
||||||
|
```c
|
||||||
|
s := "Cześć"
|
||||||
|
s += ", świecie" // sklejanie
|
||||||
|
print(s.len, s[0]) // .len liczy bajty; ą, ś, ż… zajmują po 2
|
||||||
|
s[0] = 'D' // zmiana znaku
|
||||||
|
```
|
||||||
|
|
||||||
|
| Metoda | Oddaje |
|
||||||
|
|---|---|
|
||||||
|
| `s.sub(a, b)` | fragment od `a` do `b-1` |
|
||||||
|
| `s.find(t)` | gdzie zaczyna się `t`, albo -1 |
|
||||||
|
| `s.contains(t)`, `s.starts_with(t)`, `s.ends_with(t)` | `bool` |
|
||||||
|
| `s.split(sep)` | `[]str`; `split("")` daje pojedyncze znaki |
|
||||||
|
| `s.trim()` | bez spacji i nowych linii na obu końcach |
|
||||||
|
| `s.upper()`, `s.lower()` | zmienione litery A–Z / a–z (tylko ASCII) |
|
||||||
|
| `s.replace(a, b)` | każde `a` zamienione na `b` |
|
||||||
|
| `s.repeat(n)` | `s` n razy |
|
||||||
|
| `s.bytes()` | `[]u8` z bajtami |
|
||||||
|
| `s.ptr` | `ptr[char]` dla C (ważny, dopóki żyje `s`) |
|
||||||
|
|
||||||
|
`str` pamięta swoją długość, więc `.len` działa natychmiast. Zawsze kończy się zerem, więc
|
||||||
|
przekazanie go do C jako `char*` działa.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 12. Struktury
|
||||||
|
|
||||||
|
```c
|
||||||
|
struct Gracz {
|
||||||
|
str imie
|
||||||
|
int zycia = 3 // wartość domyślna
|
||||||
|
[]int wyniki
|
||||||
|
Punkt pozycja // struktury w strukturach
|
||||||
|
}
|
||||||
|
|
||||||
|
g := Gracz(imie: "Ola") // po nazwie: brakujące pola dostają domyślne (albo zero)
|
||||||
|
q := Punkt(1, 2) // po kolei: wtedy trzeba podać każde pole
|
||||||
|
g.zycia -= 1
|
||||||
|
g.wyniki.push(10)
|
||||||
|
g.pozycja.x = 5
|
||||||
|
print(g) // Gracz(imie: "Ola", zycia: 2, wyniki: [10], pozycja: Punkt(x: 5, y: 0))
|
||||||
|
```
|
||||||
|
|
||||||
|
- Przypisanie albo przekazanie struktury ją kopiuje, razem z jej tablicami i tekstami.
|
||||||
|
- Struktura nie może zawierać samej siebie wprost; dla takiego pola użyj `ptr[Wezel]` albo `[]Wezel` (drzewa, listy).
|
||||||
|
- Struktury nie mają metod. Pisz funkcje, które je przyjmują: `fn wylecz(Gracz g) -> Gracz`.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 13. Pamięć: kto co zwalnia
|
||||||
|
|
||||||
|
Tablic, tekstów i struktur nie zwalniasz nigdy. Finch robi to za ciebie, w przewidywalnym momencie:
|
||||||
|
**gdy kończy się blok, do którego wartość należy** (`}`), albo wcześniej przy `return`, `break`, `continue`.
|
||||||
|
|
||||||
|
- Zmienna **jest właścicielem** swojej wartości. Przypisanie kopiuje, więc dwie zmienne nigdy nie dzielą jednej listy.
|
||||||
|
- Wartość z wywołania funkcji albo wyrażenia jest **przenoszona** tam, gdzie ją zapisujesz, bez kopiowania.
|
||||||
|
- `return lista` przenosi zmienną poza funkcję, bez kopiowania.
|
||||||
|
- Parametry funkcji są **pożyczane**: funkcja dostaje wartość wywołującego bez kopii. Jeśli ją zmienia,
|
||||||
|
Finch najpierw robi jej prywatną kopię. Zauważysz to najwyżej po szybkości.
|
||||||
|
|
||||||
|
Do pamięci zarządzanej samodzielnie (listy wiązane, drzewa, dzielenie między strukturami):
|
||||||
|
|
||||||
|
```c
|
||||||
|
wezel := new(Wezel(wartosc: 1)) // wstaw wartość na stertę, dostajesz ptr[Wezel]
|
||||||
|
defer free(wezel) // free(...) ją oddaje (razem z jej tablicami i tekstami)
|
||||||
|
```
|
||||||
|
|
||||||
|
Pamięć z C (`malloc`, obiekty bibliotek) zwalniasz funkcjami z C, jak w C.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 14. Wskaźniki
|
||||||
|
|
||||||
|
Wskaźnik przechowuje **adres** wartości. Finch zamiast `*` i `&` z C używa słów:
|
||||||
|
|
||||||
| C | Finch | Znaczenie |
|
| C | Finch | Znaczenie |
|
||||||
|---|---|---|
|
|---|---|---|
|
||||||
| `int *p` | `ptr[int] p` | p wskazuje na int |
|
| `int *p` | `ptr[int] p` | p wskazuje na int |
|
||||||
| `&x` | `addr(x)` | adres x |
|
| `&x` | `addr(x)` | adres x (także `addr(a[i])`, `addr(s.pole)`) |
|
||||||
| `*p` | `p.value` | wartość, na którą wskazuje p |
|
| `*p` | `p.value` | wartość, na którą wskazuje p |
|
||||||
|
| `p->pole` | `p.pole` | pole struktury, na którą wskazuje p |
|
||||||
|
| `p[i]` | `p[i]` | indeksowanie jak w C (bez kontroli zakresu) |
|
||||||
| `NULL` | `null` | wskazuje donikąd |
|
| `NULL` | `null` | wskazuje donikąd |
|
||||||
| `void *` | `ptr` | wskazuje na coś nieznanego typu |
|
| `void *` | `ptr` | wskazuje na coś nieznanego typu |
|
||||||
|
|
||||||
|
|
@ -342,72 +472,98 @@ fn podwoj(ptr[int] p) {
|
||||||
p.value = p.value * 2
|
p.value = p.value * 2
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
x := 21
|
||||||
x := 21
|
podwoj(addr(x)) // x to 42
|
||||||
podwoj(addr(x))
|
|
||||||
print(x) // 42
|
|
||||||
|
|
||||||
ptr[int] nic = null
|
|
||||||
if nic == null {
|
|
||||||
print("pusty")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
```
|
```
|
||||||
|
|
||||||
Wskaźnik może wskazywać na wskaźnik: `ptr[ptr[int]]`, a potem `pp.value.value`.
|
Jeśli struktura ma własne pole o nazwie `value`, to `p.value` na wskaźniku do niej oznacza to pole.
|
||||||
|
|
||||||
Użycie `.value` na wskaźniku `null` **zatrzymuje program** komunikatem
|
Użycie `.value`, `.pole` albo `[i]` na wskaźniku `null` **zatrzymuje program** z czytelnym komunikatem.
|
||||||
`runtime error: used .value on a null pointer`, zamiast losowo go wysypać.
|
|
||||||
|
|
||||||
⚠️ Wskaźnika na zmienną nie wolno używać po zakończeniu funkcji, do której ta zmienna należała,
|
⚠️ Wskaźnika na zmienną nie wolno używać po zakończeniu jej bloku. Finch tego nie sprawdza.
|
||||||
bo zmienna wtedy już nie istnieje. Finch jeszcze tego nie sprawdza.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 11. Biblioteki z C
|
## 15. Funkcje wbudowane
|
||||||
|
|
||||||
Prawie każda biblioteka na Linuksie ma interfejs w C: grafika, dźwięk, sieć, bazy danych.
|
| Funkcja | Co robi |
|
||||||
Finch może z nich korzystać bezpośrednio.
|
|---|---|
|
||||||
|
| `print(a, b, ...)` | Wypisuje wszystkie wartości oddzielone spacjami i przechodzi do nowej linii. Działa z każdym typem, także z tablicami i strukturami. |
|
||||||
|
| `input()`, `input("pytanie")` | Czyta jedną linijkę wpisaną przez użytkownika (bez znaku nowej linii). Na końcu wejścia daje pusty tekst. |
|
||||||
|
| `read_file(sciezka)` | Cały plik jako `str`. Jeśli nie da się go przeczytać, zatrzymuje program z czytelnym komunikatem. |
|
||||||
|
| `write_file(sciezka, tekst)` | Zapisuje (zastępuje) plik; oddaje `true`, jeśli się udało. |
|
||||||
|
| `file_exists(sciezka)` | `true` / `false` |
|
||||||
|
| `shell(polecenie)` | Uruchamia polecenie powłoki i oddaje jego kod wyjścia. |
|
||||||
|
| `exit(kod)` | Natychmiast kończy program. |
|
||||||
|
| `addr(x)` | Wskaźnik na `x`; `addr(funkcja)` daje C wskaźnik na funkcję (callback). |
|
||||||
|
| `new(wartosc)`, `free(p)` | Ręczna pamięć na stercie (zobacz [Pamięć](#13-pamięć-kto-co-zwalnia)). |
|
||||||
|
| `int(x)`, `str(x)`, `u8(x)`, … | Zamiany typów (zobacz [Zamiana typów](#zamiana-typów)). |
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 16. Moduły
|
||||||
|
|
||||||
|
Program możesz podzielić na pliki. `import ksztalty` wczytuje `ksztalty.fn` z tego samego folderu
|
||||||
|
(albo z folderu wymienionego w zmiennej środowiskowej `FINCH_PATH`, rozdzielonych `:`).
|
||||||
|
|
||||||
|
```c
|
||||||
|
// ksztalty.fn
|
||||||
|
struct Pudlo {
|
||||||
|
float w
|
||||||
|
float h
|
||||||
|
}
|
||||||
|
|
||||||
|
fn pole(Pudlo p) -> float {
|
||||||
|
return p.w * p.h
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
```c
|
||||||
|
// main.fn
|
||||||
|
import ksztalty
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
p := ksztalty.Pudlo(2, 3)
|
||||||
|
print(ksztalty.pole(p))
|
||||||
|
ksztalty.Pudlo inne // typ z modułu w deklaracji
|
||||||
|
}
|
||||||
|
```
|
||||||
|
|
||||||
|
- Wszystkiego z modułu używasz z jego nazwą z przodu: `ksztalty.pole`, `ksztalty.Pudlo`.
|
||||||
|
- Moduł nie ma `main`. Moduły mogą importować inne moduły.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 17. Biblioteki z C
|
||||||
|
|
||||||
### Krok 1: zaimportuj nagłówek
|
### Krok 1: zaimportuj nagłówek
|
||||||
|
|
||||||
```c
|
```c
|
||||||
import "stdio.h"
|
import "stdio.h"
|
||||||
import "math.h"
|
|
||||||
import "GLFW/glfw3.h" // ścieżka w systemowych katalogach nagłówków
|
import "GLFW/glfw3.h" // ścieżka w systemowych katalogach nagłówków
|
||||||
import "mojalib.h" // nagłówek leżący obok twojego pliku .fn
|
import "mojalib.h" // nagłówek obok twojego pliku .fn
|
||||||
```
|
```
|
||||||
|
|
||||||
Finch czyta nagłówek przez **libclang** (parser C z clanga) i udostępnia:
|
Finch czyta nagłówek przez **libclang** (parser C z clanga) i udostępnia:
|
||||||
|
|
||||||
- **funkcje**, także te ze zmienną liczbą argumentów, jak `printf`,
|
- **funkcje**, także te ze zmienną liczbą argumentów, jak `printf`,
|
||||||
- **wartości `enum`**,
|
- **struktury**, przez wartość i przez wskaźnik (`Vector2`, `SDL_Rect`, `CXCursor`, …), razem z polami,
|
||||||
- **proste stałe `#define`**, które są pojedynczą liczbą, np. `M_PI`, `EOF`, `GL_COLOR_BUFFER_BIT`,
|
- **wartości `enum`** i **proste stałe `#define`** (`M_PI`, `GL_COLOR_BUFFER_BIT`),
|
||||||
- **zmienne globalne**, np. `stdout` i `stderr`.
|
- **zmienne globalne**, np. `stdout` i `stderr`.
|
||||||
|
|
||||||
### Krok 2: dolinkuj bibliotekę
|
### Krok 2: dolinkuj bibliotekę
|
||||||
|
|
||||||
Nagłówek tylko *opisuje* funkcje. Ich właściwy kod jest w pliku biblioteki (`libNAZWA.so`).
|
|
||||||
Powiedz Finchowi, której biblioteki użyć, na górze pliku:
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
link "glfw" // używa libglfw.so
|
link "glfw" // używa libglfw.so (najpierw pyta pkg-config, jeśli jest)
|
||||||
link "GL" // używa libGL.so
|
link "pomocnicze.c" // skompiluj i dołącz własny plik C (obok pliku .fn)
|
||||||
|
link "gotowe.a" // albo plik obiektowy / bibliotekę statyczną
|
||||||
```
|
```
|
||||||
|
|
||||||
Wpisz samą nazwę: dla `libglfw.so` to `glfw`. Jeśli `pkg-config` zna tę nazwę, Finch użyje jego
|
|
||||||
ustawień (ścieżek i dodatkowych bibliotek). W przeciwnym razie przekaże linkerowi `-lNAZWA`.
|
|
||||||
Biblioteka standardowa C i matematyczna (`libm`) są dolinkowane zawsze.
|
|
||||||
|
|
||||||
Na linii poleceń `-l NAZWA` robi to samo co `link "NAZWA"`.
|
|
||||||
|
|
||||||
Jeśli zapomnisz linijki `link`, Finch powie dokładnie, czego brakuje:
|
Jeśli zapomnisz linijki `link`, Finch powie dokładnie, czego brakuje:
|
||||||
|
|
||||||
```
|
```
|
||||||
error: glfwInit, glfwCreateWindow, glfwMakeContextCurrent and 5 more come from "GLFW/glfw3.h", but its library isn't linked
|
error: glfwInit, glfwCreateWindow, glfwMakeContextCurrent and 5 more come from "GLFW/glfw3.h", but its library isn't linked
|
||||||
the header only says the functions exist; their code lives in a library.
|
...
|
||||||
add this at the top of your file (with the library's real name):
|
|
||||||
|
|
||||||
link "glfw"
|
link "glfw"
|
||||||
```
|
```
|
||||||
|
|
||||||
|
|
@ -421,122 +577,138 @@ error: glfwInit, glfwCreateWindow, glfwMakeContextCurrent and 5 more come from "
|
||||||
| `float`, `double` | `f32`, `f64` |
|
| `float`, `double` | `f32`, `f64` |
|
||||||
| `_Bool` / `bool` | `bool` |
|
| `_Bool` / `bool` | `bool` |
|
||||||
| `enum` | odpowiadająca liczba całkowita ze znakiem |
|
| `enum` | odpowiadająca liczba całkowita ze znakiem |
|
||||||
| `char *`, `const char *` | `str` |
|
| `char *` jako **parametr albo wynik** | `str` |
|
||||||
| `int *`, `double *`, … | `ptr[i32]`, `ptr[f64]`, … |
|
| `char *` w strukturze albo za wskaźnikiem | `ptr[char]` (czytasz przez `str(p)`) |
|
||||||
| `void *`, `struct X *`, `FILE *`, wskaźniki na funkcje | `ptr` |
|
| `struct X` przez wartość | `X`, struktura z tymi samymi polami |
|
||||||
|
| `struct X *`, `int *`, … | `ptr[X]`, `ptr[i32]`, … |
|
||||||
|
| `int arr[16]` w strukturze | `[16]i32`: indeksujesz i używasz `.len` |
|
||||||
|
| `void *`, wskaźniki na funkcje, niekompletne struktury | `ptr` |
|
||||||
|
|
||||||
Czyli `int` z C to `i32` w Finchu. Liczby wpisane w kod dopasowują się same (`abs(-5)` działa),
|
### Przykład: struktury i raylib
|
||||||
ale zmienną typu `int` z Fincha trzeba zamienić: `abs(i32(x))`.
|
|
||||||
|
|
||||||
### Przykład
|
|
||||||
|
|
||||||
```c
|
```c
|
||||||
import "stdio.h"
|
import "raylib.h"
|
||||||
import "math.h"
|
link "raylib"
|
||||||
import "stdlib.h"
|
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
printf("%d + %d = %d\n", 2, 3, 5)
|
InitWindow(800, 450, "Finch")
|
||||||
print(sqrt(2), M_PI, RAND_MAX)
|
while !WindowShouldClose() {
|
||||||
|
BeginDrawing()
|
||||||
ptr[i32] n = malloc(4) // poproś C o 4 bajty pamięci
|
ClearBackground(Color(r: 30, g: 30, b: 40, a: 255))
|
||||||
n.value = 7
|
DrawCircleV(Vector2(400, 225), 50, Color(255, 136, 0, 255))
|
||||||
print(n.value)
|
EndDrawing()
|
||||||
free(n) // i oddaj je
|
}
|
||||||
|
CloseWindow()
|
||||||
fprintf(stderr, "to idzie na wyjście błędów\n")
|
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
Pełny przykład z grafiką jest w `examples/window.fn`: okno GLFW + OpenGL, które zmienia kolor.
|
Żeby dać C funkcję do wywołania zwrotnego (np. porównywarkę dla `qsort`), użyj `addr(mojaFunkcja)`.
|
||||||
`examples/llvm.fn` pokazuje, że Finch potrafi nawet sterować samym LLVM przez jego API w C.
|
Jej parametry muszą być typami C (liczby, wskaźniki, struktury C).
|
||||||
|
|
||||||
### Co jeszcze nie działa
|
### Co jeszcze nie działa
|
||||||
|
|
||||||
- Funkcje C, które przyjmują lub zwracają **`struct` przez wartość**, np. `div()`. Finch mówi o tym
|
- **Unie** C przez wartość i struktury z **polami bitowymi** przez wartość (wskaźniki do nich działają).
|
||||||
wprost, jeśli spróbujesz. Funkcje przyjmujące *wskaźnik* na strukturę działają.
|
- **Makra-funkcje** i makra, które nie są pojedynczą liczbą.
|
||||||
- **Makra-funkcje** (`#define MAX(a,b) ...`) i makra, które nie są pojedynczą liczbą.
|
|
||||||
- `long double`, liczby 128-bitowe.
|
- `long double`, liczby 128-bitowe.
|
||||||
- Odczytywanie **pól** struktury C.
|
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 12. Błędy
|
## 18. Błędy
|
||||||
|
|
||||||
### Błędy kompilacji
|
### Błędy kompilacji
|
||||||
|
|
||||||
Finch zatrzymuje się na pierwszym problemie i pokazuje, gdzie jest:
|
|
||||||
|
|
||||||
```
|
```
|
||||||
gra.fn:12:9: error: 'wynik' must be int, but this is str
|
gra.fn:12:9: error: 'wynik' must be int, but this is str
|
||||||
12 | wynik = "wysoki"
|
12 | wynik = "wysoki"
|
||||||
| ^
|
| ^
|
||||||
```
|
```
|
||||||
|
|
||||||
Format: `plik:linijka:kolumna: error: wyjaśnienie`, a pod spodem linijka ze znakiem `^` pod miejscem błędu.
|
Format: `plik:linijka:kolumna: error: wyjaśnienie`, a pod spodem linijka ze znakiem `^`.
|
||||||
Komunikaty są po angielsku.
|
Komunikaty są po angielsku.
|
||||||
|
|
||||||
### Błędy w trakcie działania
|
### Błędy w trakcie działania
|
||||||
|
|
||||||
Niektóre problemy widać dopiero, gdy program działa. Zamiast niezdefiniowanego zachowania
|
Zamiast niezdefiniowanego zachowania (jak w C) Finch zatrzymuje się z komunikatem i kodem wyjścia 1:
|
||||||
(jak w C) Finch zatrzymuje się z czytelnym komunikatem na wyjściu błędów i kodem wyjścia 1:
|
|
||||||
|
|
||||||
| Komunikat | Przyczyna |
|
| Komunikat | Przyczyna |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `runtime error: division by zero` | `/` albo `%` przez zmienną równą 0 |
|
| `runtime error: division by zero` | `/` albo `%` przez zmienną równą 0 |
|
||||||
| `runtime error: division overflows …` | najmniejsza liczba ze znakiem podzielona przez −1 |
|
| `runtime error: division overflows …` | najmniejsza liczba ze znakiem podzielona przez −1 |
|
||||||
| `runtime error: used .value on a null pointer` | odczyt lub zapis `p.value`, gdy `p` jest `null` |
|
| `runtime error: index 5 is out of range (the length is 3)` | `a[5]` na krótszej tablicy albo tekście |
|
||||||
|
| `runtime error: pop() on an empty array` | |
|
||||||
|
| `runtime error: used .value on a null pointer` | także `.pole` i `[i]` przez `null` |
|
||||||
|
| `runtime error: can't turn "x" into int` | `int(...)` / `float(...)` na tekście, który nie jest liczbą |
|
||||||
|
| `runtime error: can't read the file "…"` | `read_file` na brakującym albo nieczytelnym pliku |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 13. Rozwiązywanie problemów
|
## 19. Debugowanie
|
||||||
|
|
||||||
|
```sh
|
||||||
|
finch build gra.fn -g -O0 -o gra
|
||||||
|
gdb ./gra
|
||||||
|
(gdb) break gra.fn:12
|
||||||
|
(gdb) run
|
||||||
|
(gdb) bt # gdzie jesteśmy, przez które funkcje
|
||||||
|
(gdb) info locals # wszystkie zmienne
|
||||||
|
(gdb) print gracz.zycia
|
||||||
|
```
|
||||||
|
|
||||||
|
`-g` dodaje informacje dla debuggera (linijki, funkcje, zmienne, pola struktur). `-O0` zostawia wszystkie
|
||||||
|
zmienne widoczne; bez niego optymalizator może część z nich usunąć.
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 20. Rozwiązywanie problemów
|
||||||
|
|
||||||
| Problem | Rozwiązanie |
|
| Problem | Rozwiązanie |
|
||||||
|---|---|
|
|---|---|
|
||||||
| `can't find the C header 'x.h'` | Brakuje plików deweloperskich biblioteki. Zainstaluj je (Debian: `libx-dev`; Nix: dopisz do `shell.nix`). Własny nagłówek połóż obok pliku `.fn`. |
|
| `can't find the C header 'x.h'` | Brakuje plików deweloperskich biblioteki. Zainstaluj je (Debian: `libx-dev`; Nix: dopisz do `shell.nix`). |
|
||||||
| `… come from "x.h", but its library isn't linked` | Dopisz `link "nazwa"` na górze pliku. |
|
| `… come from "x.h", but its library isn't linked` | Dopisz `link "nazwa"` na górze pliku. |
|
||||||
| `the library 'x' wasn't found` | Biblioteka nie jest zainstalowana albo nazwa jest zła. Na Niksie dopisz ją do `shell.nix` i pracuj wewnątrz `nix-shell`. |
|
| `the library 'x' wasn't found` | Nie jest zainstalowana albo nazwa jest zła. Na Niksie dopisz ją do `shell.nix` i pracuj w `nix-shell`. |
|
||||||
| `the C function 'f' can't be used from Finch yet` | Używa struktury przez wartość albo innego nieobsługiwanego typu. Poszukaj wariantu, który przyjmuje wskaźniki. |
|
| `the C function 'f' can't be used from Finch yet` | Używa unii, pól bitowych albo innego nieobsługiwanego typu przez wartość. Poszukaj wariantu ze wskaźnikami. |
|
||||||
| `no C compiler found to link with` | Zainstaluj gcc lub clang albo ustaw `CC`. |
|
| `can't find the module 'x'` | Połóż `x.fn` obok importującego pliku albo ustaw `FINCH_PATH`. |
|
||||||
| Program się kompiluje, ale przy starcie nie znajduje biblioteki C | Został zlinkowany ze ścieżki, której system nie przeszukuje. Uruchamiaj go w tym samym `nix-shell` albo zainstaluj bibliotekę systemowo. |
|
| `couldn't build the Finch runtime` | Brak działającego kompilatora C. Zainstaluj gcc lub clang albo ustaw `CC`. |
|
||||||
| `unexpected character 'ż'` | Polska litera w nazwie. W nazwach używaj tylko a–z. |
|
| Biblioteka nie znajduje się przy starcie programu | Zlinkowano ją z folderu, którego system nie przeszukuje. Uruchamiaj w tym samym `nix-shell` albo zainstaluj ją systemowo. |
|
||||||
| CMake: `libclang not found` | Zainstaluj pakiet deweloperski libclang albo uruchom `cmake` w `nix-shell`. |
|
| `clang` w `nix-shell` nie widzi `stdio.h` | Masz stary `shell.nix`: `llvmPackages.clang` musi być przed `llvmPackages.libclang`. |
|
||||||
| Budowanie kończy się błędami API LLVM | Masz inną wersję LLVM niż 21. |
|
|
||||||
| Program nigdy się nie kończy | Warunek pętli nigdy nie staje się fałszywy. Naciśnij Ctrl+C. |
|
| Program nigdy się nie kończy | Warunek pętli nigdy nie staje się fałszywy. Naciśnij Ctrl+C. |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 14. Struktura projektu i testy
|
## 21. Struktura projektu i testy
|
||||||
|
|
||||||
```
|
```
|
||||||
Finch/
|
Finch/
|
||||||
├── src/ kompilator (C++)
|
├── src/ kompilator (C++)
|
||||||
├── examples/ przykładowe programy (hello, tour, types, c_import, window, llvm)
|
├── runtime/ finch_rt.c: mała biblioteka uruchomieniowa (teksty, tablice, wejście, pliki)
|
||||||
|
├── boot/ kompilator Fincha napisany w Finchu (zobacz przewodnik dla inżynierów)
|
||||||
|
├── examples/ hello, tour, types, structs, todo, guess, c_import, window, raylib, llvm
|
||||||
├── tests/
|
├── tests/
|
||||||
│ ├── run/ programy + dokładny wynik, który muszą wypisać (.out)
|
│ ├── run/ programy + dokładny wynik (.out) i wejście (.in)
|
||||||
│ ├── fail/ programy, które muszą się nie udać, z oczekiwanym błędem w 1. linijce
|
│ ├── fail/ programy, które muszą się nie udać, z oczekiwanym błędem w 1. linijce
|
||||||
│ └── run.sh skrypt uruchamiający testy
|
│ ├── run.sh uruchamia testy (MEMCHECK=1 sprawdza też pamięć valgrindem)
|
||||||
|
│ └── boot.sh buduje kompilator samohostujący nim samym i porównuje
|
||||||
├── docs/ ta dokumentacja (en, pl)
|
├── docs/ ta dokumentacja (en, pl)
|
||||||
├── shell.nix środowisko deweloperskie Nix
|
├── shell.nix środowisko deweloperskie Nix
|
||||||
└── CMakeLists.txt
|
└── CMakeLists.txt
|
||||||
```
|
```
|
||||||
|
|
||||||
Testy uruchomisz po zbudowaniu:
|
|
||||||
|
|
||||||
```sh
|
```sh
|
||||||
tests/run.sh # → 34 passed, 0 failed
|
tests/run.sh # → 58 passed, 0 failed
|
||||||
|
MEMCHECK=1 tests/run.sh # to samo pod valgrindem: bez wycieków i złych dostępów do pamięci
|
||||||
|
tests/boot.sh # sprawdzenie samohostowania (wymaga clanga)
|
||||||
```
|
```
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
## 15. Obecne ograniczenia
|
## 22. Obecne ograniczenia
|
||||||
|
|
||||||
Finch 1.0 to solidny rdzeń, a nie skończony język. Jeszcze nie ma:
|
Finch 2.0 to kompletny mały język, ale nie skończony. Jeszcze nie ma:
|
||||||
|
|
||||||
- `struct`, tablic, czytania z klawiatury (`input()`), sklejania tekstów (`"a" + "b"`).
|
- Metod w strukturach, typów generycznych, słowników (map), `match`. (Używaj tablic struktur i funkcji.)
|
||||||
Na razie użyj do tego funkcji z C (`scanf`, `snprintf`, `malloc`…).
|
- Błędów jako wartości: błąd w `int("x")` albo `read_file` zatrzymuje program. Sprawdzaj wcześniej (`file_exists`).
|
||||||
- Automatycznego zarządzania pamięcią (w planach: zwalnianie na końcu bloku i `defer`).
|
- Tekstu świadomego Unicode: `.len`, `s[i]` i `upper()` działają na bajtach / ASCII.
|
||||||
- Modułów Fincha (na razie jeden program = jeden plik `.fn`).
|
- Wątków.
|
||||||
- Platform innych niż Linux x86-64.
|
- Platform innych niż Linux x86-64.
|
||||||
|
|
||||||
Plan rozwoju jest w [README](../../README.pl.md#plan-rozwoju).
|
Plan rozwoju jest w [README](../../README.pl.md#plan-rozwoju).
|
||||||
|
|
|
||||||
15
examples/raylib.fn
Normal file
15
examples/raylib.fn
Normal file
|
|
@ -0,0 +1,15 @@
|
||||||
|
// A raylib window with a circle: C structs (Color, Vector2) passed by value.
|
||||||
|
// Needs raylib (in shell.nix).
|
||||||
|
import "raylib.h"
|
||||||
|
link "raylib"
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
InitWindow(800, 450, "Finch")
|
||||||
|
while !WindowShouldClose() {
|
||||||
|
BeginDrawing()
|
||||||
|
ClearBackground(Color(r: 30, g: 30, b: 40, a: 255))
|
||||||
|
DrawCircleV(Vector2(400, 225), 50, Color(255, 136, 0, 255))
|
||||||
|
EndDrawing()
|
||||||
|
}
|
||||||
|
CloseWindow()
|
||||||
|
}
|
||||||
1
notatka.txt
Normal file
1
notatka.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Kupić mleko
|
||||||
1
note.txt
Normal file
1
note.txt
Normal file
|
|
@ -0,0 +1 @@
|
||||||
|
Buy milk
|
||||||
|
|
@ -10,8 +10,9 @@ pkgs.mkShell {
|
||||||
ninja
|
ninja
|
||||||
pkg-config # finds the right flags for `link "..."`
|
pkg-config # finds the right flags for `link "..."`
|
||||||
|
|
||||||
# for examples/window.fn
|
# for examples/window.fn and examples/raylib.fn
|
||||||
glfw
|
glfw
|
||||||
libGL
|
libGL
|
||||||
|
raylib
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -230,7 +230,8 @@ Value *Codegen::own(const Value_ &v) {
|
||||||
}
|
}
|
||||||
|
|
||||||
void Codegen::release(const Value_ &v) {
|
void Codegen::release(const Value_ &v) {
|
||||||
if (v.fresh && v.v && owning(v.type)) dropValue(v.v, v.type);
|
// constants (string literals, empty arrays) own no memory: nothing to free
|
||||||
|
if (v.fresh && v.v && !isa<Constant>(v.v) && owning(v.type)) dropValue(v.v, v.type);
|
||||||
}
|
}
|
||||||
|
|
||||||
Value *Codegen::copyValue(Value *v, const FType &t) {
|
Value *Codegen::copyValue(Value *v, const FType &t) {
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue