Examples
Real programs from the repo, each with the output it really prints.
fn add ['a': int32, 'b': int32] -> int32 {
return 'a' plus 'b';
}
MAIN {
let 'sum' := add[10, 20];
cord::print.useful["sum: ", 'sum', newln];Add8 linesfn loud ['name': str.utf8, 'answer': bool] -> bool {
cord::print.useful["checked ", 'name', newln];
return 'answer';
}
MAIN {
let 'ok' := loud["first", false] and loud["second", true]; # both printand runs both sides18 linesfn loud ['name': str.utf8, 'answer': bool] -> bool {
cord::print.useful["checked ", 'name', newln];
return 'answer';
}
MAIN {
let 'xs' := [3, 5, 8];and.then / or.else19 linesMAIN {
let 'sample': not_std.int24 = -8_000_000;
let 'flags': not_std.uint4 = 9;
let 'big': not_std.int100 = 1_000_000_000_000_000_000;
cord::print.useful['sample', " ", 'flags', " ", 'big', " ", ('flags' plus.wrap 9), newln];
}Any width7 linesMAIN ['argc': int32, 'argv': ptr[ptr[uint8]]] {
cord::print.stored["argc = ", 'argc', newln];
let mut 'i': int32 = 1;
while 'i' < 'argc' {
no_check let 'word' := ptr.read[ptr.at['argv', 'i']];
let mut 'k': int32 = 0;Args24 linesfn show ['b': uint8] { cord::print.useful['b', newln]; }
fn wide ['w': uint32] -> uint32 { return 'w'; }
MAIN {
show[0 minus.wrap 1];
let 'v': uint64 = to.uint64[wide[2 shl 3]];
cord::print.useful['v', " ", wide[not.bit 0], newln];Argument context12 linesbare.never [fn, struct]; # every pub fn and struct in this Neuron: the path is required
pub const 'unit' := 1; # a const takes no mark: its path is always written
pub bare.never module shapes { # everything in this block module
pub fn area ['side': int32] -> int32 {
return 'side' times 'side';
}Bare marks25 linesMAIN {
let 'f': bin32 = 0.1;
let 'h': bin16 = 0.1;
let 'd': bin64 = 0.1;
cord::print.stored['f', newln]; # 0.100000001490116119384765625
cord::print.stored['h', newln]; # 0.0999755859375Bin widths31 linesMAIN {
let 'a': uint8 = 12; # 0000 1100
let 'b': uint8 = 10; # 0000 1010
cord::print.useful['a' and.bit 'b', newln]; # 0000 1000 = 8
cord::print.useful['a' or.bit 'b', newln]; # 0000 1110 = 14
cord::print.useful['a' xor 'b', newln]; # 0000 0110 = 6Bitwise14 linesMAIN {
let 'v': uint32 = 5;
let 'keep': uint32 = 'v' and.bit.wrap (0 minus 1); # -1's bits are all ones: 'v' unchanged
let 'none': uint32 = 'v' and.bit.wrap (1 minus 7); # -6's bits and 5's: 0
let 'flip': uint32 = 'v' xor.wrap (1 minus 7); # 4294967295
cord::print.useful['keep', " ", 'none', " ", 'flip', newln];Bitwise wrap9 linesMAIN {
let 'correct?': bool = true;
let 'wrong?' := not 'correct?';
if 'correct?' and (not 'wrong?') {
cord::print.stored["fine", newln];
}Bools10 linesfn fill ['count': int32] -> list[int32][min 0, max 5] or fail[too_many] {
if 'count' > 5 { fail too_many; }
let mut 'out' := list.empty;
for 'i' from 1 to 'count' by 1 { list.append[lend.mut 'out', 'i' times 'i']; }
return give 'out';
}Bounded21 linesMAIN {
let mut 'small': map[str.utf8[min 1, max 3 bytes], int32[min 0, max 10]][min 0, max 2] = map.empty;
map.set[lend.mut 'small', "ab", 5];
map.set[lend.mut 'small', "cd", 7];
let 'n' := map.length[lend 'small']; # uint64[min 0, max 2]
let 'tiny': int8 = 'n'; # proven by the boundBounded map12 linesMAIN {
let 'a': brain16 = 0.1; # a literal rounds to the nearest: 0.10009765625
let 'b': brain16 = 0.2;
let 'c': brain16 = 'a' plus 'b';
cord::print.stored['a', " ", 'c', newln]; # what is stored
cord::print.useful['a', " ", 'c', newln]; # the shortest text that rounds back to itBrain1616 linesMAIN {
let 'i': int64 = 9223372036854775803;
let 'b' := to.brain16['i'];
let 'd' := to.useful.deci64['b'];
let 'n' := to.int64['d'] otherwise -1;
cord::print.useful['b', " ", 'd', " ", 'n', newln];Brain16 useful large9 linesMAIN {
let 'good': list[uint8] = [104, 195, 169, 108, 108, 111];
let 'bad': list[uint8] = [104, 255, 105];
let 'a' := to.str.utf8['good'] otherwise "?";
let 'b' := to.str.utf8['bad'] otherwise "not UTF-8";
cord::print.stored['a', newln, 'b', newln];Bytes to text10 lineslayout.C enum Key { a = 65 b = 66 escape = 256 }
extern.C fn IsKeyDown ['key': Key] -> bool;
fn name ['k': Key] -> str.utf8 {
match 'k' {
a { return "A"; }
b { return "B"; }C enums19 lineslayout.C enum Key { a = 65 b = 66 escape = 256 }
fn on_key ['code': int32] -> int32 {
let 'k' := to.Key['code'] otherwise { out_of_range { return 0; } };
match 'k' {
a { return 1; }
b { return 2; }C enum convert16 linesincl.C.system["unistd.h", "stdio.h"];
module text { pub.neuron incl.C.system["string.h"]; }
MAIN {
let 'msg' := "hello through C's write";
no_check let 'n' := write[1, lend 'msg', text.strlen[lend 'msg']];
cord::print.useful[newln, 'n', " bytes; BUFSIZ ", 'BUFSIZ', ", EOF ", 'EOF', ", SEEK_END ", 'SEEK_END', newln];C headers15 lineslayout.C struct Rect { w: int32[min 0, max 4096] h: int32[min 0, max 4096] }
extern.C fn DrawRect ['r': Rect];
MAIN {
let 'r' := Rect[w = 640, h = 480];
cord::print.useful['r'.w, "x", 'r'.h, " ", size.of[Rect], newln];
}C struct ranges9 linesincl.C.system["time.h", "stdio.h"];
incl.C["headers/shapes.h"];
MAIN {
let 'b' := buf[size = 42, count = 7];
cord::print.useful["tm is ", size.of[tm], " bytes, buf ", size.of[buf], "; size ", 'b'.size, ", count ", 'b'.count, newln];
}C structs13 linesincl.C["headers/paint.h"];
MAIN {
let 'n': C.long = 40;
let 'c': C.char = -3;
let 'd': C.long_double = 1.5;
cord::print.useful[to.int32[color.BLUE], " ", to.int32[level_t.LOW], " ", 'SEEK_B', newln];C types23 lineslayout.C enum Mode { emacs = 0 vi = 1 }
extern.C fn malloc ['bytes': uint64] -> ptr.mut[Mode];
extern.C mut 'edit_mode': int32;
fn mode_at ['p': ptr[Mode]] -> int32 {
no_check let 'm' := ptr.read['p'] otherwise Mode.emacs;
match 'm' {C variables25 linesextern.C fn qsort ['base': ptr.mut[int32], 'n': uint64, 'size': uint64,
'cmp': fn[ptr[int32], ptr[int32]] -> int32];
fn ascending ['a': ptr[int32], 'b': ptr[int32]] -> int32 {
no_check return ptr.read['a'] minus ptr.read['b']; # C hands pointers to two elements
}
fn descending ['a': ptr[int32], 'b': ptr[int32]] -> int32 {Callbacks19 linescase.any;
const 'Limit' := 3;
struct Point {
X: int32
Y: int32
}Case file18 linesenum Status { empty claimed: str.utf8 locked }
fn label ['s': Status] -> str.utf8 {
let immut 'text' := match 's' {
empty { is "free"; }
claimed 'who' { let immut 'prefix' := "taken by "; is 'prefix' ++ 'who'; }
locked { is "locked"; }is gives a case its value14 linescase.any [fn, var];
case.any enum Mood {
Happy
Grumpy
}
case.exact struct Exact {Case marks23 linescase.any [fn, var];
fn Größe [] -> int32 {
return 7;
}
MAIN {
let 'Café' := GRÖSSE[];Case unicode12 linesMAIN {
let 'a' := `A`;
cord::print.useful[char.code['a'], newln]; # 65 — the number under it
let 'seven' := to.int32[to.str.utf8[`7`]] otherwise -1; # 7 — a digit's value is a text parse
cord::print.useful['seven', newln];
let 'b' := char.point.from_code[66] otherwise `?`;Chars19 linesfn draw ['y': bin16] { cord::print.useful["drawing ", 'y', newln]; }
MAIN {
let 'x': bin32 = 70000.0;
if 'x' > 65_504.0 {
cord::print.stored["too big", newln];
} else {Check tiers25 linesMAIN {
let 'a' := 1; # trailing: from here to the end of the line
let 'b' := 2; #wl this whole line is a comment, including the code before the #
let 'c' := 3;
let 'd' := 4;
let 'e' := 5; #2ld this line and two more downComments12 linesfn fetch [lent 'url': str.utf8] -> str.utf8 { return "page of " ++ 'url'; }
MAIN {
let 'from_a' := channel[str.utf8];
let 'from_b' := channel[str.utf8];
let 'a' := "a.com";
concur with [lend 'from_a', give 'a'] { channel.send[lend 'from_a', fetch[lend 'a']]; }Concurrency16 linesbare.never [fn, struct];
pub const 'max' := 8;
const 'pi': bin64 = 3.141_592_653_589_793;
const 'twice_max' := 'max' times 2;
const 'greeting' := "hello " ++ "world";
pub struct P { x: int32 }Consts15 linesfn g ['p': bool] -> uint8 { return 0; }
MAIN {
let 'x': int64 = 0;
let 'v': uint8 = g[0 > (-1) minus 'x']; # the (-1) minus 'x' is int64 arithmetic, not uint8
let 'w': uint32 = 2 shl 3; # but a bare literal still takes its width from here
cord::print.useful['v', " ", 'w', newln];Context stops at a call9 linesMAIN {
let 'w': uint32 = 3;
let 'b': bool = (5 minus.wrap 'w') > 1; # a uint32 subtraction, 'w' says so, not a bool one
let 'c': bool = 1 < (0 minus.wrap 'w'); # wraps to 4294967293
let 'n': uint64 = 5;
let 'd': bool = 'n' > (0 minus.wrap 1); # but the other side sizes it: 0 minus.wrap 1 wraps in uint64Context stops at a comparison10 linesconst 'shop_name' := "Corner Shop";
const 'points_per_item' := 2; # loyalty points earned for every item bought
const 'low_stock' := 3; # at or below this, an item goes on the reorder list
enum Aisle {
fresh
bakeryCorner shop669 linesMAIN {
for 'i': uint64 from 3 to 1 by -1 { cord::print.useful['i', " "]; }
cord::print.stored[newln];
for 'j': uint64 from 3 to 0 by -1 { cord::print.useful['j', " "]; } # ends at 0: must not underflow
cord::print.stored[newln];
let 'xs' := [10, 20, 30];Countdown11 linesMAIN {
let 'a': deci64 = 0.1;
let 'b': deci64 = 'a' plus 0.2;
cord::print.stored['b', " ", 'b' equal_to 0.3, newln];
let 'price': deci64 = 19.99;
let 'sub': deci64 = 'price' times 3;deci: exact decimals37 linesMAIN {
let 'a': deci64 = 1.00;
cord::print.stored['a' plus (1.5 times 2), " ", 'a' plus 1.5 times 2, newln];
let 'f': bin32 = 0.1;
cord::print.stored[to.useful.deci64['f'], " ", to.stored.deci64['f'], newln];
let mut 'm': map[deci64, int32] = map.empty;deci beside other numbers12 linesstruct Price { amount: deci64 }
enum Pay { cash voucher: deci64 }
MAIN {
let 'p' := Price[amount = 0.45];
let 'v' := Pay.voucher[5.00];
cord::print.useful['p'.amount, " ", 'v', newln];Deci field context9 linesMAIN {
let 't': deci64 = 7.50;
let 'm': deci64 = -7.50;
cord::print.stored['t' mod.floor 2, " ", 'm' mod.floor 2, " ", 't' mod.floor -2, newln];
let 'r': deci64 = 1.05;
cord::print.stored['r' pow 10, " ", 'r' pow 0, " ", 'r' pow -1, newln];deci, continued22 linesMAIN {
let 'a' := to.deci32["1234567.0"] otherwise { not_a_number { is *0.0; } too_many_digits { is *0.0; } out_of_range { is *0.0; } };
let 'b' := to.deci32.written["1234567.0"] otherwise { not_a_number { is *0.0; } too_many_digits { is *9.0; } out_of_range { is *0.0; } };
let 'c' := to.deci32.written["1234567"] otherwise { not_a_number { is *0.0; } too_many_digits { is *9.0; } out_of_range { is *0.0; } };
cord::print.useful['a', " ", 'b', " ", 'c', newln];
}Deci written9 linesfn g ['x': uint32] -> uint32 {
return 'x';
}
MAIN {
let 'v': uint32 = g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[g[7]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]]];
cord::print.useful['v', newln];Deep calls10 linesMAIN {
let 'x': bin64 = 0.00000000000000000001;
let 'n': bin64 = -0.00000000000000000001;
let 'two': bin64 = 2.0;
let 'turn': bin64 = 360.0;
cord::print.useful[('x' div.ceil 'two'), " ", ('x' mod.ceil 'two'), " ", ('n' div.floor 'turn'), " ", ('n' mod.floor 'turn'), newln];Div edges17 linesMAIN {
let 'a': int8 = -128;
cord::print.useful[('a' div.trunc -1), " ", ('a' div.floor -1), " ", ('a' mod.floor -1), newln];
let 'b': int16 = 'a' div.near -1; # lands in an int16: fits
cord::print.useful['b', newln];
}Div lands8 linesMAIN {
cord::print.useful[(7 div.floor 2), " ", (7 div.ceil 2), " ", (7 div.trunc 2), " ", (7 div.near 2), newln];
cord::print.useful[(-7 div.floor 2), " ", (-7 div.ceil 2), " ", (-7 div.trunc 2), " ", (-7 div.near 2), newln];
cord::print.useful[(7 mod.floor 2), " ", (7 mod.ceil 2), " ", (7 mod.trunc 2), " ", (7 mod.near 2), newln];
cord::print.useful[(-7 mod.floor 2), " ", (-7 mod.ceil 2), " ", (-7 mod.trunc 2), " ", (-7 mod.near 2), newln];
cord::print.useful[(5 div.near 2), " ", (5 mod.near 2), newln]; # 2.5 is a tie: to the even 2, 1 leftDiv rounding20 linesMAIN {
let 'a': int8 = -128;
cord::print.useful[('a' div.trunc.wrap -1), " ", ('a' div.floor.wrap -1), " ", ('a' div.trunc -1), newln];
let 'm': int128 = -170141183460469231731687303715884105728;
cord::print.useful[('m' div.trunc.wrap -1), " ", ('m' div.near.wrap 2), newln];
}Div wrap9 linesMAIN {
cord::print.useful[7 div.floor 2, " ", 7 mod.floor 2, newln];
cord::print.useful[-7 div.floor 2, " ", -7 mod.floor 2, newln]; # -4 and 1: the clock never goes negative
cord::print.useful[7 div.floor -2, " ", 7 mod.floor -2, newln]; # -4 and -1: the result has the divisor's sign
let 'hour' := -1;
cord::print.useful[('hour' mod.floor 12) plus 1, newln]; # an hour before 1 o'clock is 12Division10 linesfn twice ['d': duration] -> duration {
return 'd' plus 'd';
}
MAIN {
let 'w': duration = 2 seconds;
cord::print.useful[twice['w'] equal_to 4 seconds, newln];Duration bare9 linesMAIN {
let 'xs': list[int32] = [];
list.append[lend.mut 'xs', 7];
list.append[lend.mut 'xs', 8];
cord::print.useful['xs', " ", list.length[lend 'xs'], newln];
let 'ys' := list.empty;Empty10 linesenum Status {
empty
claimed: str.utf8
locked
}
struct Locker {Enums & match33 linesMAIN {
let 'price' := *19.99;
let 'tenth' := *0.1;
let 'total' := 'tenth' plus *0.2; # exactly 0.3
let 'half': deci32 = *0.5; # a typed deci takes it at its width
let 'speed' := 0.1; # a binExact literal10 linesbare.never [fn];
module text {
extern.C {
pub fn strlen ['s': ptr[uint8]] -> uint64;
fn write ['fd': int32, 'buf': ptr[uint8], 'len': uint64] -> int64;
}Extern block pub23 linesextern.C 'lib_version': int32; # C: extern int lib_version;
extern.C mut 'lib_verbose': int32; # C: extern int lib_verbose; (we may write it)
MAIN {
no_check let 'v' := 'lib_version';
cord::print.useful["version ", 'v', newln];
no_check change 'lib_verbose' = 1;Extern data11 linesextern.C fn strlen ['s': ptr[uint8]] -> uint64[min 0, max 10]; # C promises at most 10; checked at the door
MAIN {
let 'short' := "hello";
let 'long' := "this is longer than ten";
no_check let 'a' := strlen[lend 'short'] otherwise 99;
no_check let 'b' := strlen[lend 'long'] otherwise 99; # 23 is outside 0..10: fails out_of_rangeExtern range12 linesstruct Locker {
owner: str.utf8
items: list[str.utf8]
}
fn stash [lent.mut 'l': Locker, 'item': str.utf8] -> bool or fail[full, bad_item: str.utf8] {
if list.length[lend 'l'.items] at_least 2 { fail full; }Failures43 linesMAIN {
let 'x': deci64 = 3.141592653589793;
let 'y' := to.deci32['x'] otherwise 0;
let 'z' := to.int64['y' times 1000000] otherwise -1;
let 'b': bin64 = to.bin64["not a number"] otherwise 0;
cord::print.stored['y', " ", 'z', " ", 'b', newln];Fallback type9 linesextern.C fn write ['fd': int32, 'buf': ptr[uint8], 'len': uint64] -> int64;
extern.C fn strlen ['s': ptr[uint8]] -> uint64;
extern.C fn getenv ['name': ptr[uint8]] -> ptr[uint8];
extern.C fn malloc ['bytes': uint64] -> ptr.mut[uint8];
extern.C fn free ['p': ptr.mut[uint8]];
layout.C struct Timeval {Talking to C35 linesfn say ['n': int32] {
let 'by3' := ('n' mod.floor 3) equal_to 0;
let 'by5' := ('n' mod.floor 5) equal_to 0;
if 'by3' and 'by5' {
cord::print.stored["FizzBuzz", newln];
} else if 'by3' {FizzBuzz22 linesMAIN {
let 'xs': list[int32] = [1, 2];
for 'x' in lend 'xs' {
let 'v': int64 = to.int64['x' plus.wrap 10];
let 'w': int64 = to.int64[not.bit 'x'];
cord::print.useful['v', " ", 'w', newln];For item type12 linesMAIN {
let mut 'prices': list[int32] = [10, 20, 30];
for 'x' in lend.mut 'prices' {
change 'x' = 'x' times 2;
}
cord::print.stored['prices', newln];for over lend.mut10 linesMAIN {
let mut 'xs': list[int32] = [1, 2, 3];
let mut 'seen': list[int32] = [];
for 'x' in lend.mut 'xs' {
change 'x' = 'x' times 10;
list.append[lend.mut 'seen', 'xs'[pos 1]];Reading during a lend.mut walk12 linesMAIN {
let mut 'acc': int64 = 0;
for no_cheat 'i': int64 from 1 to 1000 by 1 {
change 'acc' = 'acc' plus 'i';
}
let mut 'more': int64 = 0;for no_cheat: no cheating14 linesMAIN {
let 'xs': list[int64] = [1, 2, 3, 4];
let mut 'total': int64 = 0;
for para 'x' in lend 'xs' {
change 'total' = 'total' plus 'x';
}for para and for seq13 linesMAIN {
let 'xs' := ["ann", "bob", "cy"];
for 'i', 'x' in lend 'xs' {
cord::print.useful['i', ". ", 'x', newln];
}
let 'scores' := [70, 95, 88];Position and item17 linesMAIN {
let 'n' := 3;
let 'line' := format["{} items at {:.2} each, 0x{:x}\n", 'n', 1.5, 255];
print.useful['line'];
print.weird.useful <- "hex: " <- format["{:x}", 'n' times 100] <- newln;
print.useful.stdout["said ", "stdout", newln];Format value10 linesstruct Locker { number: int32 owner: str.utf8 }
fn by_number [lent 'a': Locker, lent 'b': Locker] -> bool { return 'a'.number < 'b'.number; }
fn by_owner [lent 'a': Locker, lent 'b': Locker] -> bool { return str.bytes[lend 'a'.owner] < str.bytes[lend 'b'.owner]; }
fn first_by [lent 'xs': list[Locker], 'less': fn[lent Locker, lent Locker] -> bool] -> str.utf8 {
let 'best' := 1;
for 'i' from 2 to list.length[lend 'xs'] by 1 {Functions as values38 linesinterface Number <T> {
op minus ['a': <T>, 'b': <T>] -> <T>;
op < ['a': <T>, 'b': <T>] -> bool;
}
op ~= <T: Number> ['a': <T>, 'b': <T>] -> bool {
if 'a' < 'b' { return 'b' minus 'a' < 10; }Generic op22 linesinterface Number {
int32
int64
bin64
}
fn max <T: Number> ['a': <T>, 'b': <T>] -> <T> {Generics39 linespub const 'passing' := 60;
struct Student {
name: str.utf8
scores: list[int32]
}
fn average [lent 's': Student] -> int32 or fail[no_scores] {Gradebook46 linesMAIN {
cord::print.stored["Hello, World!", newln];
}Hello, World3 linesMAIN {
let 'text' := cord::input.line[] otherwise "(no input)"; # a boundary: fails with `closed`
cord::print.stored["got: ", 'text', newln];
let 'n' := to.int32[min 0, max 100]['text'] otherwise 50;
cord::print.useful["n = ", 'n', newln];
}Input10 linesinterface Number {
int32
int64
bin64
}
interface Ordered <T> {Interface types41 linesinterface Ordered <T> {
op < ['a': <T>, 'b': <T>] -> bool;
op equal_to ['a': <T>, 'b': <T>] -> bool;
}
interface Printable <T> {
fn show [lent 'x': <T>] -> str.utf8;Interfaces39 linesstruct Item { name: str.utf8 grams: int32[min 1, max 50_000] }
fn heaviest [...'items': Item] -> Item or fail[none] {
if list.length[lend 'items'] equal_to 0 { fail none; }
let mut 'best' := list.remove[lend.mut 'items', pos 1];
for 'it' in lend 'items' {
if 'it'.grams > 'best'.grams { change 'best' = copy 'it'; }Inventory44 linesstruct Counter {
now: int32
stop: int32
}
fn Counter.next [lent.mut 'c': Counter] -> optional[int32] {
if 'c'.now equal_to 'c'.stop { return optional.none; }Iterators44 linesMAIN {
let 'n' := 3;
let 's' := "n=" ++ to.stored.str.utf8['n' plus 4]; # arithmetic, convert, then join
cord::print.stored['s', newln];
cord::print.stored["count: " ++ to.stored.str.utf8[10], newln]; # a number is converted, in its stored form
let 'x': bin64 = 0.1;Join13 linesinterface Key <T> { op equal_to ['a': <T>, 'b': <T>] -> bool; fn hash [lent 'v': <T>] -> uint64; }
struct Point { x: int32 y: int32 } # structural: fields decide
struct User { name: str.utf8 } # its own rule: names compare lowercased
op equal_to ['a': User, 'b': User] -> bool { return cord::str.lower[lend 'a'.name] equal_to cord::str.lower[lend 'b'.name]; }
fn hash [lent 'v': User] -> uint64 { let 'low' := cord::str.lower[lend 'v'.name]; return str.bytes[lend 'low']; }
User satisfies Key;Keys22 linesfn to [] -> int32 { return 5; }
fn true [] -> int32 { return 1; }
MAIN {
let 'x' := my.to[];
let 'y' := my.true[];
cord::print.useful['x', " ", 'y', newln];Keyword fn9 linesfn pick [@x] [lent 'a': list[int32], lent @x 'b': list[int32]] -> lent @x list[int32] {
return lend 'b';
}
MAIN {
let 's': list[int32] = [1, 2];
let 'r' := pick[lend 's', lend 's'];Lent twice10 linesfn longer [@x] [lent @x 'a': str.utf8, lent @x 'b': str.utf8] -> lent @x str.utf8 {
if str.bytes[lend 'a'] at_least str.bytes[lend 'b'] { return lend 'a'; }
return lend 'b';
}
fn pick [@x, @y] [lent @x 'a': str.utf8, lent @y 'b': str.utf8] -> lent @x str.utf8 {
return lend 'a';Lifetimes: @x24 linesMAIN {
let mut 'l': list[int32] = [1, 2];
list.append[lend.mut 'l', 3];
let 'a' := to.array[give 'l']; # [1, 2, 3], can no longer grow
let mut 'm' := to.list[copy 'a']; # 'a' is still here
list.append[lend.mut 'm', 4];list and array13 linesMAIN {
let mut 'scores' := list.fill[value 0, count 5];
change 'scores'[pos 2] = 7;
cord::print.stored['scores', newln];
let 'n': int64 = 3;
let 'flags': list[bool] = list.fill[value false, count 'n'];list.fill12 linesMAIN {
let 'i': uint8 = 5;
let 'xs': list[uint8] = [0 minus.wrap 1, 0 minus.wrap 'i', 250 plus.wrap 10];
let 'ys': list[uint32] = [2 shl 3, not.bit 0];
let 'zs': list[list[uint8]] = [[0 minus.wrap 2,], [1,]];
let 'big': list[uint64] = [9692729768110883998 minus 3166240359165959856,];List item context12 linesMAIN {
let 'bs': list[bin64] = [1, 2];
let 'more': list[bin64] = list.fill[value 1, count 3];
let 'ds': list[deci64] = list.fill[value 0.25, count 3];
cord::print.stored['bs', newln];
cord::print.stored['more', newln];List literal family10 linesMAIN {
let 'xs' := [1, 2.5];
let 'ys': list[bin64] = [2.5, 1];
cord::print.useful['xs', newln];
cord::print.useful['ys', newln];
cord::print.useful['xs'[pos 1] plus ('xs'[pos 2] times 2.0), newln];List literal mixed14 linesfn count <T: any> [lent 'items': list[<T>]] -> int32 {
let 'n' := 0;
for 'item' in lend 'items' {
change 'n' = 'n' plus 1;
}
return 'n';Lists18 linesfn sum [lent 'items': list[int32]] -> int32 {
let 'total' := 0;
for 'n' in lend 'items' {
change 'total' = 'total' plus 'n';
}
return 'total';Lists231 linesconst 'base' := 100;
fn tries ['n': int32] -> int32 {
const 'extra' := 2;
return 'n' plus 'extra';
}
MAIN {Local const16 linespub const 'capacity' := 12;
struct Locker {
immut number: int32
owner: str.utf8
items: list[str.utf8]
}Lockers43 linesfn double ['n': int32] -> int32 { return 'n' times 2; }
fn apply ['v': int32, 'f': fn[int32] -> int32] -> int32 { return 'f'['v']; }
MAIN {
cord::print.useful[double[4], " ", apply[5, double], newln];
cord::print.weird.useful <- "weird: " <- double[2] <- newln;
}Long arrow8 linesMAIN {
let 'i' := 0;
while 'i' < 3 {
cord::print.useful["while ", 'i', newln];
change 'i' = 'i' plus 1;
}Loops23 linesextern.C {
fn write ['fd': int32, 'buf': ptr[uint8], 'len': uint64] -> int64;
fn malloc ['bytes': uint64] -> ptr.mut[uint8];
fn free ['p': ptr.mut[uint8]];
}
layout.C struct Header { magic: uint32 flags: uint8 length: uint64 }Low level56 linesenum E1 { c1: int32 c2: uint8 c3 }
MAIN {
let 'e' := E1.c1[5];
match 'e' {
c1 'd' { cord::print.useful[not.bit 'd', " ", 'd' times.wrap 1000000000, newln]; }
c2 'b' { }A match arm's data14 linesenum Status { empty claimed: str.utf8 locked }
fn label ['s': Status] -> str.utf8 {
let 'text' := match 's' {
empty { is "free"; }
claimed 'who' { is "taken by " ++ 'who'; }
locked { return "(locked)"; }match gives a value21 linesMAIN {
let 'angle': bin64 = -370.0;
let 'turn': bin64 = 360.0;
let 'a': bin64 = 7.5;
let 'b': bin64 = -2.0;
let 'h': brain16 = -5.0;Mod bin15 linesbare.never [fn, struct];
const 'scale' := 10;
module counter {
pub const 'start' := 1;
pub struct Count { n: int32 }
pub fn bump ['c': Count] -> Count {Modules29 linesfn twice [immut 'n': int32] -> int32 {
return 'n' times 2;
}
MAIN {
let 'plain' := 1;
change 'plain' = 'plain' plus 1;Mutability12 linesenum Order { cancelled paid }
enum Ship { pickup post }
MAIN {
let 'o' := Order.paid;
let 's' := Ship.post;
match 'o' {Nested match14 linesextern.C fn write ['fd': int32, 'buf': ptr[uint8], 'len': uint64] -> int64;
MAIN {
let 'msg' := "hello";
NO_FUCKING_CHECKS let 'n' := write[1, lend 'msg', str.bytes[lend 'msg']];
NO_FUCKING_CHECKS {
let 'a': int32 = 10;NO_FUCKING_CHECKS14 linesextern.C fn write ['fd': int32, 'buf': ptr[uint8], 'len': uint64] -> int64;
fn emit ['m': uint64, 'neg': bool] {
let mut 'buf': list[uint8] = [];
if 'neg' { list.append[lend.mut 'buf', 45]; }
let mut 'v': uint64 = 'm';
let mut 'ds': list[uint8] = [];Not bit fill45 lineson.target.os windows {
fn where [] -> str.utf8 { return "windows"; }
} else {
fn where [] -> str.utf8 { return "not windows"; }
}
MAIN {On target26 linesMAIN {
let 'pos': int32[min 1] = 1;
let 'score': int32[max 100] = 50;
let 'small': int8[min 1] = 120;
let 'whole': uint8[min 0, max 255] = 200; # the whole type: harmless, allowed (owner)
let 'also': int32 = -7; # no bound at all: the type itselfOne ended10 linesstruct Vec { x: bin64 y: bin64 }
op dot ['a': Vec, 'b': Vec] -> bin64 { return 'a'.x times 'b'.x plus 'a'.y times 'b'.y; }
fn fold [lent 'xs': list[int32], 'start': int32, 'f': fn[int32, int32] -> int32] -> int32 {
let mut 'acc' := 'start';
for 'x' in lend 'xs' { change 'acc' = 'f'['acc', 'x']; }
return 'acc';Operators as values27 linesstruct Vec { x: bin64 y: bin64 }
op <+> ['a': Vec, 'b': Vec] -> Vec {
return Vec[x = 'a'.x plus 'b'.x, y = 'a'.y plus 'b'.y];
}
op dot ['a': Vec, 'b': Vec] -> bin64 {
return 'a'.x times 'b'.x plus 'a'.y times 'b'.y;Operators30 linesMAIN {
let 'small': int16 = 5;
let 'big': int64 = (20000 plus 20000) plus 'small'; # 40005: the true answer, and it fits int64
let 's': int16 = 30000;
let 'twice': int64 = 's' plus 's'; # 60000, though no int16 holds it
let 'tiny': int8 = (100 plus 100) minus 150; # 50: the 200 in between is fineOverflow sites21 linesfn count [lent 'items': list[str.utf8]] -> int32 {
let 'n' := 0;
for 'item' in lend 'items' {
change 'n' = 'n' plus 1;
}
return 'n';Ownership34 linesMAIN {
let 'xs' := [1, 2, 3];
let 'count' := fn [] -> uint64 with [copy 'xs'] { return list.length[lend 'xs']; };
let 'again' := copy 'count'; # its own copy of the list inside
let 'moved' := give 'count'; # 'count' is gone after this
let 'inc' := fn ['a': int32] -> int32 { return 'a' plus 1; };Owning function12 linesMAIN {
let mut 'phones': map[str.utf8, int32] = map["ann" = 5551, "bob" = 5552]; # a literal: key = value
map.set[lend.mut 'phones', "ann", 5553]; # same key: replaced
cord::print.useful[map.length[lend 'phones'], " entries", newln];
let 'a' := map.get[lend 'phones', "ann"] otherwise 0;
let 'c' := map.get[lend 'phones', "cat"] otherwise 0; # missing → 0Phonebook23 linesfn pi_digits ['n': int32] {
let 'len' := (10 times 'n') div.floor 3 plus 1;
let mut 'a' := list.empty;
for 'i' from 1 to 'len' by 1 { list.append[lend.mut 'a', 2]; }
let mut 'nines' := 0;
let mut 'predigit' := 0;Digits of pi36 linesMAIN {
cord::print.useful[(2 pow (3 pow 2)), newln];
cord::print.useful[((2 pow 3) pow 2), newln];
let 'kilo' := 2 pow 10;
cord::print.useful['kilo', newln];
cord::print.useful[(10 minus 3 minus 2), newln];Power7 linesMAIN {
cord::print.useful[(1 plus 2 times 3), newln];
cord::print.useful[(2 times (3 pow 2)), newln];
cord::print.useful[-(2 pow 2), newln];
cord::print.useful[((-2) pow 2), newln];
cord::print.useful[(10 minus 4 minus 3), newln];Precedence14 linesstruct Vec { x: bin64 y: bin64 }
precedence.low_first {
level.when_chained.refused 1 { equal_to ~= }
level.when_chained.left_first 2 { plus }
level.when_chained.left_first 3 { times dot }
level.when_chained.left_first 4 { scale }Precedence levels33 linesMAIN {
cord::print.useful.auto_newln["Hello, World!"];
let 'n' := 3;
cord::print.useful.auto_newln["n is ", 'n'];
cord::print.useful["the same, by hand: ", 'n', newln];
}print.useful.auto_newln7 linesMAIN {
let 'name' := "rope";
let 'count' := 3;
let 'price': bin64 = 12.5;
let 'pay': deci64 = 37.5 times 12.40;
let 'tenth': bin64 = 0.1;print.format19 linesMAIN {
let 'x': bin64 = 0.1;
cord::print.stored['x', newln];
cord::print.useful['x', newln];
let 'y': bin16 = 1000;
cord::print.useful['y', newln];print vs print.useful13 linesMAIN {
let 'tenth': bin64 = 0.1;
let 'n' := 3;
cord::print.weird.useful <- "tenth is " <- 'tenth' <- ", n is " <- 'n' <- newln;
cord::print.weird.stored <- "stored: " <- 'tenth' <- newln;
}print.weird10 linesMAIN {
let 'name' := "Ann";
let 'count' := 6;
let 'x': bin64 = 0.1;
cord::print.stored["x is ", 'x', newln];
cord::print.useful["x is ", 'x', newln];Prints20 linesextern.C fn malloc ['bytes': uint64] -> ptr.mut[uint8];
extern.C fn free ['p': ptr.mut[uint8]];
layout.C struct Point {
x: int32
y: int32
}ptr.cast18 linesstruct Job { name: str.utf8 }
fn run ['job': Job] { cord::print.useful["ran ", 'job'.name, newln]; }
MAIN {
let mut 'queue' := [Job[name = "a"], Job[name = "b"], Job[name = "c"]];
run[list.remove[lend.mut 'queue', pos 1]]; # straight into a call
let 'next' := list.remove[lend.mut 'queue', pos 1]; # or keptQueue12 linesMAIN {
for 'i' from 1 to 3 by 1 {
cord::print.useful['i', " "];
}
cord::print.stored[newln];
for 'k' from 0 to 10 by 5 {Range33 linesstruct Percent { value: uint8[min 0, max 100] }
fn scale ['p': Percent, 'total': int32[min 0, max 1000]] -> int32[min 0, max 1000] {
return ('total' times to.int32['p'.value]) div.floor 100;
}
MAIN {
let 'half' := Percent[value = 50];Ranges24 linesenum Pick { quick slow }
fn f [] -> uint64 {
let 'v': uint16 = match Pick.quick {
quick { return 8997704354644785536 shr 42; }
slow { is 1; }
};return inside a match15 linesfn is_even ['n': int32] -> bool {
return ('n' mod.floor 2) equal_to 0;
}
fn clamp ['n': int32, 'low': int32, 'high': int32] -> int32 {
if 'n' < 'low' {
return 'low';Scores49 linesMAIN {
let immut 'a' := 1;
shadow 'a' := 2; # an immut can be shadowed: nothing is changed
let 'b' := 3; # no word: it may not change either
let no_shadow mut 'total' := 0; # changeable, and 'total' always means this one
change 'total' = 'total' plus 'a' plus 'b';Sealed12 linesMAIN {
let 'x' := 1;
if true {
shadow 'x' := 2;
cord::print.useful['x', newln];
}shadow10 linesMAIN {
let 'xs': list[uint8] = [10, 20, 30,];
cord::print.useful[(list.length[lend 'xs'] shl 1) > 5, " ", ('xs'[pos 1] shr 2) equal_to 2, newln];
}Shift length item6 linesMAIN {
let 'b': uint8 = 255;
let 'x': int64 = 1;
let 'up': uint8 = 'b' shl.masked 1; # 510 cut to 8 bits: 254
let 'far': int64 = 'x' shl.masked 70; # 70 masked to 6: 64
let 'down': uint8 = 'b' shr.masked 9; # 9 masked to 1: 127Shift masked12 linesfn g [] -> int8 { return 10; }
MAIN {
if 3 > (g[] shl 1) { cord::print.useful["yes", newln]; } else { cord::print.useful["no", newln]; }
}Shl call width6 linesinterface Priced <T> {
fn price [lent 'x': <T>] -> int32;
}
enum Stock {
out
few: int32Shop64 linesfn double ['n': int32] -> int32 { return 'n' times 2; }
MAIN {
cord::print.weird.useful <- double[3] <- newln;
}Short arrow6 linesfn is_ascii [lent 'bytes': array[uint8]] -> bool {
let mut 'acc': simd[uint8, 16] = simd.fill[value 0];
for 'i' from 1 to array.length[lend 'bytes'] by 16 {
change 'acc' = 'acc' or.bit simd.load[lend 'bytes', pos 'i'];
}
return simd.max['acc'] < 128;SIMD23 linesstruct Particle { place: simd[bin32, 4] vel: simd[bin32, 4] }
fn step ['p': Particle] -> Particle {
return Particle[place = 'p'.place plus 'p'.vel, vel = 'p'.vel];
}
MAIN {
let 'p' := Particle[place = simd.fill[value 0.0], vel = simd.fill[value 0.5]];SIMD fields15 linesMAIN {
let 's': simd[uint8, 16] = simd.fill[value 3];
cord::print.useful[simd.max['s'] shl 1, newln];
}SIMD fold shift6 linesMAIN {
let 's': simd[uint64, 2] = simd.fill[value 40];
if 3 < ('s'[pos 2] shr 2) { cord::print.useful["10 is more than 3", newln]; }
}SIMD lane shift6 linesMAIN {
let 'a': simd[int32, 4] = simd.fill[value 4];
let 'x': int32 = 'a'[pos 1];
let 'u': simd[uint8, 16] = simd.fill[value 200];
let 'w' := 'u' plus.wrap 'u';
cord::print.stored['x', " ", 'w'[pos 1], " ", 'w'[pos 16], newln];SIMD lanes13 linesfn count_on ['m': simd[bool, 4]] -> bool {
return simd.all['m'];
}
MAIN {
let 'xs': array[int32] = [5, 20, 30, 40];
let 'a': simd[int32, 4] = simd.load[lend 'xs', pos 1];SIMD mask15 linesMAIN {
on.target.chip x86_64 {
let 'w': simd[int32, 8] = simd.fill[value 1];
} else {
let 'v': simd[int32, 4] = simd.fill[value 1];
print.useful[simd.sum['v'], newln];SIMD ruled out11 linesMAIN {
let 'xs': array[int32] = [10, 20, 30, 40];
let 'v': simd[int32, 4] = simd.load[lend 'xs', pos 1];
let 'r' := simd.shuffle['v', [4, 3, 2, 1]]; # reversed
let 'pairs' := simd.shuffle['v', [2, 1, 4, 3]]; # neighbours swapped
let 'first' := simd.shuffle['v', [1, 1, 1, 1]]; # lane 1 everywhereSIMD shuffle11 linesMAIN {
let 'v': simd[int32, 4] = simd.fill[value 1200000000];
let 's': int64 = simd.sum['v'];
let 'w': int32 = simd.sum.wrap['v'];
let 'u': simd[int32, 4] = simd.fill[value -500000000];
let 'l': int32 = simd.sum.lane['u'];SIMD sum forms11 linesMAIN {
let mut 'xs': list[int32] = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
let 'n' := list.length[lend 'xs'];
let mut 'acc': simd[int32, 4] = simd.fill[value 0];
let mut 'i': uint64 = 1;
while 'i' at_most 'n' {SIMD tail25 linesMAIN {
let 'xs' := [10, 20, 30, 40, 50];
let 'mid' := list.slice[lend 'xs', from pos 2, to pos 4];
cord::print.useful['mid', " ", list.length[lend 'mid'], newln];
let 'fixed': array[int32] = [1, 2, 3];
cord::print.useful[array.slice[lend 'fixed', from pos 1, to pos 2], newln];Slicing11 linesfn ratio ['n': int32[min 1]] -> int32 { return 100 div.floor 'n'; }
MAIN {
let immut 'xs': list[int32] = [10, 20, 30, 40];
let mut 'total': int32 = 0;
for temp 'i': uint64 from 1 to 4 by 1 {
change 'total' = 'total' plus 'xs'[pos 'i'];Written out15 linesfn sum [...'nums': int32] -> int32 {
let mut 'total' := 0;
for 'n' in lend 'nums' { change 'total' = 'total' plus 'n'; }
return 'total';
}
fn show [lent 'label': str.utf8, lent ...'parts'] {Spread33 linesMAIN {
let 's' := "a b c";
let 'parts' := str.split[lend 's', " "];
let 'same' := cord::str.split[lend 's', " "];
print.useful[list.length[lend 'parts'], " ", cord::list.length[lend 'same'], newln];
cord::print.useful[round[2.5], newln];Std bare10 linesMAIN {
let 'a': int32 = 2 cord::plus 3 cord::times 4;
let 'b': int32 = 7 cord::div.floor 2;
let 'c': uint32 = 1 cord::shl 3;
cord::print.useful['a', " ", 'b', " ", 'c', newln];
}Std op path9 linesMAIN {
cord::print.stored["a\nb", newln]; # newln inside quotes is a backslash and an n
cord::print.stored["say \"hi\"", newln]; # \" is the one escape that is needed
cord::print.stored["back\\slash", newln]; # and \\ for the backslash itself
cord::print.stored["tab here", newln]; # a tab is typed, not escaped
let 'nl' := newln; # the newline is the bare newln outside quotesStrings8 linesstruct Locker {
name: str.utf8
immut number: int32
capacity: int32
occupied: bool
}Structs37 linesfn add ['a': int32, 'b': int32] -> int32 { return 'a' plus 'b'; }
fn wrong ['a': int32, 'b': int32] -> int32 { return 'a' plus 'b' plus 1; }
test fn adds_up [] {
must add[2, 3] equal_to 5;
must add[2, 3] > 4;
}Tests: test fn and must27 linesMAIN {
let 's' := "héllo 👨👩👧 wörld";
cord::print.useful[str.bytes[lend 's'], " bytes, ", str.points[lend 's'], " points, ", str.graphemes[lend 's'], " graphemes", newln];
let 'vowels' := 0;
for 'g' in str.each.grapheme[lend 's'] {
if 'g' equal_to `o` or 'g' equal_to `e` { change 'vowels' = 'vowels' plus 1; }Text27 linesfn greet [lent 'name': str.utf8[min 1, max 10 graphemes]] { cord::print.useful["hi ", 'name', newln]; }
MAIN {
let 'thai': str.utf8[min 1, max 10 graphemes] = "เกี่ยว"; # 4 graphemes (เ|กี่|ย|ว), 6 points, 18 bytes: fits
let 'ascii': str.utf8[min 0, max 5 bytes] = "hello"; # 5 bytes: fits
greet[lend 'thai'];
greet[lend 'ascii'];Text bound14 linesMAIN {
let 'a' := to.int32["42"] otherwise 0;
let 'b' := to.int32["99999999999"] otherwise -1; # too big for int32
let 'c' := to.int64["99999999999999999999999999999999999999999999"] otherwise -1; # too big for anything
let 'd' := to.uint8["-1"] otherwise 0; # below what uint8 holds
let 'e' := to.int32["12x"] otherwise -2; # not a number at allText to number16 linesMAIN {
let 'plain': str.utf8 = "hello";
let 'accented': str.utf8 = "héllo";
let 'a' := to.str.ascii['plain'] otherwise "?";
let 'b' := to.str.ascii['accented'] otherwise "not ascii";
cord::print.stored['a', newln, 'b', newln];To ASCII13 linesMAIN {
let 'a' := to.int8.bits[128]; # 128's bits in an int8: -128
let 'b' := to.uint8.bits[-1]; # -1's bits in a uint8: 255
let 'c': uint8 = 200;
let 'd' := to.int8.bits['c']; # 200's bits: -56
cord::print.useful['a', " ", 'b', " ", 'd', newln];To bits10 linesenum Size {
small
big
}
MAIN {
let 'x': bin64 = 0.1;To text forms20 linesMAIN {
let 'b': bin64 = 10000000000.0;
let 'd': deci128 = 99999999999999999999.0;
let 'small': deci64 = 42.0;
let 'x' := to.int32['b'] otherwise -1;
let 'y' := to.int64['d' times 1000] otherwise -2;Too big to int12 linesextern.C fn exit ['code': int32];
fn judge ['n': int32] -> fail[small] { if 'n' < 10 { fail small; } }
MAIN {
let mut 'seen': int32 = 0;
{
concur { judge[3] otherwise fail; } otherwise { small { change 'seen' = 'seen' plus 1; } };Two tasks fail12 linesfn sum [...'nums'] -> bin64 {
let 'total': bin64 = 0;
for 'n' in lend 'nums' { change 'total' = 'total' plus to.bin64['n']; }
return 'total';
}
fn count_ints [...'nums': int32] -> uint64 {Variadic24 linesfn fetch [lent 'url': str.utf8] -> str.utf8 or fail[no_network] {
if 'url' equal_to "down.com" { fail no_network; }
return "page of " ++ 'url';
}
MAIN {
let 'inbox' := channel[str.utf8][max 10];whichever30 linesMAIN {
let 'x': bin64 = 2.0;
let 'y': bin64 = 2.7;
let 'a' := to.int32['x'] otherwise -1; # whole: 2
let 'b' := to.int32['y'] otherwise -1; # not whole: fails → -1
let 'c' := to.int32[cord::round['y']] otherwise -1; # said: 3Whole19 linesMAIN {
let 'a': not_std.uint256 = 2 pow 200 plus 12345;
let 'b': not_std.uint256 = (2 pow 255) minus 1;
cord::print.useful[('a' and.bit 'b'), newln];
cord::print.useful[('a' xor 'b'), newln];
cord::print.useful[('a' shl 55), " ", ('a' shr 190), newln];Wide bits18 linesMAIN {
let 'max': not_std.uint256 = 115792089237316195423570985008687907853269984665640564039457584007913129639935;
let 'half': not_std.uint256 = 'max' div.floor 2;
let 'top': not_std.uint256 = 2 pow 255;
cord::print.useful['half', newln];
cord::print.useful[('top' minus 1 plus 'top'), newln];Wide integers16 linesMAIN {
let 'small': not_std.int300 = 5;
let 'huge': not_std.int300 = 2 pow 200;
let 'a' := to.deci128['small'] otherwise 0.0;
let 'b' := to.deci128['huge'] otherwise 0.0;
cord::print.useful['a', " ", 'b', newln];Wide to deci9 linesMAIN {
let 'v': uint32 = 3;
let 'a': uint32 = 2 shl 3;
let 'b': uint32 = ('v' mod.floor 16) shl 2;
let 'c': uint32 = not.bit ('v' plus 1);
let 'd': uint32 = ('v' plus 1) plus.wrap 5;Widths10 linesMAIN {
let 'a': int32 = 7;
let 'b': int32 = 3;
cord::print.useful[('a' plus 'b'), " ", ('a' minus 'b'), " ", ('a' times 'b'), " ", ('a' pow 'b'), " ", ('a' cord::pow 2), " ", -'a', newln];
let 'h': uint8 = 200;
cord::print.useful[('h' plus.wrap 100), " ", ('h' times.wrap 2), " ", ('h' pow.wrap 2), newln];Word operators11 linesfn hash [lent 'text': str.utf8] -> uint32 {
let 'h': uint32 = 2_166_136_261; # FNV-1a
for 'b' in str.each.byte[lend 'text'] {
change 'h' = 'h' xor 'b'; # FNV-1a: xor, then a wrapping multiply
change 'h' = 'h' times.wrap 16_777_619; # wraps instead of overflowing
}Wrapping23 linesMAIN {
let 'z': bin64 = 0.0;
let 'n': bin64 = -2.0;
let 'e30': bin64 = 0.000000000000000000000000000001;
let 'e60': bin64 = 'e30' times 'e30';
let 'e120': bin64 = 'e60' times 'e60';Zero everywhere26 linesMAIN {
let 'q': bin64 = 0.5 div.ceil (-1.75);
let 'r': bin64 = 0.5 div.ceil.ieee (-1.75);
let 'b': brain16 = 0.5 div.trunc (-1.75);
cord::print.useful['q', " ", 'r', " ", 'b', " ", 'q' equal_to 'r', newln];
}Zero quotient8 linesCorner shopexamples/corner_shop.nrv · 669 lines
A day at a corner shop: a longer Nerve program, written to be read.
# A day at a corner shop: a longer Nerve program, written to be read.
#
# It keeps a small catalog, takes orders written as text, prices them in exact decimals (`deci64`,
# so 0.10 plus 0.20 is 0.30), applies discounts that a range type keeps between 0 and 50 percent,
# prints receipts, tracks stock and loyalty points in maps, and ends the day with a report, a
# restocking plan, the day's busy hours, the week's trade and a catalog search. Along the way it
# shows most of Nerve's everyday features:
#
# structs and enums with data, `match` ownership said aloud: `give`, `copy`, `lend`
# failures a caller must handle, `otherwise` generics with an interface, and `Number`
# functions as values a type's own function as an iterator (`Ticket.next`)
# range types, `int32[min 0, max 50]` counting loops, `for 'i' from 1 to 'n' by 1`
# slices, `from pos 1, to pos 3` consts, at the top and inside a body
# tasks and channels, `concur` `print.useful`, `print.stored`, `print.format`
#
# Nothing here is clever on purpose. A shop's code is read far more often than it is written.
# ---------------------------------------------------------------------------------------------------
# The shop's fixed facts
# ---------------------------------------------------------------------------------------------------
const 'shop_name' := "Corner Shop";
const 'points_per_item' := 2; # loyalty points earned for every item bought
const 'low_stock' := 3; # at or below this, an item goes on the reorder list
# ---------------------------------------------------------------------------------------------------
# Types
# ---------------------------------------------------------------------------------------------------
enum Aisle {
fresh
bakery
pantry
household
}
struct Item {
name: str.utf8
aisle: Aisle
price: deci64
}
# One line of an order: what, and how many.
struct Line {
name: str.utf8
count: int32[min 1, max 99]
}
# How a customer pays. A card carries its last four digits, a voucher its value.
enum Payment {
cash
card: str.utf8
voucher: deci64
}
struct Order {
customer: str.utf8
lines: list[Line]
payment: Payment
discount: int32[min 0, max 50]
}
# What one order came to, kept for the end-of-day report.
struct Sale {
ticket: int32
customer: str.utf8
units: int32
total: deci64
}
# Receipt numbers come from a counter that hands out the next one each time it is asked.
struct Ticket {
now: int32
last: int32
}
fn Ticket.next [lent.mut 't': Ticket] -> optional[int32] {
if 't'.now equal_to 't'.last { return optional.none; }
change 't'.now = 't'.now plus 1;
return optional.value['t'.now];
}
# ---------------------------------------------------------------------------------------------------
# Small generic helpers
# ---------------------------------------------------------------------------------------------------
interface Number {
int32
int64
bin64
}
# The larger of two numbers, for any kind of number.
fn larger <T: Number> ['a': <T>, 'b': <T>] -> <T> {
if 'a' > 'b' { return 'a'; }
return 'b';
}
# The total of a list of numbers.
fn total_of <T: Number> [lent 'xs': list[<T>]] -> <T> {
let 'sum': <T> = 0;
for 'x' in lend 'xs' {
change 'sum' = 'sum' plus 'x';
}
return 'sum';
}
# The list sorted from largest to smallest: a plain insertion sort, easy to check by eye.
fn sorted_down [lent 'xs': list[int32]] -> list[int32] {
let 'out': list[int32] = list.empty;
for 'x' in lend 'xs' {
list.append[lend.mut 'out', 'x'];
let 'i' := list.length[lend 'out'];
while 'i' > 1 and.then 'out'[pos 'i'] > 'out'[pos 'i' minus 1] {
let 'held' := 'out'[pos 'i'];
change 'out'[pos 'i'] = 'out'[pos 'i' minus 1];
change 'out'[pos 'i' minus 1] = 'held';
change 'i' = 'i' minus 1;
}
}
return give 'out';
}
# ---------------------------------------------------------------------------------------------------
# The catalog and the stock room
# ---------------------------------------------------------------------------------------------------
fn catalog [] -> list[Item] {
return [
Item[name = "apple", aisle = Aisle.fresh, price = 0.45],
Item[name = "banana", aisle = Aisle.fresh, price = 0.30],
Item[name = "milk", aisle = Aisle.fresh, price = 1.20],
Item[name = "bread", aisle = Aisle.bakery, price = 2.10],
Item[name = "croissant", aisle = Aisle.bakery, price = 1.35],
Item[name = "rice", aisle = Aisle.pantry, price = 3.80],
Item[name = "beans", aisle = Aisle.pantry, price = 0.95],
Item[name = "coffee", aisle = Aisle.pantry, price = 6.50],
Item[name = "soap", aisle = Aisle.household, price = 1.75],
Item[name = "candles", aisle = Aisle.household, price = 4.20]
];
}
fn opening_stock [] -> map[str.utf8, int32] {
let 'stock': map[str.utf8, int32] = map.empty;
map.set[lend.mut 'stock', "apple", 40];
map.set[lend.mut 'stock', "banana", 30];
map.set[lend.mut 'stock', "milk", 12];
map.set[lend.mut 'stock', "bread", 8];
map.set[lend.mut 'stock', "croissant", 6];
map.set[lend.mut 'stock', "rice", 10];
map.set[lend.mut 'stock', "beans", 24];
map.set[lend.mut 'stock', "coffee", 5];
map.set[lend.mut 'stock', "soap", 9];
map.set[lend.mut 'stock', "candles", 4];
return give 'stock';
}
# The catalog entry for a name, or a failure the caller must handle.
fn find_item [lent 'items': list[Item], lent 'name': str.utf8] -> Item or fail[unknown_item] {
for 'it' in lend 'items' {
if 'it'.name equal_to 'name' { return copy 'it'; }
}
fail unknown_item;
}
fn aisle_name ['a': Aisle] -> str.utf8 {
match 'a' {
fresh { return "fresh"; }
bakery { return "bakery"; }
pantry { return "pantry"; }
household { return "household"; }
}
}
# ---------------------------------------------------------------------------------------------------
# Reading orders written as text: "apple 3, bread 1, coffee 2"
# ---------------------------------------------------------------------------------------------------
# One "name count" piece into a line; a count that is not a number, or not 1 to 99, fails.
fn parse_line [lent 'piece': str.utf8] -> Line or fail[bad_line: str.utf8] {
let 'words' := cord::str.split[lend 'piece', " "];
if list.length[lend 'words'] not_equal 2 { fail bad_line[copy 'piece']; }
let 'name' := copy 'words'[pos 1];
let 'count': int32[min 1, max 99] = to.int32[min 1, max 99]['words'[pos 2]] otherwise {
not_a_number { fail bad_line[copy 'piece']; }
out_of_range { fail bad_line[copy 'piece']; }
};
return Line[name = give 'name', count = 'count'];
}
fn parse_order [lent 'text': str.utf8] -> list[Line] or fail[bad_line: str.utf8] {
let 'lines': list[Line] = list.empty;
let 'pieces' := cord::str.split[lend 'text', ", "];
for 'piece' in lend 'pieces' {
let 'line' := parse_line[lend 'piece'] otherwise fail;
list.append[lend.mut 'lines', give 'line'];
}
return give 'lines';
}
# ---------------------------------------------------------------------------------------------------
# Pricing
# ---------------------------------------------------------------------------------------------------
# A pricing rule takes a line's price before any rule and gives what the customer pays for it.
fn no_rule ['line_total': deci64] -> deci64 { return 'line_total'; }
# Bakery goods are 20% off after six in the evening; the shop runs this rule all day here.
fn evening_bakery ['line_total': deci64] -> deci64 { return 'line_total' times 0.80; }
fn rule_for ['a': Aisle] -> fn[deci64] -> deci64 {
match 'a' {
bakery { return evening_bakery; }
fresh { return no_rule; }
pantry { return no_rule; }
household { return no_rule; }
}
}
# A whole-order discount, which the range type keeps between 0 and 50 percent.
fn apply_discount ['amount': deci64, 'percent': int32[min 0, max 50]] -> deci64 {
let 'pct': deci64 = to.deci64['percent'];
let 'off': deci64 = ('amount' times 'pct') div.near 100;
return 'amount' minus 'off';
}
# ---------------------------------------------------------------------------------------------------
# Taking one order
# ---------------------------------------------------------------------------------------------------
fn take_order [
lent 'items': list[Item],
lent.mut 'stock': map[str.utf8, int32],
lent 'order': Order,
'ticket': int32
] -> Sale or fail[out_of_stock: str.utf8, unknown_item: str.utf8] {
cord::print.useful["--- receipt #", 'ticket', " for ", 'order'.customer, " ---", newln];
let 'subtotal': deci64 = 0;
let 'units' := 0;
for 'line' in lend 'order'.lines {
let 'item' := find_item[lend 'items', lend 'line'.name] otherwise {
unknown_item { fail unknown_item[copy 'line'.name]; }
};
let 'have' := map.get[lend 'stock', copy 'line'.name] otherwise 0;
if 'have' < 'line'.count { fail out_of_stock[copy 'line'.name]; }
map.set[lend.mut 'stock', copy 'line'.name, 'have' minus 'line'.count];
let 'rule' := rule_for[copy 'item'.aisle];
let 'count': deci64 = to.deci64['line'.count];
let 'line_total' := 'rule'['item'.price times 'count'];
change 'subtotal' = 'subtotal' plus 'line_total';
change 'units' = 'units' plus 'line'.count;
cord::print.format[" {:<10} x{:>2} {:>8.2}\n", 'line'.name, 'line'.count, 'line_total'];
}
let 'total' := apply_discount['subtotal', 'order'.discount];
if 'order'.discount > 0 {
cord::print.format[" discount {}%\n", 'order'.discount];
}
cord::print.format[" {:<14} {:>8.2}\n", "total", 'total'];
cord::print.useful[" paid by ", payment_text[lend 'order'.payment, 'total'], newln];
return Sale[ticket = 'ticket', customer = copy 'order'.customer, units = 'units', total = 'total'];
}
fn payment_text [lent 'p': Payment, 'total': deci64] -> str.utf8 {
match 'p' {
cash { return "cash"; }
card 'last4' { return "card ending " ++ 'last4'; }
voucher 'worth' {
if 'worth' at_least 'total' { return "voucher, nothing left to pay"; }
return cord::format["voucher, then {:.2} in cash", 'total' minus 'worth'];
}
}
}
# ---------------------------------------------------------------------------------------------------
# The day's orders
# ---------------------------------------------------------------------------------------------------
fn todays_orders [] -> list[Order] {
let 'orders': list[Order] = list.empty;
let 'texts' := [
"apple 6, bread 1, milk 2",
"coffee 2, croissant 4",
"rice 1, beans 3, soap 2, candles 1",
"banana 12, milk 1",
"coffee 4",
"pineapple 1",
"apple two",
"candles 2, bread 2, croissant 2"
];
let 'customers' := ["Ann", "Bo", "Cy", "Dee", "Eli", "Fay", "Gus", "Hal"];
for 'i' from 1 to list.length[lend 'texts'] by 1 {
let 'lines' := parse_order[lend 'texts'[pos 'i']] otherwise {
bad_line 'what' {
cord::print.useful["(order for ", 'customers'[pos 'i'], " skipped: cannot read \"", 'what', "\")", newln];
continue;
}
};
let 'payment' := choose_payment['i'];
let 'discount': int32[min 0, max 50] = 0;
if 'i' equal_to 3 { change 'discount' = 10; }
if 'i' equal_to 8 { change 'discount' = 25; }
list.append[lend.mut 'orders', Order[customer = copy 'customers'[pos 'i'], lines = give 'lines', payment = give 'payment', discount = 'discount']];
}
return give 'orders';
}
fn choose_payment ['i': int32] -> Payment {
if ('i' mod.floor 3) equal_to 0 { return Payment.voucher[5.00]; }
if ('i' mod.floor 2) equal_to 0 { return Payment.card["4242"]; }
return Payment.cash;
}
# ---------------------------------------------------------------------------------------------------
# Loyalty points
# ---------------------------------------------------------------------------------------------------
fn add_points [lent.mut 'points': map[str.utf8, int32], lent 'sale': Sale] {
let 'earned' := 'sale'.units times 'points_per_item';
let 'before' := map.get[lend 'points', copy 'sale'.customer] otherwise 0;
map.set[lend.mut 'points', copy 'sale'.customer, 'before' plus 'earned'];
}
# ---------------------------------------------------------------------------------------------------
# The end-of-day report
# ---------------------------------------------------------------------------------------------------
fn reorder_list [lent 'items': list[Item], lent 'stock': map[str.utf8, int32]] -> list[str.utf8] {
let 'out': list[str.utf8] = list.empty;
for 'it' in lend 'items' {
let 'left' := map.get[lend 'stock', copy 'it'.name] otherwise 0;
if 'left' at_most 'low_stock' {
list.append[lend.mut 'out', copy 'it'.name ++ " (" ++ to.stored.str.utf8['left'] ++ " left)"];
}
}
return give 'out';
}
fn takings_by_aisle [lent 'items': list[Item], lent 'opening': map[str.utf8, int32], lent 'closing': map[str.utf8, int32], 'a': Aisle] -> deci64 {
let 'sum': deci64 = 0;
for 'it' in lend 'items' {
if 'it'.aisle equal_to 'a' {
let 'had' := map.get[lend 'opening', copy 'it'.name] otherwise 0;
let 'has' := map.get[lend 'closing', copy 'it'.name] otherwise 0;
let 'sold' := 'had' minus 'has';
change 'sum' = 'sum' plus 'it'.price times to.deci64['sold'];
}
}
return 'sum';
}
fn report [lent 'sales': list[Sale], lent 'items': list[Item], lent 'opening': map[str.utf8, int32], lent 'stock': map[str.utf8, int32], lent 'points': map[str.utf8, int32]] {
cord::print.useful[newln, "=== ", 'shop_name', ", end of day ===", newln];
# Orders and units
let 'units': list[int32] = list.empty;
let 'takings': deci64 = 0;
for 's' in lend 'sales' {
list.append[lend.mut 'units', 's'.units];
change 'takings' = 'takings' plus 's'.total;
}
cord::print.useful["orders served: ", list.length[lend 'sales'], ", units sold: ", total_of[lend 'units'], newln];
cord::print.format["takings: {:.2}\n", 'takings'];
# The biggest baskets, by units: the first three of the list sorted largest first
let 'ranked' := sorted_down[lend 'units'];
let 'shown' := larger[1, list.length[lend 'ranked']];
if 'shown' at_least 3 {
let 'top' := list.slice[lend 'ranked', from pos 1, to pos 3];
cord::print.useful["biggest baskets (units): ", 'top', newln];
}
# The best sale of the day
let 'best_total': deci64 = 0;
let 'best_ticket' := 0;
let 'best_customer' := "nobody";
for 's' in lend 'sales' {
if 's'.total > 'best_total' {
change 'best_total' = 's'.total;
change 'best_ticket' = 's'.ticket;
change 'best_customer' = copy 's'.customer;
}
}
cord::print.format["best sale: #{}, {}, {:.2}\n", 'best_ticket', 'best_customer', 'best_total'];
# Takings by aisle, counted from what left the shelves (at list price, before discounts)
cord::print.useful["by aisle, at list price:", newln];
let 'aisles' := [Aisle.fresh, Aisle.bakery, Aisle.pantry, Aisle.household];
for 'a' in lend 'aisles' {
cord::print.format[" {:<10} {:>8.2}\n", aisle_name[copy 'a'], takings_by_aisle[lend 'items', lend 'opening', lend 'stock', copy 'a']];
}
# Reorders
let 'reorder' := reorder_list[lend 'items', lend 'stock'];
if list.length[lend 'reorder'] equal_to 0 {
cord::print.useful["nothing to reorder", newln];
} else {
cord::print.useful["reorder: ", cord::str.join[lend 'reorder', ", "], newln];
}
# Loyalty points, for the customers who were served
cord::print.useful["loyalty points:", newln];
for 's' in lend 'sales' {
let 'p' := map.get[lend 'points', copy 's'.customer] otherwise 0;
cord::print.format[" {:<5} {:>3}\n", 's'.customer, 'p'];
}
}
# ---------------------------------------------------------------------------------------------------
# Counting at the same time: each aisle's shelf count is tallied by its own task, which reports back
# over a channel. The tasks run alongside each other; MAIN waits for every answer.
# ---------------------------------------------------------------------------------------------------
fn shelf_count [lent 'items': list[Item], lent 'stock': map[str.utf8, int32], 'a': Aisle] -> int32 {
let 'n' := 0;
for 'it' in lend 'items' {
if 'it'.aisle equal_to 'a' {
let 'on_shelf' := map.get[lend 'stock', copy 'it'.name] otherwise 0;
change 'n' = 'n' plus 'on_shelf';
}
}
return 'n';
}
fn count_shelves [lent 'items': list[Item], lent 'stock': map[str.utf8, int32]] {
let 'fresh_ch' := channel[int32];
let 'bakery_ch' := channel[int32];
let 'pantry_ch' := channel[int32];
let 'household_ch' := channel[int32];
concur with [lend 'fresh_ch', lend 'items', lend 'stock'] { channel.send[lend 'fresh_ch', shelf_count[lend 'items', lend 'stock', Aisle.fresh]]; }
concur with [lend 'bakery_ch', lend 'items', lend 'stock'] { channel.send[lend 'bakery_ch', shelf_count[lend 'items', lend 'stock', Aisle.bakery]]; }
concur with [lend 'pantry_ch', lend 'items', lend 'stock'] { channel.send[lend 'pantry_ch', shelf_count[lend 'items', lend 'stock', Aisle.pantry]]; }
concur with [lend 'household_ch', lend 'items', lend 'stock'] { channel.send[lend 'household_ch', shelf_count[lend 'items', lend 'stock', Aisle.household]]; }
let 'f' := channel.take[lend 'fresh_ch'] otherwise 0;
let 'b' := channel.take[lend 'bakery_ch'] otherwise 0;
let 'p' := channel.take[lend 'pantry_ch'] otherwise 0;
let 'h' := channel.take[lend 'household_ch'] otherwise 0;
cord::print.useful["on the shelves tonight: fresh ", 'f', ", bakery ", 'b', ", pantry ", 'p', ", household ", 'h', newln];
}
# ---------------------------------------------------------------------------------------------------
# Looking things up: finding catalog items by what their name starts with or contains
# ---------------------------------------------------------------------------------------------------
fn names_starting [lent 'items': list[Item], lent 'start': str.utf8] -> list[str.utf8] {
let 'out': list[str.utf8] = list.empty;
for 'it' in lend 'items' {
if cord::str.starts_with[lend 'it'.name, copy 'start'] {
list.append[lend.mut 'out', copy 'it'.name];
}
}
return give 'out';
}
fn names_containing [lent 'items': list[Item], lent 'part': str.utf8] -> list[str.utf8] {
let 'out': list[str.utf8] = list.empty;
for 'it' in lend 'items' {
if cord::str.contains[lend 'it'.name, copy 'part'] {
list.append[lend.mut 'out', copy 'it'.name];
}
}
return give 'out';
}
fn show_search [lent 'items': list[Item]] {
cord::print.useful[newln, "searching the catalog:", newln];
let 'starts' := ["b", "c", "z"];
for 's' in lend 'starts' {
let 'found' := names_starting[lend 'items', lend 's'];
if list.length[lend 'found'] equal_to 0 {
cord::print.useful[" nothing starts with \"", 's', "\"", newln];
} else {
cord::print.useful[" starting with \"", 's', "\": ", cord::str.join[lend 'found', ", "], newln];
}
}
let 'has_an' := names_containing[lend 'items', "an"];
cord::print.useful[" containing \"an\": ", cord::str.join[lend 'has_an', ", "], newln];
let 'sign' := 'shop_name'; # a const is a fresh value each use, so it is named to lend
let 'loud' := cord::str.upper[lend 'sign'];
cord::print.useful[" the sign over the door says ", 'loud', newln];
}
# ---------------------------------------------------------------------------------------------------
# Restocking: what to order so every shelf is back to its target, in whole cases
# ---------------------------------------------------------------------------------------------------
struct Restock {
name: str.utf8
cases: int32
cost: deci64
}
# How many items one case holds, by aisle.
fn case_size ['a': Aisle] -> int32 {
let 'size' := match 'a' {
fresh { is 10; }
bakery { is 6; }
pantry { is 12; }
household { is 4; }
};
return 'size';
}
# The supplier charges 60% of the shop's price for each item in a case.
fn case_cost ['price': deci64, 'size': int32] -> deci64 {
let 'each': deci64 = 'price' times 0.60;
let 'n': deci64 = to.deci64['size'];
return 'each' times 'n';
}
fn plan_restock [lent 'items': list[Item], lent 'opening': map[str.utf8, int32], lent 'stock': map[str.utf8, int32]] -> list[Restock] {
let 'plan': list[Restock] = list.empty;
for 'it' in lend 'items' {
let 'target' := map.get[lend 'opening', copy 'it'.name] otherwise 0;
let 'left' := map.get[lend 'stock', copy 'it'.name] otherwise 0;
let 'missing' := 'target' minus 'left';
if 'missing' > 0 {
let 'size' := case_size[copy 'it'.aisle];
# whole cases only: round the count of cases up
let 'cases' := ('missing' plus 'size' minus 1) div.floor 'size';
let 'one_case' := case_cost['it'.price, 'size'];
let 'n': deci64 = to.deci64['cases'];
list.append[lend.mut 'plan', Restock[name = copy 'it'.name, cases = 'cases', cost = 'one_case' times 'n']];
}
}
return give 'plan';
}
fn show_restock [lent 'plan': list[Restock]] {
cord::print.useful[newln, "tomorrow's delivery:", newln];
let 'bill': deci64 = 0;
for 'r' in lend 'plan' {
cord::print.format[" {:<10} {:>2} case(s) {:>7.2}\n", 'r'.name, 'r'.cases, 'r'.cost];
change 'bill' = 'bill' plus 'r'.cost;
}
cord::print.format[" {:<22} {:>7.2}\n", "to the supplier", 'bill'];
}
# ---------------------------------------------------------------------------------------------------
# A week of trade: seven days of made-up but repeatable numbers, averaged and compared
# ---------------------------------------------------------------------------------------------------
# Customers on day 'd' (1 is Monday): busier towards the weekend, quieter on Sunday.
fn customers_on ['d': int32[min 1, max 7]] -> int32 {
if 'd' equal_to 7 { return 18; }
return 20 plus 'd' times 4;
}
fn show_week [] {
const 'days' := 7;
cord::print.useful[newln, "this week:", newln];
let 'counts': list[int32] = list.empty;
for 'd' from 1 to 'days' by 1 {
let 'n' := customers_on['d'];
list.append[lend.mut 'counts', 'n'];
}
let 'names' := ["Mon", "Tue", "Wed", "Thu", "Fri", "Sat", "Sun"];
let 'busiest' := 0;
for 'i', 'n' in lend 'counts' {
cord::print.format[" {} {:>3} ", 'names'[pos 'i'], 'n'];
for 'k' from 0 before 'n' by 4 {
cord::print.useful["#"];
}
cord::print.useful[newln];
change 'busiest' = larger['busiest', 'n'];
}
let 'sum' := total_of[lend 'counts'];
let 'average': bin64 = to.bin64['sum'] div.near to.bin64['days'];
cord::print.format[" {} customers, {:.1} a day, {} on the busiest\n", 'sum', 'average', 'busiest'];
let 'weekend' := list.slice[lend 'counts', from pos 6, to pos 7];
let 'weekdays' := list.slice[lend 'counts', from pos 1, before pos 6];
cord::print.useful[" weekdays ", total_of[lend 'weekdays'], ", weekend ", total_of[lend 'weekend'], newln];
}
# ---------------------------------------------------------------------------------------------------
# Sales by the hour: a bar for each opening hour, counted with `before`
# ---------------------------------------------------------------------------------------------------
fn show_hours ['open': int32, 'close': int32] {
cord::print.useful[newln, "customers by the hour:", newln];
let 'peak' := 0;
let 'peak_hour' := 'open';
for 'h' from 'open' before 'close' by 1 {
# a lunch rush at noon and an evening rush at five, quiet otherwise
let 'n' := 2;
if 'h' equal_to 12 or 'h' equal_to 17 { change 'n' = 9; }
if 'h' equal_to 13 or 'h' equal_to 18 { change 'n' = 6; }
cord::print.format[" {:>2}:00 ", 'h'];
let 'bar' := list.fill[value "*", count 'n'];
cord::print.useful[cord::str.join[lend 'bar', ""], newln];
if 'n' > 'peak' {
change 'peak' = 'n';
change 'peak_hour' = 'h';
}
}
cord::print.useful[" busiest from ", 'peak_hour', ":00", newln];
}
# ---------------------------------------------------------------------------------------------------
# The day
# ---------------------------------------------------------------------------------------------------
MAIN {
const 'opening_hour' := 8;
const 'closing_hour' := 20;
cord::print.useful['shop_name', ", open ", 'opening_hour', ":00 to ", 'closing_hour', ":00", newln];
let 'items' := catalog[];
let 'stock' := opening_stock[];
let 'opening' := copy 'stock';
let 'points': map[str.utf8, int32] = map.empty;
let 'sales': list[Sale] = list.empty;
# The price list, three columns of a table
cord::print.useful[newln, "today's prices:", newln];
for 'it' in lend 'items' {
cord::print.format[" {:<10} {:<10} {:>6.2}\n", 'it'.name, aisle_name[copy 'it'.aisle], 'it'.price];
}
cord::print.useful[newln];
# Hours the shop is open, counted the new way: from opening, stopping before closing
let 'hours' := 0;
for 'h' from 'opening_hour' before 'closing_hour' by 1 {
change 'hours' = 'hours' plus 1;
}
cord::print.useful["open for ", 'hours', " hours", newln, newln];
# Take every order, each with the next receipt number
let 'orders' := todays_orders[];
cord::print.useful[newln];
let 'tickets' := Ticket[now = 100, last = 199];
for 'order' in lend 'orders' {
let 'n' := Ticket.next[lend.mut 'tickets'];
let 'ticket' := match 'n' {
value 'number' { is 'number'; }
none { is 0; }
};
let 'sale' := take_order[lend 'items', lend.mut 'stock', lend 'order', 'ticket'] otherwise {
out_of_stock 'what' {
cord::print.useful[" sorry, ", 'order'.customer, ": not enough ", 'what', newln, newln];
continue;
}
unknown_item 'what' {
cord::print.useful[" sorry, ", 'order'.customer, ": we do not sell ", 'what', newln, newln];
continue;
}
};
add_points[lend.mut 'points', lend 'sale'];
list.append[lend.mut 'sales', give 'sale'];
cord::print.useful[newln];
}
report[lend 'sales', lend 'items', lend 'opening', lend 'stock', lend 'points'];
count_shelves[lend 'items', lend 'stock'];
let 'plan' := plan_restock[lend 'items', lend 'opening', lend 'stock'];
show_restock[lend 'plan'];
show_hours['opening_hour', 'closing_hour'];
show_week[];
show_search[lend 'items'];
# Exact decimals: the reason money is `deci64` and not `bin64`
let 'dime': deci64 = 0.10;
let 'cents_sum': deci64 = 'dime' plus 0.20;
let 'float_sum': bin64 = 0.1 plus 0.2;
cord::print.useful[newln, "0.10 plus 0.20, stored exactly as money: "];
cord::print.stored['cents_sum', newln];
cord::print.useful["0.1 plus 0.2, stored as a binary float: "];
cord::print.stored['float_sum', newln];
cord::print.useful["good night from the ", 'shop_name', newln];
}