The Machines · Runtime stack

seedbuiltin

A reckoner seed: the runtime's own builtins, guarded onto the stack — machines/seeds/seedbuiltin.shoddy

the seedbuiltin machine's icon

Summary

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.

Why It's Useful

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.

The guards divide in two, and the second kind is the point

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:

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.

Where VAL's guard stops, on purpose

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.

Three that are absent, and look like oversights

One word from the socket family, and why only one

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.

The one exclusion that has been lifted

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.

ERROR and ASSERT are inverted, not dropped

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.

CALL is the one new capability

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.

User's Guide

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

Word Reference

GroupWords
TextLEN LEFT RIGHT MID INSTR INSTRFROM CHR ASC CODES FROMCODES CODEAT STR VAL VALOR ISNUMERIC
NumbersNEGATE ATN ATN2 TANH ERF GAMMAP BETAI
ListsNTH SETNTH ISEMPTY PREPEND DIM
Whole filesREADFILE WRITEFILE APPENDFILE
The session around itARGS CLOCK SLEEP
Programs, and stoppingCALL ERROR ASSERT
WordDescription
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.

Who Uses It

UserHow
halifaxFolded in first, before every domain seed, so the words a session reaches for hardest are the ones already there.
sparkySparky 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.

The Machines It Uses

MachineWhy
cuttleThe Cell type every registered word reads its arguments from and answers into.
reckonerRckReg and the argument readers, plus RckPureOver and RckProgOn, which are what let CALL run a program against the live session.
seqList 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.