15 Core words

(1) A core word is written as a bare name, without use. The tables of this clause write signatures as in 9.2. T means “any one type”; it is a notation for built-in words only. The stack words (dup drop swap over nip) are in 9.3 and the combining words that take stems in 10.6.

15.1 Integers

(1) Arithmetic. Overflow and division by zero are faults (11.3).

WordSignatureMeaning
add sub mul(int, int gives int)add, subtract, multiply
div mod(int, int gives int)quotient rounded toward zero and its remainder (sign of the dividend)
floor_div floor_mod(int, int gives int)quotient rounded down and its remainder (sign of the divisor)
neg abs(int gives int)negation, absolute value; overflow for the smallest int
min max(int, int gives int)the smaller, the larger
clamp(n int, lo int, hi int gives int)n brought between lo and hi
rescale(d dec(N), M gives dec(M))the decimal with M digits after the point (M a constant); fewer digits rounded half away from zero (7.5)

(2) Words that treat overflow otherwise.

WordSignatureMeaning
wrap_add wrap_sub wrap_mul(int, int gives int)wrap modulo 264
sat_add sat_sub sat_mul(int, int gives int)stop at the edge of the range
chk_add chk_sub chk_mul chk_div(int, int gives int or fail)fail with err.overflow on overflow, err.div_zero on division by zero

(3) Words that read numbers as unsigned: the 64 bits as a number from 0 to 264−1.

WordSignatureMeaning
u_div u_mod(int, int gives int)unsigned quotient and remainder; division by zero is a fault
u_lt u_le u_gt u_ge(int, int gives bool)unsigned comparison
mul_hi u_mul_hi(int, int gives int)the upper 64 bits of the 128-bit product (signed, unsigned)

(4) Bits. Shift and rotate counts are taken modulo 64 (their low 6 bits). shl does not check for overflow.

WordSignatureMeaning
bit_and bit_or bit_xor(int, int gives int)bit by bit
bit_not(int gives int)every bit flipped
shl shr u_shr(n int, k int gives int)left, signed right, right filling with zeros
rotl rotr(n int, k int gives int)rotate
count_ones leading_zeros trailing_zeros(int gives int)the number of 1 bits, of leading and trailing zeros (64 for 0)
byte_swap(int gives int)the eight bytes in reverse order

(5) On a narrow integer (7.6) the words above take two of one type and give that type; overflow, wrapping and saturation are judged by that type’s range. The words that read numbers as unsigned and floor_div floor_mod are the plain words on an unsigned type and do not take a signed one. The bit words work within the width. neg abs min max clamp do not take a narrow integer; rotl rotr mul_hi u_mul_hi take u64 only.

15-integers.pnx

use io
word p (s str, n int) cat (s, " = ", n) io.println end
"7 2 floor_div" 7 2 floor_div p
"-7 2 floor_mod" -7 2 floor_mod p
"-1 2 u_div" -1 2 u_div p
"4611686018427387904 4 mul_hi" 4611686018427387904 4 mul_hi p
"12 10 bit_xor" 12 10 bit_xor p
"1 3 shl" 1 3 shl p
"1 64 shl" 1 64 shl p                       rem the count is taken modulo 64
"-16 2 shr" -16 2 shr p                     rem shr keeps the sign
"-16 60 u_shr" -16 60 u_shr p               rem u_shr fills with zeros
"1 1 rotr" 1 1 rotr p
"255 count_ones" 255 count_ones p
"0 leading_zeros" 0 leading_zeros p
"1 byte_swap" 1 byte_swap p
"15 0 10 clamp" 15 0 10 clamp p
"false 1 2 select" false 1 2 select p
"9223372036854775807 2 sat_mul" 9223372036854775807 2 sat_mul p
"9223372036854775807 2 wrap_mul" 9223372036854775807 2 wrap_mul p

Output

$ pnx 15-integers.pnx
7 2 floor_div = 3
-7 2 floor_mod = 1
-1 2 u_div = 9223372036854775807
4611686018427387904 4 mul_hi = 1
12 10 bit_xor = 6
1 3 shl = 8
1 64 shl = 1
-16 2 shr = -4
-16 60 u_shr = 15
1 1 rotr = -9223372036854775808
255 count_ones = 8
0 leading_zeros = 64
1 byte_swap = 72057594037927936
15 0 10 clamp = 10
false 1 2 select = 2
9223372036854775807 2 sat_mul = 9223372036854775807
9223372036854775807 2 wrap_mul = -2
Constraints

