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).
| Word | Signature | Meaning |
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.
| Word | Signature | Meaning |
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.
| Word | Signature | Meaning |
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.
| Word | Signature | Meaning |
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)
| Word | Signature | Meaning |
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.
| Word | For | Meaning |
c len | array, list, queue, buffer | what it holds now (an array: its capacity; a buffer: bytes); pools do not count their rows |
c capacity | array, list, queue, buffer | the declared capacity |
c is_empty | array, list, queue, buffer | is it empty |
c is_full | array, list, queue | is it full |
c clear | array, list, queue, buffer | empties it (an array: every cell to 0); not for a pool: free its rows one by one |
i c idx | array, list | cell i; out of range is the fault range |
v c push / c pop | list | put at the end / take from the end (or fail) |
c add_row | list of records | adds an empty row and gives it (or fail) |
v c put / c take / c peek | queue | put at the back / take from the front / look at the front (or fail) |
v c wait_put / c wait_take | queue | put / take, yielding while the queue is full / empty (or fail, 14.3) |
c alloc / r c free / r c is_alive | pool | take 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_byte | buffer | append (or fail) |
c contents | buffer | a view of what it holds |
n c truncate | buffer, list | cut the length to n (a list: 8.5 (2b)) |
c none / r is_none / r row_index | table of records | the none row / is it none / the row’s number |
k x lookup / r x insert / r x remove | index | find (or fail) / put in (or fail) / take out |
k x has | index | is a row with key k in it |
c sort / c sort_desc | array, list | puts the cells in order, the smallest / the largest first ((3)) |
o t sort_by r.f / o t sort_by_desc r.f | array 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 instructions (19.5).
15.4 Other words
(1)
| Word | Signature | Meaning |
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 |
call | as the block’s signature | calls 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_tag | clause 14 | tasks |
Diagnostics
| Condition | Message |
|---|---|
A value that is not int given to an integer word | this word takes two int values |
| Two values of different types compared | the two values compared must have the same type |
The values of select differ in type | select takes a bool and two values of one type: flag a b select |
sort of an array or list of records | rows do not move: sort a list of their numbers by a field: order table sort_by record.field |
sort of cells of another type | sort orders cells of int, a narrow integer, dec(N), bool or str(N) |
sort_by without a list of int or rows and a table | sort_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 table | the cells are rows of another table than the one sort_by names |
sort_by without the field after it | sort_by is followed by the field: order table sort_by record.field |
| A field of another record than the table’s | the field is one of the record the table holds |
| A field of another type | sort_by orders by a field of int, a narrow integer, dec(N), bool or str(N) |
| Both the list and the table parameters | sort_by takes the list or the table from a parameter, not both |