finch.toml, threads and atomics, finch fmt, C++ files, struct #defines, a struct variable given for its ptr

- finch.toml: name, entry, paths, include, links, libdirs, cflags, ldflags, and [target.windows] etc.;
  finch run / build / test with no file use its entry
- import thread: spawn, join, mutex, cpus; atomic_add/sub/load/store/swap/cas built in
- finch fmt [--check]: indentation by { }, trailing spaces, empty lines; also as LSP formatting
- link "x.cpp" (or in finch.toml): built with the C++ compiler, which then links (FINCH_CXX)
- #define RAYWHITE (Color){ 245, 245, 245, 255 } imports as a Color
- push(body) where push takes ptr[Body]: the same as push(addr(body))
- --target android (NDK clang from ANDROID_NDK_HOME, -llog)

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_016GzNP6r8dg6WDxUVZy8wjL
This commit is contained in:
Nexoniarz 2026-10-29 11:17:10 +01:00
commit d428498efd
40 changed files with 1398 additions and 18 deletions

24
tests/tool/fmt_in.fch Normal file
View file

@ -0,0 +1,24 @@
struct P {
int x
int y
}
fn main() {
p := P(x: 1,
y: 2)
msg := """
a {
b
"""
if p.x > 0 {
print("{ \(p.x) }") // } not counted
} else {
print(msg)
}
s := "a" +
"b"
print(s)
}

21
tests/tool/fmt_out.fch Normal file
View file

@ -0,0 +1,21 @@
struct P {
int x
int y
}
fn main() {
p := P(x: 1,
y: 2)
msg := """
a {
b
"""
if p.x > 0 {
print("{ \(p.x) }") // } not counted
} else {
print(msg)
}
s := "a" +
"b"
print(s)
}

View file

@ -0,0 +1 @@
hello world 42

View file

@ -0,0 +1,14 @@
# a project: finch run / build / test here need no file and no flags
name = "mygame"
entry = "src/main.fch"
paths = ["src"]
include = ["native"]
links = [
"native/glue.cpp", # C++, built with the C++ compiler
]
cflags = ["-DGLUE_BASE=40"]
[target.linux]
links = ["m"]
[target.windows]
links = ["ws2_32"]

View file

@ -0,0 +1,9 @@
// C++ behind a C header: extern "C" gives the function a name C (and Finch) can call
#include "glue.h"
#include <numeric>
#include <vector>
extern "C" int glue_answer(void) {
std::vector<int> v = {1, 1};
return GLUE_BASE + std::accumulate(v.begin(), v.end(), 0);
}

View file

@ -0,0 +1,7 @@
#ifdef __cplusplus
extern "C" {
#endif
int glue_answer(void);
#ifdef __cplusplus
}
#endif

View file

@ -0,0 +1,3 @@
fn hello() -> str {
return "world"
}

View file

@ -0,0 +1,6 @@
import "glue.h"
import game/world
fn main() {
print("hello \(world.hello()) \(glue_answer())")
}

View file

@ -0,0 +1,30 @@
// finch test: each test "..." block runs on its own; a failed assert or a runtime error fails only that one
fn add(int a, int b) -> int {
return a + b
}
fn second([]int xs) -> int {
return xs[1]
}
test "add works" {
assert(add(2, 3) == 5)
assert(add(-1, 1) == 0, "zero")
}
test "a failing assert" {
x := add(1, 2)
assert(x == 4, "x is \(x), not 4")
}
test "a runtime error fails only this test" {
print(second([1]))
}
test "still runs after the others" {
assert("\(1.5, 2) and \(add(1, 1))" == "1.50 and 2")
}
fn main() {
print("main is not run by finch test")
}

View file

@ -0,0 +1,8 @@
ok add works
FAIL a failing assert
test_blocks.fch:17: runtime error: assert failed: x is 3, not 4
FAIL a runtime error fails only this test
test_blocks.fch:7: runtime error: index 1 is out of range (the length is 1)
ok still runs after the others
2 passed, 2 failed

16
tests/tool/trace.fch Normal file
View file

@ -0,0 +1,16 @@
struct Enemy {
[]int path
}
fn Enemy.next(int i) -> int {
return self.path[i]
}
fn step(Enemy e) -> int {
return e.next(3)
}
fn main() {
e := Enemy(path: [1, 2])
print(step(e))
}

4
tests/tool/trace.out Normal file
View file

@ -0,0 +1,4 @@
trace.fch:6: runtime error: index 3 is out of range (the length is 2)
in Enemy.next (trace.fch:6)
in step (trace.fch:10)
in main (trace.fch:15)