A reckoner seed: the runtime's own builtins, guarded onto the stack — machines/seeds/seedbuiltin.shoddy
A seed is the file that bridges one machine's words into the reckoner
calculator. seedbuiltin is the one seed that bridges no
machine. Every other seed in this directory takes a machine and converts
its types at the bridge. This one takes the runtime: the builtins,
the words the engine dispatches directly. No machine declares them, so no
seed had ever carried them to a prompt. Nothing is converted, because a
builtin already speaks in numbers, strings, booleans and lists. What the
seed is made of is guards — checks that refuse a bad input before it does
harm.
Every name the runtime dispatches is accounted for in one of three ways.
The core and the other seeds already registered some. Others are
deliberately unreachable under a stated rule. What was left is what this
seed carries. tst/builtinsurfacetest.shoddy asserts that whole
partition, so a builtin that is neither claimed nor excluded nor registered
here fails the build. Read the current split there, not from a number
written here that the next builtin would falsify.
Some of these are simply missing vocabulary. LENGTH is
list-only and refuses a string outright, so before this seed there was no
way to ask how long a string was. There was no NTH, no
MID, no VAL. A session could load a CSV and take
its mean, yet could not take the first three characters of a cell.
Some builtins abort — they end the whole run.
ASC of the empty string, NTH past the end, and
GAMMAP on a non-positive a all do. Refusing instead
is the ordinary R3.5(a) work every seed does.
The dangerous ones do not abort. They answer something wrong:
VAL is strtod, the C routine that reads text
as a number. It answers 0 for anything it cannot read, so
"twelve" VAL is 0 and nothing says so. It is registered here
refusing unless ISNUMERIC agrees — the question
VAL does not ask.CHR casts to a 16-bit character, so a code above 65535
wraps round to some other character, or to the empty string. Refused
outside 0 to 65535.LEFT, RIGHT and MID clamp every
argument rather than refusing, so a count of 2.5 truncates to 2. The
clamping is kept, because a substring past the end is an ordinary answer.
A fractional count is refused, because that is a typo and not an
intention.CODEAT is the opposite case, and the reason it exists. It
refuses past the end where MID trims, so the guard
here says the same thing the builtin does rather than softening it. Asking
for character 6 of a 5-character string is a mistake at the index, and both
layers name the index and the length.One cost this seed pays on purpose. In the runtime,
CODES answers an Array Of Number, and that is the
whole point of the builtin: Nth on an array is O(1) — constant
time, however long the array — and a scanner indexes in a loop. There is no
array cell at the keyboard. So CODES here answers the
list that means the same thing, and FROMCODES takes
one back. The prompt therefore pays the list cost the builtin exists to
avoid. That is correct: a prompt is not a scanner, and a bridge conversion
is what a seed is for. FROMCODES also carries the one refusal
on this page with no builtin behind it, since the builtin can only be
handed numbers while a list at a keyboard can hold any cell at all.
ISNUMERIC asks "would VAL succeed", not "is
this wholly a number". So "3kg" VAL passes it and answers
3. That laxity is strtod's, and it is the
language's: reckoner's own tokenizer — the part that splits an
entry line into pieces — inherits it rather than correcting it, so
3X typed on an entry line is 3 as well. A seed that disagreed
with the tokenizer about what counts as a number would be a worse problem
than the laxity is. The suite asserts this, so the behaviour is stated
rather than assumed.
PRINT. The engine performs no effect;
evaluation answers lines for a shell to print. A
PRINT word would write outside the transaction. The tape
would not record it, TAPESAVE would lose it, and the screen
and the tape would disagree.INPUT, INPUTLINE or
INKEY. The matching reason from the other side: the
shell owns the prompt. A word that stopped and waited for input mid-line
would be a second thing reading the same keyboard.SORT, RND or &.
Each is already in the dictionary under the name it chose —
SORTL, RANDOM, and the core +, which
joins two strings.NETALLOWED is here and the other ten TCP words are not. It
carries no handle, needs no capability — no permission granted when the
mill starts — and is the question the capability answers. So it is
the one word that has to stay askable when the answer is no. Every other
socket builtin begins by aborting if the mill was started without
--allow-net, which means nothing could tell
“no network” from “no answer” without ending the
run. A session cannot turn the capability on; it can only ask.
DELETEFILE used to be a fourth entry in that list. It was
kept out under the rule aborts on a failure it cannot pre-flight, with
no guarded twin to build on. READFILE,
WRITEFILE and APPENDFILE abort too, and all are
here, rebuilt over TRYREADFILE and TRYWRITEFILE
the way seedfile rebuilt
READLINES. The whole force of the exclusion was that there was
no TryDeleteFile to rebuild DELETEFILE on.
FILEEXISTS narrows that window without closing it: a file
that exists can still be locked when the delete lands, and then the session
is gone.
TryDeleteFile now exists, so the reason does not.
DELETEFILE is registered over it, on exactly the precedent it
used to be the exception to. It answers whether the file went —
True if it did, False if it was not there or
could not be removed — rather than ending the session when it did not.
Both exist to end the run, which looks like an automatic exclusion. But
turning an abort into a refusal is exactly what this layer is for. So
"nope" ERROR refuses with nope, and
ASSERT refuses when its flag is false. What a program used to
end the run with, a session now answers with.
Everything else here is a builtin wrapped. CALL applies a
program to a cell. That was impossible before
reckoner grew RckPureOver and
RckProgOn, and the combinators only ever offered it over a
whole list. The program is run against the whole session, so it
may name a word defined a line earlier.
The text words, which are the ones a session reaches for hardest:
> "hello" LEN
x: 5
> CLEAR "hello" 2 3 MID
x: "ell"
> CLEAR "hello" "ll" INSTR
x: 3
> CLEAR 65 CHR
x: "A"
> CLEAR "3.5" VAL
x: 3.5
Lists gain the two words that were missing, and both count from 1:
> { 10 20 30 } 2 NTH
x: 20
> CLEAR { 10 20 30 } 2 99 SETNTH
x: { 10 99 30 }
> CLEAR 1 { 2 3 } PREPEND
x: { 1 2 3 }
> CLEAR 3 0 DIM
x: { 0 0 0 }
CALL is MAP for one element, and sees the
session it was typed in:
> 5 [ DUP * ] CALL
x: 25
> CLEAR : SQ DUP * ;
ok: SQ defined
[ empty ]
> 7 [ SQ ] CALL
x: 49
And the refusals. Without their guard, the first three would each have been a confident wrong number:
> "twelve" VAL
?: VAL: "twelve" IS NOT A NUMBER — VALOR TAKES A FALLBACK FOR THIS
> 65536 CHR
?: CHR: NEEDS A CODE FROM 0 TO 65535, AND 65536 WOULD WRAP
> "hello" 2.5 LEFT
?: LEFT needs a whole number, got 2.5
> { 10 20 } 3 NTH
?: NTH: THERE IS NO ELEMENT 3 — THE LIST HOLDS 2
> "" ASC
?: ASC: THE EMPTY STRING HAS NO FIRST CHARACTER
> "nope" ERROR
?: nope
VALOR is the way past VAL's refusal, and it is
deliberately unguarded. A caller who supplied a fallback has already said
what unreadable text should answer.
> "twelve" 0 VALOR
x: 0
| Group | Words |
|---|---|
| Text | LEN LEFT RIGHT MID INSTR INSTRFROM CHR ASC CODES FROMCODES CODEAT STR VAL VALOR ISNUMERIC |
| Numbers | NEGATE ATN ATN2 TANH ERF GAMMAP BETAI |
| Lists | NTH SETNTH ISEMPTY PREPEND DIM |
| Whole files | READFILE WRITEFILE APPENDFILE |
| The session around it | ARGS CLOCK SLEEP |
| Programs, and stopping | CALL ERROR ASSERT |
| Word | Description |
|---|---|
| LEN ( s -- n ) | How many characters a string holds. LENGTH is the one for lists, and refuses a string. |
| LEFT ( s n -- s2 ) | The first n characters, or the whole string if it is shorter. Refuses a fractional n. |
| RIGHT ( s n -- s2 ) | The last n characters, or the whole string if it is shorter. Refuses a fractional n. |
| MID ( s start len -- s2 ) | len characters from position start, counting from 1. A range past the end is trimmed to what is there. |
| INSTR ( s sub -- pos ) | Where sub first appears in s, counting from 1, or 0 when it does not. An empty sub answers 0. |
| INSTRFROM ( s sub from -- pos ) | Where sub first appears at or after position from, or 0 when it does not. |
| CHR ( n -- s ) | The character with code n. 0 answers the empty string. Refuses outside 0 to 65535, where the code would wrap silently. |
| ASC ( s -- n ) | The code of the first character. Refuses on the empty string, which has none. |
| CODES ( s -- list ) | The code of every character, in order. An empty string answers an empty list. |
| FROMCODES ( list -- s ) | The string those codes spell. Refuses a code outside 0 to 65535. |
| CODEAT ( s k -- n ) | The code of the character at position k, counting from 1. Refuses past the end, where MID would trim. |
| STR ( n -- s ) | A number written out as text, the way the stack shows it. |
| VAL ( s -- n ) | Text read back as a number. Refuses anything that is not one, rather than answering 0 as the builtin would. |
| VALOR ( s fallback -- n ) | The same, answering fallback for text that is not a number. Never refuses, because you said what to do instead. |
| ISNUMERIC ( s -- flag ) | Whether VAL would read this text as a number — the question VAL itself does not ask. |
| NEGATE ( x -- -x ) | The number with its sign turned round. |
| ATN ( x -- rad ) | The arctangent, in radians. ATN2 is the one that knows which quadrant. |
| ATN2 ( y x -- rad ) | The angle of the point (x, y), in radians, in the right quadrant. |
| TANH ( x -- y ) | The hyperbolic tangent. Saturates towards 1 and -1, so it never overflows. |
| ERF ( x -- y ) | The error function: odd, and between -1 and 1. |
| GAMMAP ( a x -- p ) | The regularized lower incomplete gamma. Refuses unless a is positive and x is not negative. |
| BETAI ( a b x -- p ) | The regularized incomplete beta. Refuses unless a and b are positive and x is between 0 and 1. |
| NTH ( list k -- v ) | The k-th element, counting from 1. Refuses an index the list does not have. |
| SETNTH ( list k v -- list2 ) | The list with its k-th element replaced. The original is unchanged. Refuses an index the list does not have. |
| ISEMPTY ( list -- flag ) | Whether the list holds nothing. |
| PREPEND ( v list -- list2 ) | The list with v put on the front. APPEND's opposite end. |
| DIM ( n init -- list ) | A list of n copies of init. Refuses a negative or fractional n. |
| READFILE ( path -- s ) | The whole file as one string, newlines and all. READLINES is the one that splits it. |
| WRITEFILE ( path s -- ok ) | Write the string to path, replacing what was there; True on success. |
| APPENDFILE ( path s -- ok ) | Add the string to the end of path, making it if it is not there; True on success. |
| ARGS ( -- list ) | The arguments the mill itself was started with, as a list of strings. |
| CLOCK ( -- list ) | The wall clock as seven numbers: year, month, day, hour, minute, second, millisecond. STAMP is the readable one. |
| SLEEP ( ms -- ) | Wait that many milliseconds and answer nothing. A count of 0 or less waits not at all. |
| CALL ( x prog -- y ) | Run the program on x and answer what it left. MAP does this over a whole list; this is the one element. |
| ERROR ( s -- ) | Refuse the line, giving s as the reason. In a program this ends the run; here it answers. |
| ASSERT ( flag s -- ) | Refuse the line with reason s when flag is false, and do nothing at all when it is true. |
| User | How | |
|---|---|---|
| halifax | Folded in first, before every domain seed, so the words a session reaches for hardest are the ones already there. | |
| sparky | Sparky folds it too, so a model calling eval reaches the same words halifax puts at a prompt. |
A mill claims this seed by folding RckSeedBuiltin over its
reckoner state, which is all halifax does.
| Machine | Why | |
|---|---|---|
| cuttle | The Cell type every registered word reads its arguments from and answers into. | |
| reckoner | RckReg and the argument readers, plus RckPureOver and RckProgOn, which are what let CALL run a program against the live session. | |
| seq | List plumbing under the list words. |
No domain machine sits under this seed, which is what makes it unlike every other one here. There is nothing underneath it but the runtime.