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.
This commit is contained in:
Nexoniarz 2026-10-25 18:45:21 +01:00
commit 051af1a04e
6 changed files with 284 additions and 34 deletions

View file

@ -21,11 +21,11 @@ fi
pass=0; failed=0; skipped=0
for f in tests/run/*.fch; do
grep -q "^fn main" "$f" || continue
# the bootstrap compiler doesn't do C imports, defer, maps, methods or errors as values
# the bootstrap compiler doesn't do C imports, defer, maps or errors as values
# (checked in the test and in the modules it imports)
files="$f"
for m in $(sed -n 's/^import \([a-z_]*\)$/\1/p' "$f"); do files="$files tests/run/$m.fch"; done
if grep -qE '^import "|^link |defer | or |try |map\[|!\s*\{|^fn [A-Z][A-Za-z0-9_]*\.|for [a-z_]+, ' $files; then
if grep -qE '^import "|^link |defer | or |try |map\[|!\s*\{|for [a-z_]+, ' $files; then
skipped=$((skipped + 1))
continue
fi

View file

@ -0,0 +1,88 @@
struct Counter {
str name
int count
[]int history
}
fn Counter.add(int n) {
self.count += n
self.history.push(n)
}
fn Counter.add_twice(int n) {
self.add(n) // a method calling another method on self
self.add(n)
}
fn Counter.total() -> int {
sum := 0
for x in self.history {
sum += x
}
return sum
}
fn Counter.describe() -> str {
return self.name + ": " + str(self.count) + " " + str(self.history)
}
fn Counter.copy_named(str name) -> Counter {
c := self // a copy of the struct, not the original
c.name = name
return c
}
fn Counter.merge(Counter other) {
for x in other.history {
self.add(x)
}
}
struct Node {
int value
ptr[Node] next
}
fn Node.sum() -> int {
total := self.value
if self.next != null {
total += self.next.sum() // through a pointer
}
return total
}
fn main() {
c := Counter(name: "clicks")
c.add(3)
c.add_twice(2)
print(c.describe(), c.total())
d := c.copy_named("copy")
d.add(10)
print(c.describe())
print(d.describe())
c.merge(c) // the argument lives inside self: the method gets its own copy
print(c.describe())
[]Counter all = [Counter(name: "a"), Counter(name: "b")]
all[1].add(7)
for i in 0..all.len {
all[i].add(i)
}
print(all[0].describe(), "|", all[1].describe())
print(Counter(name: "temp", count: 5).describe())
last := new(Node(3, null))
first := new(Node(1, new(Node(2, last))))
print(first.sum())
p := first.next
p.value = 20
print(first.sum(), p.sum())
free(last)
free(first.next)
free(first)
}

View file

@ -0,0 +1,8 @@
clicks: 7 [3, 2, 2] 7
clicks: 7 [3, 2, 2]
copy: 17 [3, 2, 2, 10]
clicks: 14 [3, 2, 2, 3, 2, 2]
a: 0 [0] | b: 8 [7, 1]
temp: 5 []
6
24 23