mirror of
https://github.com/Nexoniarz/Finch.git
synced 2026-11-03 00:44:27 +00:00
Modules are known by their file: import button from ui/menu.fch and import ui/button are one module, two util.fch are two; min/max/abs/clamp win over C's int-only abs; completion after an import's other name; hover docs; engineers' guides
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_016GzNP6r8dg6WDxUVZy8wjL
This commit is contained in:
parent
17863ecf7b
commit
3ba2dcd5d6
16 changed files with 152 additions and 18 deletions
|
|
@ -343,7 +343,7 @@ import ui/button as btn // another name: btn.draw()
|
|||
| `union U` | `U`: `U u`, `u.field`, `U(field: v)`, by pointer to C (not by value) |
|
||||
| `#define N 4`, `"text"`, `(1u << 3)`, `((Uint64)2)` | constants (not function-like macros) |
|
||||
|
||||
A C function's `char *` result is a `str` already; structs by value work on every target (System V, Windows x64, ARM64).
|
||||
A C function's `char *` result is a `str` already; structs by value work with the System V, Windows x64 and ARM64 Linux calling conventions (tested in emulators; macOS by CI).
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
|
|
@ -98,6 +98,18 @@ its `endLine` (used by the language server). The old `fn name(...) type` order i
|
|||
`name.fch` there, the folders of `FINCH_PATH`, then the standard library `std/`. Each module is parsed once; its names
|
||||
are used as `module.name`. `import "x.h"` goes to the C importer instead.
|
||||
|
||||
A module is identified by its **file**: the key is its path from the main file's folder (or from a `FINCH_PATH` folder or
|
||||
`std/`) without `.fch` and without an `_<os>` suffix, e.g. `ui/button`. `Program.imports` holds the name each file uses
|
||||
(`button`, or `btn` for `import ui/button as btn`) and `Program.modules` the key; `modFor()` maps one to the other.
|
||||
Symbols use the key with `/` turned into `$` (`@finch.ui$button.make`).
|
||||
|
||||
**Constants.** `const NAME = expr` is a top-level node; `constValue()` evaluates the expression at each use, in the
|
||||
defining module with no local scopes, so it folds to a literal (integer literal operators are folded in `arith`).
|
||||
`checkConst()` allows only literals, names, operators, members and numeric conversions; `constBusy` catches cycles.
|
||||
|
||||
**Lexer extras.** `1e9` / `2.5e-3` are float tokens (the text is normalised to have a `.` for LLVM); `"""` strings are
|
||||
dedented by the closing line's indentation in `longString()`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Code generation
|
||||
|
|
@ -138,6 +150,14 @@ LLVM IR does not do the C calling convention for you, so `gen.fch` reproduces it
|
|||
|
||||
The same code is what lets the compiler call libclang, whose API passes `CXCursor`, `CXType` and `CXString` by value.
|
||||
|
||||
**Macros.** A `#define` that is one number or a string literal is read from its tokens. One whose tokens could be a
|
||||
constant expression (no braces, semicolons or statement keywords) is evaluated by clang: a second parse of the header
|
||||
adds `static const __auto_type __finch_m_NAME = (NAME);` for each, and `clang_Cursor_Evaluate` gives an int, a double
|
||||
or a string. Those that are not constants only produce errors in that second parse and are dropped.
|
||||
|
||||
**Unions** are a `CStruct` with `isUnion`: the LLVM type is `{ [n x iA] }` (size and alignment from clang), every field has
|
||||
offset 0, and a field is read through memory. They can't be passed by value to C (`unsupported` says why).
|
||||
|
||||
---
|
||||
|
||||
## 6. Driver, linking and targets
|
||||
|
|
@ -201,8 +221,9 @@ from the slot they flow into (`exprWant()`), so `[]f32 xs = [1, 2.5]` works.
|
|||
|
||||
### Binary operands: `unify(l, r)`
|
||||
|
||||
A literal side adapts to the other; otherwise the side that widens grows; `i32` + `u32` is an error;
|
||||
int + float → float; f32 + f64 → f64. There is no C integer promotion: `u8 + u8` stays `u8`.
|
||||
A literal side adapts to the other (also a float literal next to an `f32`: `x * 2.0` stays `f32`); otherwise the side
|
||||
that widens grows; `i32` + `u32` is an error; int + float → float; f32 + f64 → f64. There is no C integer promotion:
|
||||
`u8 + u8` stays `u8`. Two integer literals fold to a literal, so `FLAG_A | FLAG_B` still fits a `u64` or `u32`.
|
||||
|
||||
### Explicit conversions: `convert()`
|
||||
|
||||
|
|
|
|||
|
|
@ -97,6 +97,18 @@ kolejność `fn nazwa(...) typ` to błąd składni z podpowiedzią.
|
|||
katalogów z `FINCH_PATH`, potem biblioteki standardowej `std/`. Każdy moduł jest parsowany raz; jego nazwy są używane jako
|
||||
`modul.nazwa`. `import "x.h"` trafia do importera C.
|
||||
|
||||
Moduł rozpoznaje się po **pliku**: kluczem jest jego ścieżka od folderu głównego pliku (albo od folderu z `FINCH_PATH`
|
||||
lub `std/`) bez `.fch` i bez końcówki `_<system>`, np. `ui/przycisk`. `Program.imports` trzyma nazwę używaną w danym
|
||||
pliku (`przycisk`, albo `p` przy `import ui/przycisk as p`), a `Program.modules` klucz; `modFor()` zamienia jedno na drugie.
|
||||
Symbole używają klucza z `/` zamienionym na `$` (`@finch.ui$przycisk.rysuj`).
|
||||
|
||||
**Stałe.** `const NAZWA = wyrażenie` to węzeł najwyższego poziomu; `constValue()` liczy wyrażenie przy każdym użyciu, w
|
||||
module, w którym je zdefiniowano, bez zmiennych lokalnych, więc wychodzi literał (operatory na literałach całkowitych
|
||||
składa `arith`). `checkConst()` dopuszcza tylko literały, nazwy, operatory, pola i konwersje liczb; `constBusy` łapie pętle.
|
||||
|
||||
**Dodatki leksera.** `1e9` / `2.5e-3` to tokeny float (tekst dostaje `.` dla LLVM); teksty `"""` tracą wcięcie
|
||||
linii zamykającej w `longString()`.
|
||||
|
||||
---
|
||||
|
||||
## 4. Generowanie kodu
|
||||
|
|
@ -130,6 +142,14 @@ LLVM IR nie realizuje za ciebie konwencji wywołań C, więc `gen.fch` ją odtwa
|
|||
- reguły Microsoft x64 (struktury 1, 2, 4, 8 bajtów w rejestrze, reszta przez wskaźnik);
|
||||
- `makePlan` zamienia klasyfikację w plan wywołania; `cThunk` robi z `addr(fn)` coś, co C może wywołać (callbacki).
|
||||
|
||||
**Makra.** `#define` będący jedną liczbą albo tekstem czyta się z tokenów. Taki, którego tokeny mogą być wyrażeniem
|
||||
stałym (bez klamer, średników i słów instrukcji), liczy clang: drugie parsowanie nagłówka dodaje
|
||||
`static const __auto_type __finch_m_NAZWA = (NAZWA);` dla każdego, a `clang_Cursor_Evaluate` daje liczbę całkowitą,
|
||||
double albo tekst. Te, które nie są stałymi, dają tylko błędy w tym drugim parsowaniu i są pomijane.
|
||||
|
||||
**Unie** to `CStruct` z `isUnion`: typ LLVM to `{ [n x iA] }` (rozmiar i wyrównanie od clanga), każde pole ma
|
||||
przesunięcie 0, a pole czyta się przez pamięć. Nie da się ich przekazać do C przez wartość (`unsupported` mówi dlaczego).
|
||||
|
||||
Ten sam kod pozwala kompilatorowi wołać libclang, którego API przekazuje `CXCursor`, `CXType` i `CXString` przez wartość.
|
||||
|
||||
---
|
||||
|
|
@ -194,9 +214,10 @@ Literały tablic biorą typ elementu z miejsca, do którego trafiają (`exprWant
|
|||
|
||||
### Argumenty operatorów: `unify(l, r)`
|
||||
|
||||
Strona-literał dopasowuje się do drugiej; w przeciwnym razie rośnie strona, która się rozszerza;
|
||||
`i32` + `u32` to błąd; całkowita + zmiennoprzecinkowa → zmiennoprzecinkowa; f32 + f64 → f64.
|
||||
Nie ma promocji całkowitych z C: `u8 + u8` zostaje `u8`.
|
||||
Strona-literał dopasowuje się do drugiej (także literał float obok `f32`: `x * 2.0` zostaje `f32`); w przeciwnym razie
|
||||
rośnie strona, która się rozszerza; `i32` + `u32` to błąd; całkowita + zmiennoprzecinkowa → zmiennoprzecinkowa;
|
||||
f32 + f64 → f64. Nie ma promocji całkowitych z C: `u8 + u8` zostaje `u8`. Dwa literały całkowite składają się w literał,
|
||||
więc `FLAG_A | FLAG_B` dalej mieści się w `u64` albo `u32`.
|
||||
|
||||
### Konwersje jawne: `convert()`
|
||||
|
||||
|
|
|
|||
|
|
@ -342,7 +342,7 @@ import ui/przycisk as p // inna nazwa: p.rysuj()
|
|||
| `union U` | `U`: `U u`, `u.pole`, `U(pole: v)`, przez wskaźnik do C (nie przez wartość) |
|
||||
| `#define N 4`, `"tekst"`, `(1u << 3)`, `((Uint64)2)` | stałe (bez makr-funkcji) |
|
||||
|
||||
Wynik `char *` z funkcji C to od razu `str`; struktury przez wartość działają na każdym systemie (System V, Windows x64, ARM64).
|
||||
Wynik `char *` z funkcji C to od razu `str`; struktury przez wartość działają w konwencjach System V, Windows x64 i ARM64 Linux (sprawdzone w emulatorach; macOS przez CI).
|
||||
|
||||
---
|
||||
|
||||
|
|
|
|||
Loading…
Reference in a new issue