Finch/docs/en/cheatsheet.md

11 KiB
Raw Blame History

Finch Cheat Sheet

Everything in Finch on one page. For explanations, see the guides.

🇵🇱 Polska wersja: sciaga.md


The finch command

Command Does
finch run file.fch [args…] compile and run (args go to the program)
finch build file.fch [-o name] make a program (name.exe on Windows)
finch ir file.fch print the LLVM IR
finch lsp the language server (editors use it)
finch version version
-l lib link a C library (like link "lib")
--target windows / linux / arm64 / macos / triple build for another system
-g debug info (gdb, lldb, Visual Studio)
-O0 no optimizations

Environment: FINCH_PATH (folders with modules), FINCH_CC / CC (the C compiler that links).


A file

import "stdio.h"        // a C header
import shapes           // a Finch module: shapes.fch
link "m"                // a C library, or "mine.c" / ".o" / ".a"

struct Point {
    int x
    int y = 0           // default value
}

fn main() {
    print("Hello")
}

main can be fn main(), fn main() -> int (exit code) or fn main([]str args). One statement per line, no semicolons, { on the same line, no brackets around conditions.


Variables

Code Meaning
x := 5 new variable, type inferred
int x = 5 new variable, type written
int x zero / "" / [] / null / the struct's defaults
x = 7 assign
x += 1 -= *= /= %= update

Types

Type Example
int (= i64) 42, -7, 0xFF, 1_000_000
float (= f64) 3.14
bool true, false
char 'A', '\n'
str "text\t\"quoted\""
i8 i16 i32 i64 signed, sized
u8 u16 u32 u64 unsigned, sized
f32 f64 floats
[]T array: [1, 2, 3], []str names
map[K]V map: ["a": 1], map[str]int counts, [:]
ptr[T], ptr pointer, untyped pointer
Name / module.Name a struct

Escapes: \n \t \r \0 \\ \" \'.


Operators

Priority Operators
5 * / % << >> &
4 + - | ^ (+ also joins text)
3 == != < <= > >=
2 &&
1 ||
unary -x !x ~x

x & 1 == 0 means (x & 1) == 0.


Control flow

if a > b { … } else if a == b { … } else { … }
while x > 0 { … }
for i in 0..10 { … }          // 0 … 9
for item in list { … }        // every element (or char of a str)
for i, item in list { … }     // with its index
for key, value in m { … }     // every map entry, in insertion order
break     continue     return value
defer cleanup()               // runs when the block ends

Functions

fn add(int a, int b) -> int {
    return a + b
}
fn greet(str name) {          // no result
    print("Hi", name)
}

Parameters behave like copies. Order in the file doesn't matter. A comma after the last argument is allowed.


Methods

fn Point.move(int dx, int dy) {   // self is the Point it's called on (not a copy)
    self.x += dx
    self.y += dy
}
fn Point.dist() -> float { … }

p.move(1, 2)       list[0].move(1, 1)       ptr_to_point.move(0, 1)

Also on structs from C: fn Vector2.length() -> f32 { … }.


Errors as values

fn parse(str s) -> int! {         // ! = can fail
    if s.len == 0 {
        return error("empty")
    }
    return int(s) or { return error("not a number: " + s) }
}
fn save(str p, str t) -> ! {      // can fail, no result
    try write_file(p, t)
}
Code On failure
x := parse(s) or 0 use 0
x := parse(s) or { print(err); return } run the block (err: the message)
x := try parse(s) fail the current function too
fn main() -> ! a failure prints error: …, exit code 1

Fallible built-ins: int(s), float(s), read_file, write_file, delete_file.


Structs

Code Meaning
struct P { … } define (one field per line, = default optional)
P(1, 2) create, all fields in order
P(x: 1) create by name, the rest default/zero
p.x, p.x = 5 read, change a field
b := a a full copy

Arrays []T

Code Gives
a.len number of elements
a[i], a[i] = x element (checked)
a.push(x) add at the end
a.pop() remove the last, give it back
a.insert(i, x) put at position i
a.remove(i) remove position i, give it back
a.clear() empty it
a.resize(n) length n (new elements are zero)
a.find(x) index or -1
a.contains(x) bool
a.sort() sort (numbers, chars, str)
a.reverse() reverse
a.slice(s, e) new array of s … e-1
a.join(sep) []str → one str
a.ptr address of the first element (for C)

Maps map[K]V

Code Gives
m := ["a": 1, "b": 2] a map (keys: numbers, char, bool, str)
m[k] value (missing key: the program stops)
m[k] = v add / replace
m[k] += 1, m[k].push(x) a missing key starts at the default (0, [], …)
m.len number of keys
m.has(k) bool
m.get(k, default) value or default
m.remove(k) bool: was it there
m.clear() empty it
m.keys(), m.values() arrays, insertion order

Text str

Code Gives
s.len bytes
s[i], s[i] = 'x' char
a + b joined text
s.sub(a, b) part a … b-1
s.find(t) position or -1
s.contains(t) bool
s.starts_with(t), s.ends_with(t) bool
s.split(sep) []str
s.trim() no spaces at the ends
s.upper(), s.lower() A–Z / a–z
s.replace(a, b) every a → b
s.repeat(n) n times
s.bytes() []u8
s.ptr ptr[char] (for C)
== != < > compare

Conversions

Code Result
int(3.9) 3
int("42") 42 (stops the program if it isn't a number)
int('A') 65
float(7), float("2.5") 7, 2.5
u8(300) 44 (keeps the low bits)
char(66) 'B'
bool(0) false
str(42), str(1.5), str(true), str('c') text
str([1, 2]), str(m), str(point) the same text print shows
int("x") or 0, float(s) or 0.0 a number, or the fallback
str(bytes) []u8 → text
str(p) C char* → text
ptr(p), ptr(16) untyped pointer, from a pointer or a number
int(p) pointer → address

Automatic only when nothing is lost: smaller → bigger number, any int → float, f32 → f64.


Built-in functions

Function Does
print(a, b, …) print, spaces between, newline at the end
input(), input("Question? ") read a line
read_file(path) file → str
write_file(path, text) str → file, true if it worked
file_exists(path) bool
delete_file(path) bool
shell(command) run a command, its exit code
exit(code) stop the program now
error(message) return error("…") in a -> T! function
addr(x) pointer to x; addr(fn) = C callback
new(value) value on the heap → ptr[T]
free(p) give it back

Pointers

Finch C
ptr[int] p int *p
addr(x) &x
p.value *p
p.field p->field
p[i] p[i]
null NULL
ptr void *

Memory

  • Arrays, text and structs free themselves at the end of their block. No free needed.
  • b := a copies; a call's result moves; return x moves.
  • new(...) + free(...) (often with defer) for linked lists, trees, sharing.
  • C memory: C's own functions (malloc / free, fclose, …).

Modules

import shapes            // shapes.fch next to this file (or in FINCH_PATH)
shapes.area(b)           // its functions
shapes.Box(2, 3)         // its structs
shapes.Box other         // in declarations

C

Code Meaning
import "x.h" functions, structs, enums, #define numbers, globals
link "name" libname.so / name.lib (pkg-config first)
link "file.c" compile your own C file
addr(myFn) pass a Finch function as a callback
C type Finch
int / long long / unsigned i32 / i64 / u32 (by size)
float / double f32 / f64
char * (parameter, result) str
char * (field, behind a pointer) ptr[char]
struct X X
T * ptr[T]
void *, handles ptr
T x[N] (in a struct) [N]T

Runtime errors (the program stops with file and line)

Message Cause
division by zero / or % by 0
index 5 is out of range (the length is 3) a[5]
pop() on an empty array
used .value on a null pointer .value / .field / [i] through null
can't turn "x" into int int("x")
can't read the file "…" read_file (without or)
the key "x" is not in the map m["x"]

Editors

Kate: editors/kate/install.sh, then enable the LSP Client plugin; run with Build & Run → finch run %f. Any LSP editor: finch lsp.

VS Code (extension "Finch")

Key / action Does
▶ / Ctrl+F5 run the file
Finch: Build This File build; errors go to Problems
F12 go to definition
hover type / signature / docs
Ctrl+Space completion (after .: fields, methods, module members)
Ctrl+Shift+O functions and structs in the file
main, fn, fnr, fnf, method, struct, for, foreach, forkv, map, orb, if, ife, while, input + Tab snippets
setting finch.path where finch / finch.exe is

Enums and match

enum Color { Red, Green, Blue }          enum Status { Ok = 200, NotFound = 404 }
c := Color.Green    int(c)    Color(2)    c == Color.Red      // == and != only; Color(7) is an error
fn Color.next() -> Color { ... }                               // methods work

match c { Red -> ...   Green, Blue -> { ... }   else -> ... }  // bare variant names; every variant or else
x := match n { 1, 2 -> "few"   else -> "many" }                // an expression: every arm the same type

Generics

fn max[T](T a, T b) -> T { ... }     max(3, 9)     max[float](1, 2.5)    // worked out, or written out
struct Stack[T] { []T items }        fn Stack[T].push(T x) { ... }       // the type goes with it:
s := Stack[int]()     Stack[int] t     Pair[str, int]("age", 31)         //   never just Stack()

Standard library (import name; your own file of that name wins)

path join(a, b) base(p) dir(p) ext(p) stem(p) parts(p) clean(p) is_abs(p)
time now() millis() sleep(ms) date(t) local(t) format(t, fmt) days_in_month(y, m)
proc run(cmd) output(cmd) (fails with its output) env(name, fallback) pid() cwd()
json parse(text) stringify(v) pretty(v) new_text/number/bool/null/list/object v.get(k) v.at(i) v.set(k, x) v.push(x) v.has(k) v.str_or(d) v.int_or(d) v.float_or(d) v.bool_or(d)

Keywords

fn return if else while for in break continue true false null import link struct enum match defer or try (and self inside methods)