FREAKV3 docs freak 0.14.2 (Maverick)

Operators#

> Full precedence table, exact type rules, and the four anime operators V3 really implements.

Precedence#

Loosest binding first. Everything on one row is left-associative.

LevelOperators
1or
2and
3== != < > <= >=
4+ - NAKAMA
5* / %
6 (prefix)not - PLUS ULTRA FINAL FORM TSUNDERE
7 (postfix).field .method() [index] |>

Parentheses group as expected.

examples/operators.fk compilesruns
-- Arithmetic, comparison and logic.
task main() -> void {
    pilot a: int = 17
    pilot b: int = 5

    say word_from_int(a + b)
    say word_from_int(a - b)
    say word_from_int(a * b)
    say word_from_int(a / b)
    say word_from_int(a % b)

    say word_from_bool(a > b)
    say word_from_bool(a == 17)
    say word_from_bool(a != b)
    say word_from_bool(a <= 17)

    say word_from_bool(a > b and b > 0)
    say word_from_bool(a < b or b > 0)
    say word_from_bool(not false)

    -- Unary minus applies to an expression. A negative *literal*
    -- is written as a subtraction: `0 - 5`.
    pilot neg: int = 0 - 5
    say word_from_int(-neg)
}
Program output
22
12
85
3
2
true
true
true
true
true
true
true
5

Type rules#

The checker is strict — these are the exact rules, not approximations.

OperatorAcceptsProduces
+both numeric (int/num), or both wordnum if either side is num, else int; word for word+word
- * /both numericnum if either side is num, else int
%**both int**int
NAKAMA**both int**int
and or**both bool**bool
== !=equality-compatible typesbool
< > <= >=both numericbool
notboolbool
- (prefix)numericsame as operand
PLUS ULTRA FINAL FORM TSUNDERE**int only**int

Two consequences worth internalising:

  • **% is integer-only.** 7.5 % 2.0 is a type error, not a float remainder.
  • **and / or do not coerce.** There is no truthiness. if count and flag is an error unless count is already bool.

+ is the only overloaded operator: numeric addition and word concatenation.

FREAK
say "Muv" + "-" + "Luv"
say word_from_int(2 + 3)
Not in V3

** (exponent) does not exist — you get expected ',', found '**'. Use math::pow(base, exp) for num, or std_pow(base, exp) for int.

Negative numbers#

There is no negative literal. -5 is unary minus applied to 5. In an initialiser position, write the subtraction the compiler's own source uses:

FREAK
pilot below: int = 0 - 5
say word_from_int(-below)

The anime operators#

Four of the bible's anime operators are implemented. Their V3 semantics are not what the specification describes — the specification defines emotional scaling formulas; V3 implements simple integer arithmetic.

examples/anime_operators.fk compilesruns
-- The anime operators that V3 actually implements.
-- The three unary forms are PREFIX and accept `int` only.
task main() -> void {
    pilot base: int = 6

    say word_from_int(FINAL FORM base)    -- base * base
    say word_from_int(PLUS ULTRA base)    -- base * 2
    say word_from_int(TSUNDERE base)      -- 0 - base

    -- NAKAMA is infix, at the same precedence as + and -.
    say word_from_int(3 NAKAMA 4)
}
Program output
36
12
-6
8
OperatorFormV3 loweringBible says
FINAL FORMprefix, intx * xpostfix base FINAL FORM, plus a 5-second build pause
PLUS ULTRAprefix, intx * 2infix base PLUS ULTRA emotionbase * (1 + e²)
TSUNDEREprefix, int0 - xpostfix; !x for bool, -x for num
NAKAMAinfix, inta + ba + b + (a * b * 0.1)
Careful

Position and type both differ from the specification. In V3 all three unary operators are prefix and accept **int only**. base FINAL FORM fails with expected ',', found 'FINAL FORM', and TSUNDERE true fails with operator 'TSUNDERE' does not accept bool.

Keyword matching is case-insensitive, so plus ultra, Plus Ultra and PLUS ULTRA all lex to the same token. Both words must be present — PLUS alone is an ordinary identifier.

The pipe operator#

|> binds at postfix precedence and rewrites a call so the left value becomes its first argument.

examples/pipe.fk compilesruns
-- `|>` feeds the left value in as the FIRST argument of the call on the
-- right, so `x |> f(y)` is exactly `f(x, y)`.
task double(n: int) -> int { give back n * 2 }
task offset(n: int, by: int) -> int { give back n + by }

task main() -> void {
    say word_from_int(5 |> double())
    say word_from_int(5 |> offset(3))
    say word_from_int(5 |> double() |> offset(1))
}
Program output
10
8
11
x |> f()        is  f(x)
x |> f(y)       is  f(x, y)
x |> f() |> g() is  g(f(x))

The right-hand side must be a bare task name followed by an optional argument list. You cannot pipe into a method call, a shape constructor, or a namespaced builtin like math::sqrt.

Postfix forms#

FormMeaning
value.fieldShape field access
value.method(args)Instance method or builtin method call
Shape::method(args)Associated method call
namespace::call(args)Builtin namespace call (math::sqrt, fs::read, …)
word[i]Indexing — **only on word**, yielding a one-character word
value |> task()Pipe

Indexing an array handle with [i] does not work. Arrays use array_get(handle, i) — see Arrays.

Operator overloading#

Writing impl Add for YourShape registers an implementation, and the method is callable by name. V3 does not rewrite the + token to dispatch to it — see Shapes & impl.

examples/operator_overload.fk compilesruns
-- `impl Doctrine for Shape` registers an operator implementation.
-- V3 does not accept a `doctrine` *declaration*, but it does accept
-- this impl form for the built-in operator doctrines, and the method
-- is callable by name.
shape Vec2 {
    x: int
    y: int
}

impl Add for Vec2 {
    task add(self, other: Vec2) -> Vec2 {
        give back Vec2 { x: self.x + other.x, y: self.y + other.y }
    }
}

impl Vec2 {
    task show(self) -> word {
        give back "({self.x}, {self.y})"
    }
}

task main() -> void {
    pilot a: Vec2 = Vec2 { x: 1, y: 2 }
    pilot b: Vec2 = Vec2 { x: 10, y: 20 }
    pilot c: Vec2 = a.add(b)
    say c.show()
}
Program output
(11, 22)

Not implemented#

OperatorStatus
** exponentV4 — use math::pow / std_pow
? error propagationV4
or else fallbackV4
|| as an xm3 branch separatorV4 — lexes as one token but has no grammar
as? downcastV4
*ptr, .read(), .write(), .offset(), .cast<U>()V4
.. rangesV4

Every FREAK snippet on this site was compiled by freak 0.14.2 (Maverick), built from source with a verified self-host fixed point. 45/45 examples compile; regenerate with python tools/verify.py then python tools/build_docs.py.