A tour of ik¶
This page walks the core of the language by example. Each snippet is valid ik
that you could drop inside an @main body. For the precise rules behind every
construct, follow the links into the Language Reference.
Variables and storage spaces¶
Every variable declaration starts with a storage space, a mutability,
the $ name, a type, and an initialiser:
ram mut $counter: u8 = 0 # mutable, lives in SRAM
ram imut $limit: u8 = 100 # immutable (write-once)
eeprom mut $boots: u16 = 0 # persists across power cycles
flash imut $table: u8[4] = 0 # read-only, stored in program memory
ramis SRAM,eepromis the on-chip EEPROM,flashis program memory. The space is part of the variable’s identity, not a hint.mutis read/write;imutis write-once. There is no separateconstfor locals —imutis the immutable form. (constis reserved for top-level register aliases; see below.)
See Memory model for the full memory model.
Assignment goes left to right¶
The defining syntactic choice of ik: assignment is an arrow that points at the destination.
42 -> $counter # store 42 into $counter
$counter -> $other # copy $counter into $other
There are compound forms that read-modify-write the destination:
5 ->+ $counter # $counter = $counter + 5
1 ->- $counter # $counter = $counter - 1
0xF0 ->& $flags # $flags &= 0xF0
0x01 ->| $flags # $flags |= 0x01
0x80 ->^ $flags # $flags ^= 0x80
Types¶
The primitive types are sized integers, a boolean, a character, and two fixed-point types:
Type |
Meaning |
|---|---|
|
unsigned 8-bit |
|
unsigned 16-bit |
|
signed 8-bit |
|
signed 16-bit |
|
boolean ( |
|
character / byte |
|
Q4.4 fixed-point (8-bit) |
|
Q8.8 fixed-point (16-bit) |
|
no value (function return only) |
There are no floating-point types; fractional literals such as 3.14 are
resolved at compile time into the fixed-point r8/r16 representation. The
math library operates entirely in r16 (Q8.8). See Type system.
Operators¶
ik has the usual set of operators with conventional precedence:
$a + $b $a - $b $a * $b $a / $b $a % $b
$a & $b $a | $b $a ^ $b # bitwise
$a && $b $a || $b # logical, short-circuit
$a == $b $a != $b
$a < $b $a <= $b $a > $b $a >= $b
!$a ~$a -$a # unary not / bitnot / negate
&$a *$p # address-of / dereference
Literals can be decimal (42), hexadecimal (0x2A), boolean (true /
false), or character ('A', '\n'). See
Expressions.
Conditionals¶
The condition keyword is ?. There is no if/else keyword — ?
takes a block, and an optional : introduces the else block:
? $counter > 100 {
0 -> $counter
} : {
1 ->+ $counter
}
For multi-way dispatch on a single value, use switch with -> arrows and
a * wildcard default:
switch $cmd {
1 -> { @start() }
2 -> { @stop() }
* -> { @ignore() } # default
}
Loops¶
Two loop forms cover the embedded cases:
loop * { # infinite loop
@poll()
}
loop 0..8 -> $i { # counted loop, $i takes 0,1,...,7
@shift_out($i)
}
The range loop binds its induction variable after the -> arrow, consistent
with the rest of the language. The range is half-open: 0..8 visits 0 through
7. See Statements.
Functions¶
Functions are declared with the @ sigil. Parameters and the return type are
optional:
@square($x: u16) -> u16 {
return $x * $x
}
@greet { # no parameters, no return -> parentheses optional
@uart_println()
}
@main {
ram imut $n: u16 = @square(7) # call with @name(args)
}
@main is just a function the compiler treats as the entry point. See
Functions.
Arrays¶
Arrays carry a compile-time length in brackets and are indexed in the usual way. The single initialiser fills every element:
ram mut $buf: u8[5] = 0 # five zeroed bytes
10 -> $buf[0]
20 -> $buf[1]
ram imut $first: u8 = $buf[0]
ram imut $i: u8 = 1
$buf[$i] -> $first # dynamic indexing is allowed
Pointers and strings¶
Pointers name the space they point into. Dereference with * and take an
address with &:
ram mut $value: u8 = 7
ram ptr u8 $p = &$value # pointer into SRAM
*$p -> $value # write through the pointer
ram imut $got: u8 = *$p # read through the pointer
Strings are NUL-terminated byte arrays. ram str lives in SRAM, flash str
is stored in program memory:
ram str $msg = "hello"
ram imut $len: u16 = @strlen($msg)
See Memory model for pointer/string declaration rules.
Function pointers¶
A function-pointer type is written fn(args) -> ret. Take the address of a
function with &@name and call indirectly with @$var(...):
@double($x: u8) -> u8 { return $x * 2 }
@main {
ram imut $f: fn(u8) -> u8 = &@double
ram imut $r: u8 = @$f(21) # indirect call -> 42
}
This is how callback-driven library functions like @font_stream work. See
Functions.
Talking to hardware¶
Register aliases are declared at top level with const and a % name, then
assigned to like any other location:
const %PORTB: u16 = 0x0025
@main {
0x20 -> %PORTB # write the port
ram imut $pins: u8 = %PORTB # read it back
}
The right-hand-side value is the I/O address for the current target. Most of
the time you let the standard library declare these for you.
Where to go next¶
Using the standard library — using
importand the standard library.Handling interrupts — handling hardware interrupts.
Language Reference — the precise rules for everything above.