(5) Integer words take int only (or two values of the same declared type, 7.4).

15-max-str.pnx

"a" "b" max drop

Refused

$ pnx 15-max-str.pnx
15-max-str.pnx:1:9: this word takes two int values, or two of the same declared type
Faults

(6) neg and abs overflow at −263.

15-neg-min.pnx

-9223372036854775808 neg drop

Fault

$ pnx 15-neg-min.pnx
15-neg-min.pnx:1: integer overflow

15.2 Comparison and logic

(1)

WordSignatureMeaning
eq ne(T, T gives bool)equal, not equal: int bool str, declared types, rows, error codes
lt le gt ge(T, T gives bool)int (as signed), str (in byte order), declared types
and or(bool, bool gives bool)logical and, or; both values are computed
not(bool gives bool)negation
select(bool, T, T gives T)the first value when true, the second when false; no branch

15-compare.pnx

use io
word yes (b bool gives str) b if "true" else "false" end end
"abc" "abc" eq yes io.println              rem strings compare by their bytes
"abc" "abd" lt yes io.println
-1 1 u_lt yes io.println                   rem as unsigned, -1 is the largest
true false ne yes io.println

Output

$ pnx 15-compare.pnx
true
true
false
true
Constraints

(2) The two values compared shall have the same type; so shall the two values of select.

15-compare-mixed.pnx

1 true eq drop

Refused

$ pnx 15-compare-mixed.pnx
15-compare-mixed.pnx:1:8: the two values compared must have the same type

15-select-types.pnx

true 1 "one" select drop

Refused

$ pnx 15-select-types.pnx
15-select-types.pnx:1:14: select takes a bool and two values of one type: flag a b select

15.3 Collections

(1) The words for the storage clause 8 declares. c is the name of that storage.

WordForMeaning
c lenarray, list, queue, bufferwhat it holds now (an array: its capacity; a buffer: bytes); pools do not count their rows
c capacityarray, list, queue, bufferthe declared capacity
c is_emptyarray, list, queue, bufferis it empty
c is_fullarray, list, queueis it full
c cleararray, list, queue, bufferempties it (an array: every cell to 0); not for a pool: free its rows one by one
i c idxarray, listcell i; out of range is the fault range
v c push / c poplistput at the end / take from the end (or fail)
c add_rowlist of recordsadds an empty row and gives it (or fail)
v c put / c take / c peekqueueput at the back / take from the front / look at the front (or fail)
v c wait_put / c wait_takequeueput / take, yielding while the queue is full / empty (or fail, 14.3)
c alloc / r c free / r c is_alivepooltake a row (owned, or fail) / give it back (and out of its indexes) / is it alive
s c append n c append_int b c append_bytebufferappend (or fail)
c contentsbuffera view of what it holds
n c truncatebuffer, listcut the length to n (a list: 8.5 (2b))
c none / r is_none / r row_indextable of recordsthe none row / is it none / the row’s number
k x lookup / r x insert / r x removeindexfind (or fail) / put in (or fail) / take out
k x hasindexis a row with key k in it
c sort / c sort_descarray, listputs the cells in order, the smallest / the largest first ((3))
o t sort_by r.f / o t sort_by_desc r.farray or list of int or of rows of t; table of records (a pool: rows only)puts the row numbers or rows in order of field f of their rows ((4))

(2) Examples are in clause 8.

(3) c sort puts the cells of an array, or of a list up to its length, in order from the smallest; c sort_desc from the largest. The cells change in place and the word gives nothing. The cells shall be int, a narrow integer, dec(N), bool (false first) or str(N), or of a type declared over one of them; u64 cells are compared unsigned, str(N) cells in the byte order of str.compare (16.1). A collection parameter (9.9) is sorted the same way. A list or array of records is refused: an index, a field, a global or a named row may keep its rows. Its rows are put in order through a list of their numbers, by (4).

15-sort.pnx

use io
list marks int 6
list names str(8) 4
rem the cells on one line, a blank between two
word show (cells list int)
  0 cells len range do (i int) i 0 gt if " " io.print end  cat (i cells idx) io.print end each
  "" io.println
