Commit graph

53 commits

Author SHA1 Message Date
Nexoniarz
c830c780fe "\(x)" in text, test blocks with assert and finch test, a build cache, the chain of calls on runtime errors
- "x is \(x)", "\(speed, 2)" (two digits after the point), also in """ text
- test "name" { ... } blocks; assert(cond) and assert(cond, why); finch test runs each on its own
- the program's object and its C files (link "x.c") are kept in the cache until they or their headers change
- runtime errors show the calls that led there (finch run, finch test, -g, -O0, --trace)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016GzNP6r8dg6WDxUVZy8wjL
2026-10-29 10:59:30 +01:00
Nexoniarz
3ba2dcd5d6 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
2026-10-29 09:52:04 +01:00
Nexoniarz
17863ecf7b docs, Kate and VS Code: const, if as a value, """ text, 1e9, str(x, 2), min/max/abs/clamp, import a/b and as, fs, C unions and macros
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016GzNP6r8dg6WDxUVZy8wjL
2026-10-29 09:40:06 +01:00
Nexoniarz
f2d6480749 const, if as a value, """ text over several lines, min/max/abs/clamp, import a/b and import x as y, the fs module
- const NAME = value (numbers, text, other constants; typed: const f32 G = 9.8), also module.NAME
- x := if c { a } else { b }
- """ ... """: the closing quotes' indentation goes from every line
- min, max, abs, clamp for any numbers, unless your own function has the name
- import ui/button (a module in a folder), import path as p
- fs: read_bytes, write_bytes, exists, is_dir, mkdir (with parents), list, remove_dir, data_dir(app)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016GzNP6r8dg6WDxUVZy8wjL
2026-10-29 09:37:41 +01:00
Nexoniarz
d0666cf788 C import: unions (SDL_Event) and their fields; #defines that are expressions, casts or text; typedef'd structs no function mentions; FLAG_A | FLAG_B fits a u64
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 09:23:29 +01:00
Nexoniarz
6142e47e71 Struct defaults apply inside structs; exit() ends an or-block; 1e9 literals; x * 2.0 stays f32; floats print as the shortest exact text; str(x, digits)
Also frees main's args and the message of a failing main (valgrind was not clean on two tests).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-29 09:14:58 +01:00
Nexoniarz
b24a7845ef Merge embed: export fn, --shared, -I and the two limit fixes were ported to the Finch-written compiler
The C++ sources those commits changed no longer exist on this branch; their tests (early_exit, map_add_while_looping,
shared) are in tests/ and pass.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015f73FesGZGYPkmDvUcj6QX
2026-10-26 00:37:21 +01:00
Nexoniarz
b53e0910d8 The compiler runs on Windows (and has seeds for macOS)
Windows: the compiler made from bootstrap/windows-x86_64.ll runs under Wine, compiles itself to the same IR, builds an
exe of itself, and every test program passes through it. It needed: Windows-sized unsigned long for libclang's unsaved
file, no 'cross' when Windows builds for Windows, --target passed to libclang (libclang.dll assumes MSVC), the MinGW
triple always in the IR, FINCH_LDFLAGS, .exe names and FINCH_LLVM_INCLUDE in bootstrap/build.sh, winseed.sh/winbuild.sh.
macOS: seeds for arm64 and x86-64 made with the 11.3 SDK; IR is accepted by clang, nothing has run on a Mac yet.
CI gets a windows and a macos job. UNTESTED on real Windows/macOS runners.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015f73FesGZGYPkmDvUcj6QX
2026-10-26 00:37:06 +01:00
Nexoniarz
3e45b62812 Enums whose variants hold values
enum Shape { Circle(float), Rect(float, float), Point }; Shape.Circle(2.0) makes one, match names the values
(Circle(r), _ to ignore), exhaustive like plain enums, printing shows Rect(2, 3.5). Underneath it is a struct (tag +
every variant's values), so copying, freeing, methods and valgrind-cleanliness come with it. Also: stray note files removed.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015f73FesGZGYPkmDvUcj6QX
2026-10-26 00:18:53 +01:00
Nexoniarz
dc0334fa0e Programs built by the Finch compiler free their memory
gen.fch never dropped anything (it was the bootstrap compiler); now it does what the C++ one did: owned variables are
dropped when their scope ends (defers interleaved, newest first), return moves a local out, assignments drop the old
value, temporaries nobody keeps are released, values an expression holds are dropped when try/or leave early,
clear/resize/remove/map.clear drop what goes, free() drops the pointee. The compiler itself now frees as it goes.

MEMCHECK=1 tests/run.sh: 108 passed under valgrind with --leak-check=full.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015f73FesGZGYPkmDvUcj6QX
2026-10-25 22:45:39 +01:00
Nexoniarz
837ad45177 The compiler carries its runtime and std inside itself; host module for the system it runs on
src/embedded.fch (made by tools/pack.fch, checked by tests/run.sh) holds runtime/finch_rt.c and std/; when they aren't
beside the binary they're written to the cache folder once. All the sh/cmd specifics of the driver (quoting, temp dir,
mkdir, rm, mv, null device, path separator, cache dir, binary stdio) moved into host.fch / host_windows.fch.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015f73FesGZGYPkmDvUcj6QX
2026-10-25 22:32:02 +01:00
Nexoniarz
a0c54a1252 docs: the engineers' guide describes the compiler written in Finch
Rewritten (EN+PL): architecture, source tree, front end, code generation, C import and ABI, driver, bootstrapping and the
language server. The type, ownership and semantics sections are kept; the C++ function reference is gone (branch
before-bootstrap has that version).

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015f73FesGZGYPkmDvUcj6QX
2026-10-25 21:55:42 +01:00
Nexoniarz
81df9f8c3e Install, CI, seeds and docs for the compiler written in Finch
bootstrap/install.sh and a share/finch lookup for the runtime and std; an ARM64 Linux seed; bootstrap/README.md;
CI builds from the seed on x64 and ARM64 and runs every test on Windows (Wine) and ARM64 (qemu); README, install and
layout sections of the guides (EN+PL) no longer talk about CMake; editors know enum, match and export.

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_015f73FesGZGYPkmDvUcj6QX
2026-10-25 21:53:50 +01:00
Nexoniarz
636eaefe59 finch lsp: the language server, written in Finch
Hover, go to definition, completion (after a dot too: fields, methods, a module's names, an enum's variants,
array/text/map methods), signature help, the outline and errors while typing -- everything the C++ one did,
and the same tests/lsp_test.py passes against it.

It doesn't type-check by itself: for every change it runs  finch index  on the editor's text (--overlay says
which file the text stands in for) and reads what the compiler learned about every name, which is also what
the compiler's own error messages are made of. Half-typed code keeps using the last version that compiled.
src/docs.fch is the one description of the built-ins that hover and completion share.

tests/run.sh runs the LSP test too. 107 passed.
2026-10-25 21:48:11 +01:00
Nexoniarz
b9378050ab The compiler is written in Finch, and nothing else: src/*.fch, built from a seed
boot/ is src/ now. The C++ compiler and CMake are gone from this branch (they are on before-bootstrap).
bootstrap/build.sh builds the compiler from bootstrap/<system>.ll -- the compiler's own LLVM IR -- then builds
it with itself and checks the two come out identical. bootstrap/build.sh seed writes the seed anew.

The driver is complete: the runtime is compiled once and kept in ~/.cache/finch; a program's own C files,
.o and .a files and frameworks link along; a linker failure is read and answered with  link "lib"  or the
library that is missing. The old tests/fail diagnostics are all in again (a missing import, a str compared with
null, 'write just the library's name', a map key that is a float, non-ASCII names, ...).

tests/run.sh is the one test runner: programs, refusals, -g builds and the shared library. 106 passed.
2026-10-25 21:42:17 +01:00
Nexoniarz
750eca3e85 --target: windows, linux, arm64, macos or a triple, in the compiler written in Finch
Targets, the target's C compiler (FINCH_CC) for linking, C import for the target (--target to libclang, its
headers), the AAPCS64 and Microsoft x64 ways of passing structs by value (and the System V one),
dllexport for libraries on Windows, .exe names, and running the program through wine or qemu-aarch64.
std/ gets time_windows.fch and proc_windows.fch: a module has a version per system (name_windows.fch,
name_macos.fch, name_linux.fch) that wins over name.fch. stdin, stdout and stderr work where C makes them macros.

Run for real: all 27 programs under tests/run and tests/new pass on ARM64 Linux under qemu and on Windows
under Wine (MinGW), structs by value and callbacks included. macOS is only checked as far as clang accepts the
IR; there is no emulator for it here.
2026-10-25 21:33:19 +01:00
Nexoniarz
8c3b5b15b9 -g: debug info, in the compiler written in Finch
DWARF as LLVM metadata: a compile unit, a subprogram per function, a location on every call, a variable
for each local and parameter with types a debugger can open (structs with their fields, arrays and text
as ptr/len/cap, maps, enums with their variants, pointers, fixed arrays). Methods show self.

Use it with -O0, as the docs say: the optimizer inlines the program into main, which has no debug info.
boot.sh builds ten programs with -g -O0 and checks they still behave. 51 passed.
2026-10-25 21:08:13 +01:00
Nexoniarz
dd9cbe7611 export fn and finch build --shared, in the compiler written in Finch; FINCH_PATH, FINCH_RT, FINCH_CC
export fn name(...) is a C function of a library; build --shared makes lib<name>.so with no main and a
finch_module_on_fatal(handler) the host can take runtime errors over with. Ported from the embed work (the
runtime, its test and the docs are that work's; the compiler side is new).

The driver reads FINCH_PATH (more module folders), FINCH_RT (the runtime's file) and FINCH_CC (the clang).
tests/boot.sh also runs tests/shared.sh with the compiler under test. 41 passed.
2026-10-25 21:03:05 +01:00
Nexoniarz
94e41484dd docs: enums, match, generics and the standard library (English and Polish) 2026-10-25 20:59:38 +01:00
Nexoniarz
ea6d2a57e5 a standard library in Finch: path, time, proc, json
import json   import path   import time   import proc  -- found in std/ after the program's own files,
so a program's own json.fch always wins.

path: join, base, dir, ext, stem, parts, clean, is_abs.
time: now, millis, sleep, date, local, format, days_in_month (clock_gettime, strftime through C import).
proc: run, output (an error with the command's output when it fails), env, pid, cwd.
json: parse (errors with line and column), stringify, pretty, new_*, get/at/set/push/has/names and
str_or/int_or/float_or/bool_or; \u escapes with surrogate pairs.

The C importer now leaves a plain (non-const) char * parameter a ptr[char], a buffer C writes into;
only const char * is text going in. str(ptr) and str([]u8) are in the self-hosted compiler.

boot.sh: 40 passed, 0 failed.
2026-10-25 20:58:26 +01:00
Nexoniarz
04eb0cce55 generics (in the compiler written in Finch)
fn max[T](T a, T b) -> T      struct Stack[T] { []T items }      fn Stack[T].push(T x)

The type is worked out from the arguments (max(3, 4), first([1, 2])) and written out
where it cannot be: max[float](1, 2.5), Stack[int](), Pair[str, int](...). Each use makes
its own copy, so a generic costs nothing at run time. Several parameters
(Pair[A, B]), nesting (Stack[Pair[int, str]]), methods, and printing (Stack[int](items: ...))
work. An error inside a generic says which version it was building.

boot.sh: 37 passed, 0 failed (stage 2 and 3 identical).
2026-10-25 20:53:13 +01:00
Nexoniarz
609ceffe58 enums and match (in the compiler written in Finch)
enum Color { Red, Green, Blue }   enum Status { Ok = 200, NotFound = 404 }

Color.Red, Color(n) (checked), int(c), == and != only, printed by name, usable as
map keys and struct fields, with methods (fn Color.next()).

match value { Red, Green -> ... Blue -> ... else -> ... } as a statement, or as an
expression that gives a value. Works on enums, whole numbers, chars, text and bools;
a match on an enum has to handle every variant or end with else, and says which are
missing. A bare variant name (Red) is enough inside a match on an enum.

Only the self-hosted compiler has them; tests/new holds their tests, tests/run stays what
the C++ compiler also runs. boot.sh: 31 passed.
2026-10-25 20:49:04 +01:00
Nexoniarz
a5ba4bc8f0 boot: finch run, version, -O0, -l, -I; clear errors for -g and --target
The self-hosted driver now has the everyday commands. -g (debug info), --target
(Windows, ARM64, macOS) and lsp are still only in the C++ compiler, and say so.
2026-10-25 19:49:04 +01:00
Nexoniarz
04d5486477 boot: structs by value (System V), addr(fn) callbacks -- the compiler builds itself
C structs travel as C passes them: up to 16 bytes in INTEGER/SSE registers per eightbyte,
bigger ones byval and through sret, out-of-registers structs on the stack. addr(fn) makes a
C-callable thunk that rebuilds the arguments. With those, the self-hosted compiler can
compile boot/cimport.fch, which calls libclang with CXCursor and CXString by value and gives
it callbacks -- so it compiles itself.

boot.sh: stage 2 and stage 3 are identical (57904 lines of IR); 22 passed, 0 failed,
0 skipped. Only x86-64 System V so far; Windows and ARM64 conventions are still in C++.
2026-10-25 19:47:20 +01:00
Nexoniarz
13ef63a586 boot: C import (import "x.h", link, C functions, constants, globals, .ptr, ptr(x))
The self-hosted compiler reads headers with boot/cimport.fch and compiles calls to C
functions (variadics, char* as str, C's default promotions), enum and #define
constants, extern variables like stdout, C structs laid out as C laid them (padding
and fixed arrays, by pointer), .ptr of a str or array, ptr(x) and int(ptr). link
"lib" asks pkg-config, link "x.c" compiles the file along.

cimport and c_pointers pass. Not yet: structs by value (the calling convention) and
addr(fn) for C callbacks, which is also what stops it building itself.

boot.sh now says so when stage 2 can't be made and runs the tests on stage 1.
2026-10-25 19:44:58 +01:00
Nexoniarz
f71ae8b1ef boot: cimport.fch, the C header importer written in Finch on libclang
Reads functions (with variadics and why one is unsupported), enum and #define
constants, extern variables and structs with their layout, the same as
src/cimport.cpp. It calls libclang through Finch's own C import, so compiling
it is what the bootstrap will have to do. Checked with the C++ compiler:
stdio.h gives 90 functions and 347 constants; EOF is -1, stdout is ptr[C.FILE].
2026-10-25 19:40:50 +01:00
Nexoniarz
e4ad3540f1 README: say what the self-hosted compiler does and does not do yet 2026-10-25 19:13:46 +01:00
Nexoniarz
083d66c82b boot: maps, for k, v in, for i, x in
map[K]V, [:] and ["a": 1] literals, m[k] reads and writes (m[k] += 1 starts from
zero), has/get/remove/clear/keys/values, .len, copy and printing, and a loop over
a map that stops with an error when it adds keys. for i, x in list gives the
index too.

boot.sh: 17 passed, 0 failed, 5 skipped (all five import C).
2026-10-25 19:13:46 +01:00
Nexoniarz
a5f417100d boot: errors as values (-> T!, error(), try, or, fallible builtins and main)
A function that can fail returns { ok, value, message }. return error(...) makes
the failure; try passes it on after running the defers; 'or <value>' and
'or { ... err ... }' handle it. int(text), float(text), read_file, write_file
and delete_file report failure to an enclosing or/try instead of stopping the
program. fn main() -> ! prints the error and exits with 1.

boot.sh: 15 passed, 0 failed, 7 skipped.
2026-10-25 19:13:46 +01:00
Nexoniarz
84693aa655 boot: defer, str.bytes()
defer runs when its scope ends and before return, break and continue leave it,
newest first, and sees only the variables declared before it. Not allowed
inside a defer: defer, return, break, continue.

boot.sh: 14 passed, 0 failed, 8 skipped.
2026-10-25 19:13:46 +01:00
Nexoniarz
051af1a04e boot: methods (fn T.m, self by address, mutation analysis), str() of any value
Methods are functions whose first parameter is the receiver's address; a method
that changes self can't be called on a temporary or a read-only value, and
calling one on a variable keeps a parameter from being borrowed. An argument
that lives inside the receiver is copied (c.merge(c)). str(x) and print of
arrays and structs go through one formatter, as in the C++ compiler.

boot.sh: 12 passed, 0 failed, 10 skipped.
2026-10-25 19:13:46 +01:00
Nexoniarz
873b52565d boot: sized numbers (i8..u64, f32), conversions, unsigned arithmetic
The self-hosted compiler now has the numeric types the C++ one has: int and
float stay the i64 and f64 defaults, the others lower to their LLVM sizes;
literals adapt to the other operand if they fit, smaller types widen into
bigger ones, signed and unsigned mixing is refused, division and shifts and
comparisons pick their signedness, and u8(x), f32(x), bool(x) convert.

boot.sh: 11 passed, 0 failed, 10 skipped (was 9 / 12).
2026-10-25 19:13:46 +01:00
Nexoniarz
393327b353 Fix the two known limits: adding map keys while looping over the map is a runtime error; temporaries held by an expression are freed when try / or-blocks leave early. err usable after or, inner err shadows outer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-25 19:13:46 +01:00
Nexoniarz
5f2ba99f2d -I <dir>: look for imported C headers there too (an SDK's headers)
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:20:42 +02:00
Nexoniarz
68637a35a7 export fn and finch build --shared: libraries a C program loads (game scripts)
export fn name(...) is a C function by that name (numbers, bool, char, pointers in and out).
--shared builds lib<name>.so / <name>.dll with no main. finch_module_on_fatal(handler) lets the
host take runtime errors over (longjmp out) instead of the process exiting.
tests/shared.sh: a C host loads one, calls it and survives an index error.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-11 02:14:09 +02:00
Nexoniarz
ca1d938087
Delete OpenGL.fn 2026-10-09 10:10:47 +02:00
Nexoniarz
f9838dfe03 Fix the two known limits: adding map keys while looping over the map is a runtime error; temporaries held by an expression are freed when try / or-blocks leave early. err usable after or, inner err shadows outer.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 01:26:53 +02:00
Nexoniarz
b872be3176 Finch 2.4.0: methods, maps, errors as values; str() of any value; macOS and ARM64 docs; Kate support v2.4.0
- fn Struct.method(...) with self by reference, also on C structs
- map[K]V: insertion-ordered hash maps, literals, m[k] += 1, has/get/remove/keys/values
- -> T! / -> !, return error(...), or <value>, or { err }, try; fallible int/float/read_file/write_file/delete_file
- for i, x in list / for k, v in map
- print and str() share one text formatter
- LSP: method and map completion, method signatures; grammar and snippets for VS Code and Kate
- tests: 74 (methods, errors, maps + 11 failure cases); docs at all three levels, en and pl

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 01:11:12 +02:00
Nexoniarz
fd86eb885c CMake: enable C (Homebrew LLVM's config needs it); Kate: highlighting, language server setup, install script
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:36:44 +02:00
Nexoniarz
484c14fe77 ARM64 and macOS: AAPCS64 struct passing, aarch64/macos targets, Apple frameworks and ld messages, tests/cross.sh, CI on ARM64 Linux and macOS
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-09 00:34:00 +02:00
Nexoniarz
013b95d584 docs: version 2.3.0 v2.3.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:05:12 +02:00
Nexoniarz
d2693c5bac Finch 2.3.0: docs for Windows, LSP and VS Code; cheat sheets (en, pl); portable LSP test
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:05:02 +02:00
Nexoniarz
eaacf70e42 VS Code extension (highlighting, snippets, language client, Run/Build); LF line endings; LNK1181
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 22:01:13 +02:00
Nexoniarz
5972d805aa Language server (finch lsp): diagnostics, hover, definition, completion, symbols, signature help; MSVC fix
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:58:01 +02:00
Nexoniarz
ae363b1fa3 CI: point LLVM's DIA SDK at the installed Visual Studio; semantic index for the language server
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 21:53:42 +02:00
Nexoniarz
84cbbb3e16 Windows support (wip): target layer, Microsoft x64 ABI, portable runtime, CI
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 20:46:51 +02:00
Nexoniarz
8497251dc5 OpenGL and Vulkan examples; ptr(int)/int(ptr); trailing commas in calls; drop .fn hint v2.2.0
- examples/opengl.fch: OpenGL 3.3 core, shaders, VAO/VBO, a spinning triangle (checked offscreen)
- examples/vulkan.fch: instance, GPUs with properties/memory/queues, logical device and queue
- ptr(n) and int(p) conversions for C APIs that pass offsets as pointers
- .ptr works on string literals; a comma after the last call argument is allowed
- a missing header included by an imported header is now named in the error
- the old .fn extension hint is gone (Finch is new, there are no old files)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:37:34 +02:00
Nexoniarz
f897fb3140 Rename the Finch file extension from .fn to .fch v2.1.0
.fn is already used by other tools (e.g. Fennel). Modules are now looked up as name.fch;
a leftover name.fn gets a clear message telling you to rename it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:27:42 +02:00
Nexoniarz
01c5badc3e Branding: logo (light/dark), bird mark, icon, social preview, brand guide; logo in READMEs v2.0.0
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:24:31 +02:00
Nexoniarz
3e55da2645 Docs for Finch 2.0: beginners, technicians, engineers (en, pl); READMEs; raylib example
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
2026-10-08 19:20:46 +02:00