end
word main (or fail)
  7 marks push or_fail  -2 marks push or_fail  12 marks push or_fail  0 marks push or_fail
  marks sort
  marks show
  marks sort_desc
  marks show
  "pear" names push or_fail  "Fig" names push or_fail  "apple" names push or_fail
  names sort
  0 names len range do (i int) i 0 gt if " " io.print end  i names idx io.print end each
  "" io.println
end
main or_else (e) e err_text io.println end

Output

$ pnx 15-sort.pnx
-2 0 7 12
12 7 0 -2
Fig apple pear

15-sort-records.pnx

record entry
  count int
end
list terms entry 8
word order_them () terms sort end

Refused

$ pnx 15-sort-records.pnx
15-sort-records.pnx:5:26: rows do not move: sort a list of their numbers by a field: order table sort_by record.field

(4) o t sort_by r.f takes o, an array or list of int, each cell the number of a row of t, or of rows of t (8.8 (5a)); t, an array or list of records, or a pool of records when the cells of o are its rows; and the field r.f of the record t holds, written after the word as to and set take their name. It puts the cells of o in order of that field of the rows they number, from the smallest; sort_by_desc from the largest. The field shall be of a type the cells of (3) may have. The rows do not move, so indexes and kept rows stay right. A cell that is not a row number of t, or a none row, is the fault range, and a row of a pool given back since is the fault stale, found before any cell moves: o is left as it was. At most one of o and t may be a parameter.

15-sort-by.pnx

use io
record entry
  term str(8)
  count int
end
list terms entry 8
list order int 8
word count_in (t str, n int or fail)
  terms add_row or_fail to r
  t r to entry.term
  n r to entry.count
end
word main (or fail)
  "to" 4 count_in or_fail  "be" 2 count_in or_fail  "or" 2 count_in or_fail  "not" 1 count_in or_fail  "a" 4 count_in or_fail
  0 terms len range do (i int) i order push or_fail end each
  order terms sort_by entry.term
  order terms sort_by_desc entry.count       rem by count; the same count stays in byte order
  0 order len range do (i int)
    i order idx terms idx to r
    cat (r entry.count, " ", r entry.term) io.println
  end each
end
main or_else (e) e err_text io.println end

Output

$ pnx 15-sort-by.pnx
4 a
4 to
2 be
2 or
1 not

15-sort-by-range.pnx

record entry
  count int
end
list terms entry 8
list order int 8
word main (or fail)
  terms add_row or_fail to r
  5 order push or_fail
  order terms sort_by entry.count
end
main or_else (e) end

Fault

$ pnx 15-sort-by-range.pnx
15-sort-by-range.pnx:9: index out of range
  r terms = 1

(5) Both sorts are stable: cells of equal keys keep their order. A sort by several keys is several sorts, the least important key first.

(6) A sort does not fail. A load that sorts gives the program a work area of 8 bytes for each cell of the largest collection it sorts, or, when it sorts a collection parameter, of the largest array or list; the work area counts as a global of the state, and the block must have room for it. A sort of 𝑛 cells is charged to the budget as 𝑛·⌈log2𝑛⌉ instructions (19.5).

15.4 Other words

(1)

WordSignatureMeaning
mark(gives owned mark)the current place of the region (12.2)
release(owned mark)rewinds the region to that place (12.2)
region_free(gives int)the bytes left in the region
callas the block’s signaturecalls a block value (10.5)
raw(D gives base)a value of a declared type as its base type (7.4)
err_text(err gives str)the name of an error code (11.1)
assert(bool)the fault failed when false
spawn run_all resume is_done cancel yield task_tagclause 14tasks

Diagnostics
ConditionMessage
A value that is not int given to an integer wordthis word takes two int values
Two values of different types comparedthe two values compared must have the same type
The values of select differ in typeselect takes a bool and two values of one type: flag a b select
sort of an array or list of recordsrows do not move: sort a list of their numbers by a field: order table sort_by record.field
sort of cells of another typesort orders cells of int, a narrow integer, dec(N), bool or str(N)
sort_by without a list of int or rows and a tablesort_by takes a list of rows or row numbers and a table of records: order table sort_by record.field
A list of rows of another tablethe cells are rows of another table than the one sort_by names
sort_by without the field after itsort_by is followed by the field: order table sort_by record.field
A field of another record than the table’sthe field is one of the record the table holds
A field of another typesort_by orders by a field of int, a narrow integer, dec(N), bool or str(N)
Both the list and the table parameterssort_by takes the list or the table from a parameter, not both